<jupyter_start><jupyter_text>Local Binary Patterns (LBP) Reference 1. Definition: compute local representation of texture, by comparing each pixel with its surrounding neighborhood of pixels.2. Steps    1. Convert image to grayscale    2. Select a neighborhood of size r surrounding the center pixel    3. Calculate LBP value for the center pixel and store output in 2D array with the same width and height as input image           1. If neighbor >= center: set value to 1;else 0        2. go around the neighbor to construct an array of binaries        3. convert to decimal        4. Store the number as LBP for the pixel corresponding to center location in output    4. Compute a histogram over the output LBP array3. Properties    1. To capture details at varying scales (Ojala et. al), capture neighbors in a circle, change the radius of circle    2. LBP is considered uniform if at most two 1-0 or 0-1 transitions    3. Not rotation invariant, need extra steps to introduce rotation invariance.  Reference<jupyter_code>#ref: Kaikeba
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
def get_LBP(gray_image, window=3):
    lbp = np.zeros_like(gray_image)
    h,w = gray_image.shape
    p_center = window//2
    for ph in range(0,h-window):
        for pw in range(0,w-window):
            img = gray_image[ph:ph+window, pw:pw+window]
            center = img[p_center,p_center]
            binary = (img>=center)*1.0
            binary_vector = binary.flatten()
            #remove center point
            binary_vector = np.delete(binary_vector,4)
            res = 0
            for i in range(len(binary_vector)):
                if binary_vector[i]==1:
                    res+= 2**i
            lbp[ph+p_center,pw+p_center] = res
    return lbp
        
img = cv2.imread('img.png')
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
lbp = get_LBP(img_gray)
hist = lbp.flatten()
fig = plt.figure(figsize = (20,8))
ax = fig.add_subplot(1,3,1)
ax.imshow(img_gray,'gray')
ax = fig.add_subplot(1,3,2)
ax.imshow(lbp,'gray')
ax = fig.add_subplot(1,3,3)
freq,lbp,_ = ax.hist(hist,bins=255)
ax.set_title('LBP histogram')
# To obtain rotation invariance
def binary_min(binary):
    '''Take array of binary, and find the minimum rotation instance'''
    min_b = []
    for i in range(len(binary))[::-1]: #reverse
        print('binary:', binary)
        print('min_b:', min_b)
        if binary[i]==0:
            binary = binary[:i]
            min_b = min_b + [0]

        else:
            min_b = min_b + binary
            return np.array(min_b)
        
binary_min([1,0,1,1,0,1,0,0,0])<jupyter_output>binary: [1, 0, 1, 1, 0, 1, 0, 0, 0]
min_b: []
binary: [1, 0, 1, 1, 0, 1, 0, 0]
min_b: [0]
binary: [1, 0, 1, 1, 0, 1, 0]
min_b: [0, 0]
binary: [1, 0, 1, 1, 0, 1]
min_b: [0, 0, 0]<jupyter_text>HOG (Histogram of Oriented Gradients)1. BGR2GRAY: gradient only for grey scale    1. can involve aforementioned transformations, such as gamma transformation.2. calculate gradient for every pixel (magnitude and direction)    1. use gradient filters (kernel), eg. y gradient, use this kernel to convolute over whole image to get directional gradient for each pixel:\begin{matrix}-1 & -1 & -1\\0 & 0 & 0\\1 & 1 & 1\\\end{matrix}    2. magnitude of gradient: $\sqrt{dx^2+dy^2}$     3. orientation: $\arctan{\dfrac{dy}{dx}}$    4. output: magnitude matrix, orientation matrix3. divide image into small cells (eg 8*8), with 8 * 8 * 2 values, 2 =(magnitude and orientation)4. obtain gradient histogram for each cell    1. ```plot(angle, count)```: angle in range, eg. [0,20], [20,40]....    2. output shape: (1,  ranges)5. group every 3*3 cells into a block in a similar fasion to convolution (with block size and stride=1). Concatenate histogram descriptors of these cells: concat([...],[...],[...]) = [.........].    1. output: (1, 3 * 3 * ranges)    2. can add one more layer between cell and block (window)6. concat descriptors of every block, normalize to give the final descriptor. Sample pipelineInput image -> normalize gamma & color -> compute gradients -> weighted vote into spatial & orientation cells -> contrast normalize over overlapping spatial blocks -> collect HOG's over detection window -> Linear SVM -> classification Using Built-in HOGDescriptor from cv2<jupyter_code>hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
from skimage import io
url = 'http://absfreepic.com/absolutely_free_photos/small_photos/walking-people-on-street-2500x1667_84106.jpg'
img2 = io.imread(url)




(rects,weights) = hog.detectMultiScale(img2,
                                     winStride=(4,4),
                                     padding=(8,8),
                                     scale=1.25,
                                     useMeanshiftGrouping=False)
print(rects)
for (x,y,w,h) in rects:
    cv2.rectangle(img2, (x,y), (x+w,y+h), (0,255,0),2)
plt.imshow(img2)
plt.show()
#check the number of weights in default people detector
weight = cv2.HOGDescriptor_getDefaultPeopleDetector()
weight.shape
plt.plot(weight[:-1])<jupyter_output><empty_output><jupyter_text>A closer look at HOG Descripor<jupyter_code>def hog_descriptor(image):
    hog = cv2.HOGDescriptor()
    h, w = image.shape[:2]
    rate = 64 / w
    image = cv2.resize(image, (64, np.int(rate*h)))
    bg = np.zeros((128, 64), dtype=np.uint8)
    print(bg.shape,image.shape)
    bg[:,:] = 127
    h, w = image.shape
    dy = (128 - h) // 2
    bg[dy:h+dy,:] = image
    descriptors = hog.compute(bg, winStride=(8, 8), padding=(0, 0))
    return descriptors
from skimage import io
url = 'http://absfreepic.com/absolutely_free_photos/small_photos/walking-people-on-street-2500x1667_84106.jpg'
img2 = io.imread(url)

img2_gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)[50:350,0:300]
plt.imshow(img2_gray,cmap="gray")
img2_gray.shape
descriptor1 = hog_descriptor(img2_gray)
plt.plot(descriptor1)
def svm_predict(feature):
    weight = cv2.HOGDescriptor_getDefaultPeopleDetector()
    result = np.sum(weight[:-1]*feature)+weight[-1]
    return result
svm_predict(descriptor1)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1209848361323985, 'fraction_numerical': 0.0396217185716615, 'mean_word_length': 3.244982698961938, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '586738', 'license': 'MIT', 'n_tokens_mistral': 2164, 'n_tokens_neox': 2004, 'n_words': 620, 'path': 'image_processing_basics/2_descriptor_implementation_LBP_HOG.ipynb', 'repo_name': 'qyangaa/cv_tutorial_in_jupyter_notebook', 'size': '6133'}