domingo, 20 de setembro de 2015

Contando Elementos de uma Imagem Binária

Uma das partes do processamento de imagens é a identificação de elementos nela contidos. Neste exemplo, será demostrada uma maneira de realizar a contagem de elementos em uma imagem binária (fundo preto 0, elemento branco 1) por meio da linguagem Python.

Após recebida a imagem, operação realizada com o auxílio da biblioteca OpenCv (cv2), é preciso realizar a normalização da mesma para se adequar ao formato binário.

 img = cv2.imread("img.png",0)  
 img[img > 50] = 1  
 img[img <> 1] = 0 

Utilizou-se o limiar 50 para o caso de serem inseridas imagens em tons de cinza em que tons mais baixos que a metade dos níveis ainda podem ser um objeto.

Considerou-se a abordagem de vizinhança do objeto como 4-conexo. Desse modo, para verificar os pixels pertencentes à um objeto é preciso partir do atual e verificar 4 pixels ao seu redor.


Para melhor visualização dos resultados, não contou-se os elementos apenas, mas criou-se uma matriz de mesmo tamanho da original em que o fundo possui valor zero e cada elemento é preenchido com um valor diferente. Assim, caso a entrada seja:

[[0 0 1 0 0 0 0 0 0 0]
 [0 1 1 0 1 0 0 0 0 0]
 [0 1 1 1 1 0 0 0 0 0]
 [0 0 1 1 0 0 0 0 0 0]
 [0 0 0 0 1 1 1 1 0 0]
 [0 0 0 0 1 0 0 1 0 0]
 [0 1 1 0 1 0 0 1 0 0]
 [0 1 1 0 1 0 0 1 0 0]
 [0 0 0 0 1 1 1 1 0 0]
 [0 0 1 0 0 0 0 0 0 0]]

Será obtida a saída:

4

[[0 0 1 0 0 0 0 0 0 0]
 [0 1 1 0 1 0 0 0 0 0]
 [0 1 1 1 1 0 0 0 0 0]
 [0 0 1 1 0 0 0 0 0 0]
 [0 0 0 0 2 2 2 2 0 0]
 [0 0 0 0 2 0 0 2 0 0]
 [0 3 3 0 2 0 0 2 0 0]
 [0 3 3 0 2 0 0 2 0 0]
 [0 0 0 0 2 2 2 2 0 0]
 [0 0 4 0 0 0 0 0 0 0]]

Para construção do objeto implementou-se uma fila em que seriam inseridos os possíveis pixels contidos no mesmo objeto a partir do pixel atual. A cada pixel analisado, sua posição na matriz original é setada como "-1", identificando que esse pixel não poderá ser utilizado novamente.

Em busca de reduzir o processamento, não analisaram-se todos os pixels da imagem inicial, mas apenas os que fazem parte de algum objeto. Isso é possível com a utilização da função "nonzero()", que retorna dois vetores com as posições das linhas e colunas, respectivamente, em que existem valores diferentes de zero. Nesse caso, todos os valores que não são zeros são uns, e representam os objetos.

Segue o código completo utilizado:

 import numpy as np  
 import cv2  
   
 def contaElementos(img):  
   l,c = np.shape(img)  
   count = 0  
   fila = []  
   m = np.zeros((l,c))  
     
   (linha,coluna) = img.nonzero()  
   tam = len(linha)  
       
   for i in range(tam):  
     e = [linha[i],coluna[i]]      
     if img[e[0]][e[1]] == 1:  
       fila.append(e)  
       count+=1;  
       while len(fila) <> 0:  
         [i0,i1] = fila.pop(0)  
         if img[i0][i1] == 1:  
           img[i0][i1] = -1  
           m[i0][i1] = count            
           if i0 > 0 and fila.count([i0-1,i1]) == 0 and img[i0-1][i1] <> -1:  
             fila.append([i0-1,i1])  
           if i1 > 0 and fila.count([i0,i1-1]) == 0 and img[i0][i1-1] <> -1:  
             fila.append([i0,i1-1])  
           if i0 < l-1 and fila.count([i0+1,i1]) == 0 and img[i0+1][i1] <> -1:  
             fila.append([i0+1,i1])  
           if i1 < c-1 and fila.count([i0,i1+1]) == 0 and img[i0][i1+1] <> -1:  
             fila.append([i0,i1+1])            
             
     img[linha[i]][coluna[i]] = -1  
             
   return count,np.uint8(m)
   
 img = cv2.imread("img.png",0)  
 img[img > 50] = 1  
 img[img <> 1] = 0  
   
 contaElementos(img)  

0 comentários:

Postar um comentário