neste post, iremos conhecer os detalhes do Histograma de orientação de Gradientes (HOG) recurso descritor. Vamos aprender o que está sob o capô e como este descritor é calculado internamente pelo OpenCV, MATLAB e outros pacotes.
este post faz parte de uma série que estou escrevendo sobre Reconhecimento de imagens e Detecção de objetos.
a lista completa de tutoriais nesta série é dada abaixo:
- reconhecimento de imagens utilizando técnicas tradicionais de Visão Computacional : Parte 1
- Histograma de orientação Gradientes : Parte 2
- Exemplo de código para o reconhecimento da imagem : Parte 3
- a Formação de um olho melhor detector: Parte 4a
- detecção de objetos utilizando a introdução tradicional de técnicas de Visão computacional : Parte 4b
- Como treinar e testar as suas próprias OpenCV objeto detector : Parte 5
- reconhecimento de Imagem usando uma Aprendizagem mais Profunda : Parte 6
- Introdução à Redes Neurais
- Compreensão Feedforward Neural Networks
- Reconhecimento de Imagem usando Convolucionais Redes Neurais
- a detecção de objetos usando uma Aprendizagem mais Profunda : Parte 7
muitas e muitas coisas parecem difíceis e misterioso. Mas uma vez que você toma o tempo para desconstruí-los, o mistério é substituído pela mestria e é isso que estamos atrás. Se você é um iniciante e está achando a visão de computador difícil e misteriosa, basta lembrar o seguinte
Q : Como você come um elefante ?
A : Uma dentada de cada vez!
- o que é um descritor de funcionalidades?
- como calcular o histograma de gradientes orientados ?
- Passo 1 : Pré-processamento
- Passo 2: calcular as imagens gradientes
- Passo 3 : Calcular o Histograma de Gradientes no 8×8 células
- Passo 4 : 16×16 normalização dos blocos
- Step 5: Calculate the HOG feature vector
- Visualizando Histograma de gradientes orientados
- Subscribe & Download Code
o que é um descritor de funcionalidades?
um descritor de recurso é uma representação de uma imagem ou um adesivo de imagem que simplifica a imagem extraindo informações úteis e jogando fora informações externas.
Normalmente, um recurso descritor converte uma imagem de tamanho largura x altura x 3 (canais ) para um recurso vetor / matriz de comprimento n. No caso do PORCO característica descritor, a imagem de entrada é de tamanho 64 x 128 x 3 e a função de saída de vetor de comprimento 3780.
tenha em mente que o descritor de porco pode ser calculado para outros tamanhos, mas neste post eu estou aderindo aos números apresentados no papel original para que você possa facilmente entender o conceito com um exemplo concreto.
tudo isto soa bem, mas o que é “útil” e o que é “estranho” ? Para definir “útil”, precisamos saber para que é” útil”? Claramente, o vetor de recursos não é útil para a finalidade de visualizar a imagem. Mas é muito útil para Tarefas como reconhecimento de imagens e detecção de objetos. O vetor de recursos produzido por esses algoritmos quando alimentado em algoritmos de classificação de imagens como suporte Máquina vetorial (SVM) produzem bons resultados.Mas, que tipos de” recursos ” são úteis para tarefas de classificação ? Vamos discutir este ponto usando um exemplo. Suponha que queremos construir um detector de objetos que detecte botões de camisas e Casacos.
um botão é circular (pode parecer elíptico numa imagem) e geralmente tem alguns buracos para costurar. Você pode executar um detector de borda na imagem de um botão, e facilmente dizer se é um botão simplesmente olhando para a imagem de borda sozinho. Neste caso, a informação de bordo é” útil ” e a informação de cor não é. Além disso, as características também precisam ter poder discriminativo. Por exemplo, boas características extraídas de uma imagem deve ser capaz de dizer a diferença entre botões e outros objetos circulares, como moedas e pneus de carro.
no descritor HOG feature, a distribuição ( histogramas ) de direções de gradientes ( gradientes orientados ) são usadas como características. Gradientes (derivados x e y) de uma imagem são úteis porque a magnitude dos gradientes é grande em torno das arestas e cantos ( regiões de mudanças bruscas de intensidade ) e sabemos que as arestas e os cantos empacotam muito mais informações sobre a forma do objeto do que as regiões planas.
como calcular o histograma de gradientes orientados ?
nesta secção, analisaremos os pormenores do cálculo do descritor de características do porco. Para ilustrar cada passo, vamos usar um patch de uma imagem.
Passo 1 : Pré-processamento
tal como mencionado anteriormente, o descritor de características do porco utilizado para a detecção de peões é calculado num sistema de 64×128 de uma imagem. Claro, uma imagem pode ser de qualquer tamanho. Tipicamente patches em várias escalas são analisados em muitos locais de imagem. A única restrição é que os patches que estão sendo analisados têm uma razão de aspecto fixa. No nosso caso, os patches precisam ter uma proporção de 1: 2. Por exemplo, eles podem ser 100×200, 128×256, ou 1000×2000, mas não 101×205.
para ilustrar este ponto, mostrei uma grande imagem de tamanho 720×475. Selecionamos um patch de tamanho 100×200 para calcular o nosso descritor de recursos de porco. Este patch é cortado de uma imagem e redimensionado para 64×128. Agora estamos prontos para calcular o descritor de porco para este patch de imagem.
o artigo de Dalal e Triggs também menciona a correção gama como um passo de pré-processamento, mas os ganhos de desempenho são menores e por isso estamos pulando o passo.
Passo 2: calcular as imagens gradientes
para calcular um descritor de porco, é necessário primeiro calcular os gradientes horizontal e vertical; afinal, queremos calcular o histograma de gradientes. Isto é facilmente conseguido filtrando a imagem com os seguintes kernels.
nós também podemos alcançar os mesmos resultados, usando o operador Sobel no OpenCV com o tamanho do kernel 1.
// C++ gradient calculation.// Read imageMat img = imread("bolt.png");img.convertTo(img, CV_32F, 1/255.0);// Calculate gradients gx, gyMat gx, gy;Sobel(img, gx, CV_32F, 1, 0, 1);Sobel(img, gy, CV_32F, 0, 1, 1);
# Python gradient calculation # Read imageim = cv2.imread('bolt.png')im = np.float32(im) / 255.0# Calculate gradientgx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
ao lado, podemos encontrar a magnitude e a direção do gradiente usando a seguinte fórmula
Se você estiver usando o OpenCV, o cálculo pode ser feito usando a função cartToPolar como mostrado abaixo.
// C++ Calculate gradient magnitude and direction (in degrees)Mat mag, angle;cartToPolar(gx, gy, mag, angle, 1);
o mesmo código em python se parece com este.
# Python Calculate gradient magnitude and direction ( in degrees )mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
a figura abaixo mostra os gradientes.
repare, o gradiente x dispara em linhas verticais e o gradiente y dispara em linhas horizontais. A magnitude dos incêndios gradientes onde sempre há uma mudança acentuada na intensidade. Nenhum deles dispara quando a região está lisa. Eu deliberadamente deixei de fora a imagem que mostra a direção do gradiente porque a direção mostrada como uma imagem não transmite muito.
a imagem gradiente removeu um monte de informações não essenciais ( por exemplo, fundo colorido constante), mas esboços realçados. Em outras palavras, você pode olhar para a imagem gradiente e ainda facilmente dizer que há uma pessoa na imagem.
em cada pixel, o gradiente tem uma magnitude e uma direcção. Para imagens coloridas, os gradientes dos três canais são avaliados ( como mostrado na figura acima ). A magnitude do gradiente em um pixel é o máximo da magnitude dos gradientes dos três canais, e o ângulo é o ângulo correspondente ao gradiente máximo.
Passo 3 : Calcular o Histograma de Gradientes no 8×8 células
nesta etapa, a imagem é dividida em 8×8 células e um histograma de gradientes é calculado para cada 8×8 células.Vamos aprender sobre os histogramas em um momento, mas antes de irmos lá vamos primeiro entender por que dividimos a imagem em 8×8 células. Uma das razões importantes para usar um descritor de recurso para descrever um patch de uma imagem é que ele fornece uma representação compacta. Um patch de 8×8 imagens contém 8x8x3 = 192 valores de pixels. O gradiente deste patch contém 2 valores (magnitude e direção) por pixel, o que adiciona até 8x8x2 = 128 números.
no final desta seção veremos como esses 128 números são representados usando um histograma de 9 bin que pode ser armazenado como uma matriz de 9 números. Não só a representação é mais compacta, calculando um histograma sobre um patch torna esta representação mais robusta ao ruído. Os graidents individuais podem ter ruído, mas um histograma sobre 8×8 patch torna a representação muito menos sensível ao ruído.
mas porquê 8×8 patch ? Porque não 32×32 ? É uma escolha de design informada pela escala de recursos que estamos procurando. O porco foi usado inicialmente para a detecção de peões. 8×8 células em uma foto de um pedestre escalado para 64×128 são grandes o suficiente para capturar características interessantes ( por exemplo, a face, o topo da cabeça, etc. ).
o histograma é essencialmente um vector (ou uma matriz ) de 9 células ( números ) correspondentes a ângulos 0, 20, 40, 60 … 160.
vamos olhar para um patch 8×8 na imagem e ver como os gradientes parecem.
se você é um iniciante na visão do computador, a imagem no centro é muito informativa. Ele mostra o patch da imagem sobreposta com setas mostrando o gradiente — a seta mostra a direção do gradiente e seu comprimento mostra a magnitude. Observe como a direção das setas aponta para a direção da mudança de intensidade e a magnitude mostra quão grande é a diferença.
à direita, vemos os números brutos representando os gradientes nas 8×8 células com uma pequena diferença – os ângulos estão entre 0 e 180 graus em vez de 0 a 360 graus. Estes são chamados gradientes “sem sinal” porque um gradiente e é negativo são representados pelos mesmos números. Em outras palavras, uma seta gradiente e um 180 graus opostos a ela são considerados os mesmos. Mas, porque não usar os 0 a 360 graus ? Empiricamente, foi demonstrado que os gradientes sem sinal funcionam melhor do que os gradientes assinados para a detecção de peões. Algumas implementações de HOG lhe permitirão especificar se você deseja usar gradientes assinados.
o próximo passo é criar um histograma de gradientes nestas 8×8 células. O histograma contém 9 caixas correspondentes aos ângulos 0, 20, 40 … 160. A figura seguinte ilustra o processo. Estamos olhando para a magnitude e direção do gradiente do mesmo patch 8×8 como na figura anterior.
um bin é selecionado com base na direção, e o voto ( o valor que vai para o bin ) é selecionado com base na magnitude. Vamos primeiro focar-nos no pixel rodeado de azul. Tem um ângulo (direção ) de 80 graus e magnitude de 2. Então adiciona 2 ao 5º cesto. O gradiente no pixel circundado a vermelho tem um ângulo de 10 graus e uma magnitude de 4. Uma vez que 10 graus está a meio caminho entre 0 e 20, o voto do pixel divide-se uniformemente nos dois caixotes.
Há mais um detalhe a ter em consideração. Se o ângulo é maior que 160 graus, é entre 160 e 180, e sabemos que o ângulo envolve fazendo 0 e 180 equivalentes. Assim, no exemplo abaixo, o pixel com ângulo de 165 graus contribui proporcionalmente ao bin de 0 graus e ao bin de 160 graus.
as contribuições de todos os pixels nas células 8×8 são adicionadas para criar o histograma de 9 bin. Para o patch acima, parece-se com este
na nossa representação, o eixo y é 0 graus. Você pode ver que o histograma tem muito peso perto de 0 e 180 graus, o que é apenas outra maneira de dizer que nos gradientes do patch estão apontando para cima ou para baixo.
Passo 4 : 16×16 normalização dos blocos
na etapa anterior, criamos um histograma baseado no gradiente da imagem. Gradientes de uma imagem são sensíveis à iluminação geral. Se você tornar a imagem mais escura dividindo todos os valores de pixels por 2, a magnitude do gradiente irá mudar para a metade, e, portanto, os valores do histograma irá mudar para a metade. Idealmente, queremos que o nosso descritor seja independente das variações de iluminação. Em outras palavras, gostaríamos de” normalizar ” o histograma para que eles não sejam afetados por variações de iluminação.
Antes de explicar como o histograma é normalizado, vamos ver como um vetor de comprimento 3 é normalizado.Digamos que temos um vetor de cores RGB . O comprimento deste vector é $\sqrt{128^2 + 64^2 + 32^2} = 146.64$. Isto também é chamado de norma L2 do vetor. Dividindo cada elemento deste Vetor por 146.64 nos dá um vetor normalizado .
considere agora outro vetor no qual os elementos são o dobro do valor do primeiro vetor 2 x = . Você pode trabalhar para fora para ver que a normalização resultará em , que é o mesmo que a versão normalizada do vetor RGB original. Você pode ver que normalizar um vetor remove a escala.
agora que sabemos como normalizar um vetor, você pode ser tentado a pensar que ao calcular o porco você pode simplesmente normalizar o histograma 9×1 da mesma forma que normalizamos o vetor 3×1 acima. Não é uma má idéia, mas uma idéia melhor é normalizar sobre um bloco maior de 16×16.
a 16×16 block has 4 histograms which can be concatened to form a 36 x 1 element vector and it can be normalized just the way a 3×1 vector is normalized. A janela é então movida por 8 pixels (veja animação) e um vetor normalizado de 36×1 é calculado sobre esta janela e o processo é repetido.
Step 5: Calculate the HOG feature vector
To calculate the final feature vector for the entire image patch, the 36×1 vectors are concatenated into one giant vector. Qual é o tamanho deste vector ? Vamos calcular
- Quantas posições dos 16×16 blocos temos ? Existem 7 posições horizontais e 15 verticais, perfazendo um total de 7 x 15 = 105 posições.
- cada bloco de 16×16 é representado por um vector de 36×1. Então, quando os concatenamos todos em um vetor de ganho, obtemos um vetor 36×105 = 3780 dimensional.
Visualizando Histograma de gradientes orientados
o descritor HOG de um patch de imagem é geralmente visualizado através da representação dos 9×1 histogramas normalizados nas 8×8 células. Veja a imagem de lado. Você vai notar que a direção dominante do histograma captura a forma da pessoa, especialmente em torno do tronco e pernas.
infelizmente, não há uma maneira fácil de visualizar o descritor de porco no OpenCV.