web-dev-qa-db-fra.com

Obtenez les fonctionnalités d'image HOG d'OpenCV + Python?

J'ai lu cet article sur la façon d'utiliser le détecteur de piétons basé sur HOG d'OpenCV: Comment puis-je détecter et suivre des personnes utilisant OpenCV?

Je veux utiliser HOG pour détecter d'autres types d'objets dans les images (pas seulement les piétons). Cependant, la liaison Python de HOGDetectMultiScale ne semble pas donner accès aux fonctionnalités HOG réelles.

Existe-t-il un moyen d'utiliser Python + OpenCV pour extraire les fonctionnalités HOG directement à partir de n'importe quelle image?

30
lubar

Si vous voulez un code rapide Python pour les fonctionnalités HOG, j'ai porté le code sur Cython: https://github.com/cvondrick/pyvision/blob/master/vision/ features.pyx

8
carl

Dans python opencv vous pouvez calculer le porc comme ceci:

 import cv2
 hog = cv2.HOGDescriptor()
 im = cv2.imread(sample)
 h = hog.compute(im)
148
ton4eg

1. Obtenez la documentation intégrée: La commande suivante sur votre console python vous aidera à connaître la structure de la classe HOGDescriptor:

 import cv2; 
 help(cv2.HOGDescriptor())

2. Exemple de code: Voici un extrait de code pour initialiser un cv2.HOGDescriptor avec différents paramètres (Les termes que j'ai utilisés ici sont des termes standard bien définis dans la documentation OpenCV ici =):

import cv2
image = cv2.imread("test.jpg",0)
winSize = (64,64)
blockSize = (16,16)
blockStride = (8,8)
cellSize = (8,8)
nbins = 9
derivAperture = 1
winSigma = 4.
histogramNormType = 0
L2HysThreshold = 2.0000000000000001e-01
gammaCorrection = 0
nlevels = 64
hog = cv2.HOGDescriptor(winSize,blockSize,blockStride,cellSize,nbins,derivAperture,winSigma,
                        histogramNormType,L2HysThreshold,gammaCorrection,nlevels)
#compute(img[, winStride[, padding[, locations]]]) -> descriptors
winStride = (8,8)
padding = (8,8)
locations = ((10,20),)
hist = hog.compute(image,winStride,padding,locations)

3. Raisonnement: Le descripteur de porc résultant aura la dimension suivante: 9 orientations X (4 blocs d'angle qui obtiennent 1 normalisation + 6x4 blocs sur les bords qui obtiennent 2 normalisations + 6x6 blocs qui obtiennent 4 normalisations) = 1764. car je n'ai donné qu'un seul emplacement pour hog.compute ().

4. Une autre façon d'initialiser est à partir du fichier xml qui contient toutes les valeurs des paramètres:

hog = cv2.HOGDescriptor("hog.xml")

Pour obtenir un fichier xml, on peut faire ce qui suit:

hog = cv2.HOGDescriptor()
hog.save("hog.xml")

et modifiez les valeurs respectives des paramètres dans le fichier xml.

41
mdilip

Voici une solution qui utilise uniquement OpenCV:

import numpy as np
import cv2
import matplotlib.pyplot as plt

img = cv2.cvtColor(cv2.imread("/home/me/Downloads/cat.jpg"),
                   cv2.COLOR_BGR2GRAY)

cell_size = (8, 8)  # h x w in pixels
block_size = (2, 2)  # h x w in cells
nbins = 9  # number of orientation bins

# winSize is the size of the image cropped to an multiple of the cell size
hog = cv2.HOGDescriptor(_winSize=(img.shape[1] // cell_size[1] * cell_size[1],
                                  img.shape[0] // cell_size[0] * cell_size[0]),
                        _blockSize=(block_size[1] * cell_size[1],
                                    block_size[0] * cell_size[0]),
                        _blockStride=(cell_size[1], cell_size[0]),
                        _cellSize=(cell_size[1], cell_size[0]),
                        _nbins=nbins)

n_cells = (img.shape[0] // cell_size[0], img.shape[1] // cell_size[1])
hog_feats = hog.compute(img)\
               .reshape(n_cells[1] - block_size[1] + 1,
                        n_cells[0] - block_size[0] + 1,
                        block_size[0], block_size[1], nbins) \
               .transpose((1, 0, 2, 3, 4))  # index blocks by rows first
# hog_feats now contains the gradient amplitudes for each direction,
# for each cell of its group for each group. Indexing is by rows then columns.

gradients = np.zeros((n_cells[0], n_cells[1], nbins))

# count cells (border cells appear less often across overlapping groups)
cell_count = np.full((n_cells[0], n_cells[1], 1), 0, dtype=int)

for off_y in range(block_size[0]):
    for off_x in range(block_size[1]):
        gradients[off_y:n_cells[0] - block_size[0] + off_y + 1,
                  off_x:n_cells[1] - block_size[1] + off_x + 1] += \
            hog_feats[:, :, off_y, off_x, :]
        cell_count[off_y:n_cells[0] - block_size[0] + off_y + 1,
                   off_x:n_cells[1] - block_size[1] + off_x + 1] += 1

# Average gradients
gradients /= cell_count

# Preview
plt.figure()
plt.imshow(img, cmap='gray')
plt.show()

bin = 5  # angle is 360 / nbins * direction
plt.pcolor(gradients[:, :, bin])
plt.gca().invert_yaxis()
plt.gca().set_aspect('equal', adjustable='box')
plt.colorbar()
plt.show()

J'ai utilisé calcul et visualisation des descripteurs HOG pour comprendre la disposition des données et vectoriser les boucles sur les groupes.

11
pixelou

Malgré le fait qu'il existe une méthode comme indiqué dans les réponses précédentes:

hog = cv2.HOGDescriptor ()

Je voudrais publier une implémentation python que vous pouvez trouver dans le répertoire d'exemples d'opencv, en espérant qu'il puisse être utile de comprendre la fonctionnalité HOG:

def hog(img):
    gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
    gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
    mag, ang = cv2.cartToPolar(gx, gy)
    bin_n = 16 # Number of bins
    bin = np.int32(bin_n*ang/(2*np.pi))

    bin_cells = []
    mag_cells = []

    cellx = celly = 8

    for i in range(0,img.shape[0]/celly):
        for j in range(0,img.shape[1]/cellx):
            bin_cells.append(bin[i*celly : i*celly+celly, j*cellx : j*cellx+cellx])
            mag_cells.append(mag[i*celly : i*celly+celly, j*cellx : j*cellx+cellx])   

    hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in Zip(bin_cells, mag_cells)]
    hist = np.hstack(hists)

    # transform to Hellinger kernel
    eps = 1e-7
    hist /= hist.sum() + eps
    hist = np.sqrt(hist)
    hist /= norm(hist) + eps

    return hist

Cordialement.

10
omotto

Je ne serais pas d'accord avec l'argument de peakxu. Le détecteur HOG à la fin est "juste" un filtre linéaire rigide. tous les degrés de liberté dans "l'objet" (c'est-à-dire les personnes) conduisent à un estompage dans le détecteur et ne sont pas réellement manipulés par lui. Il existe une extension de ce détecteur utilisant des SVM latents qui gèrent explicitement les degrés de liberté en introduisant des contraintes structurelles entre les parties indépendantes (c'est-à-dire la tête, les bras, etc.) et en permettant plusieurs apparences par objet (c'est-à-dire les personnes frontales et les personnes latérales). .).

Concernant le détecteur HOG en opencv: En théorie, vous pouvez télécharger un autre détecteur à utiliser avec les fonctionnalités, mais vous ne pouvez pas afaik obtenir les fonctionnalités elles-mêmes. ainsi, si vous avez un détecteur formé (c'est-à-dire un filtre linéaire spécifique à une classe), vous devriez pouvoir le télécharger dans le détecteur pour obtenir les performances de détection rapides de l'opencv. cela dit, il devrait être facile de pirater le code source opencv pour fournir cet accès et proposer ce correctif aux responsables.

1
maddanio