Segmentação usando espaço de cor

Técnicas poderosas como deep learning estão em alta quando se trata de detecção e segmentação de objetos em imagens. Entretanto, para análise de vídeo em tempo real, uma simples segmentação baseada em cor poder ser muito eficiente.

O espaço de cor mais comum é o RGB (vermelho verde e azul). Cada pixel é representado por uma tupla contendo 3 ou 4 valores que variam de 0 a 255 (8bits). 

O OpenCV tem mais de 150 implementação de espaço de cor aqui.  Para converter uma imagem usamos função cvtColor. 

hsv_img=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

O parâmetro COLOR_BGR2HSV (BGR to HSV), BGR é o espaço de cor da imagem de entrada e HSV é o espaço de cor de saída. 

Isso é bem intuitivo, se quiser converte a imagem para o formato original então o parâmetro é cv2.COLOR_HSV2BGR. 

Mais o que é espaço HSV?

HSV é a abreviatura para o sistema de cores formadas pelas componentes hue (matiz), saturation (saturação) e value (valor). 

O script abaixo inicia sua webcam e mostra na tela a imagem original e convertida para espaço HSV.

import cv2
cap=cv2.VideoCapture(0)

while(cap.isOpened()):
    _,img=cap.read()
    hsv_img=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
    cv2.imshow("img",img)
    cv2.imshow("hsv",hsv_img)
    cv2.waitKey(30)

Para segmentação de imagens, o espaço HSV é o mais utilizado porque as cores são representadas apenas no canal H, os outros dois estão relacionado com a tonalidade.

Para mapear uma cor, precisamos delimitar um valor máximo e mínimos para cada canal.

O script abaixo cria uma janela com as barras para selecionar os valores.

import cv2
import numpy as np
cv2.namedWindow("janela")
cap=cv2.VideoCapture(0)
def mause(pos):
    pass
cv2.createTrackbar("H_min", "janela" , 0, 180,mause)
cv2.createTrackbar("S_min", "janela" , 0, 255,mause)
cv2.createTrackbar("V_min", "janela" , 0, 255,mause)
cv2.createTrackbar("H_max", "janela" , 0, 180,mause)
cv2.createTrackbar("S_max", "janela" , 0, 255,mause)
cv2.createTrackbar("V_max", "janela" , 0, 255,mause)
while(cap.isOpened()):
    ret,frame=cap.read()
    h_min = cv2.getTrackbarPos("H_min", 'janela')
    s_min = cv2.getTrackbarPos("S_min", 'janela')
    v_min = cv2.getTrackbarPos("V_min", 'janela')
    h_max = cv2.getTrackbarPos("H_max", 'janela')
    s_max = cv2.getTrackbarPos("S_max", 'janela')
    v_max = cv2.getTrackbarPos("V_max", 'janela')
    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    maks=cv2.inRange(hsv,np.array([h_min,s_min,v_min]),np.array([h_max,s_max,v_max]))

    saida=cv2.bitwise_and(frame,frame,mask=maks)
    string = "H_min " + str(h_min)+" S_min "+str(s_min)+ " V_min "+str(v_min)
    string=string+" H_max " + str(h_max)+" S_max "+str(s_max)+ " V_max "+str(v_max)
    cv2.putText(saida, string, (10, 30), cv2.FONT_HERSHEY_COMPLEX, 0.45, (0, 0, 255))
    cv2.imshow("janela",saida)
    k = cv2.waitKey(30)
    if k ==ord("q"):
        break

Mova as barras H_max, S_max e V_max para o final. Você deve ver a imagem sem nem uma alteração. Comece a aumentar lentamente H_min ate o objeto que você queira detectar comece a desaparecer, Faça o mesmo para as demais.

O final, anote os valores escrito em vermelho na imagen.

Aplicação

Vamos desenvolver um script que selecione duas cores, azul e laranja.

import cv2
import numpy as np
cap=cv2.VideoCapture(0)

#define intervalos de cores
 #[(H_min, S_min, V_min) , (H_max, S_max, V_max)]
azul=[(71 , 107 , 78),(117, 255, 211)]
laranja=[(4, 155, 128), (21, 255, 255)]

while(cap.isOpened()):
    _,img=cap.read() # le um frame
    hsv_img=cv2.cvtColor(img,cv2.COLOR_BGR2HSV) # converte para escala HSV
    # cria mascara para cor azul
    mask_azul = cv2.inRange(hsv_img, np.array(azul[0]), np.array(azul[1]))
    # pega contorno dos objetos da mascara
    cnt_azul=cv2.findContours(mask_azul,
                              cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[0]
    # ordena por area e pega os dois maiores objetos
    cnt_azul=sorted(cnt_azul, key=cv2.contourArea, reverse=True)[:2]
    
    if cnt_azul: # testa se encontrou objeto azul
        for cont in cnt_azul: # pecorre contoros encontrados
            # pega centro e raio de um circo incrito do objeto
            (cx,cy),raio=cv2.minEnclosingCircle(cont)
            # escreve nome da cor
            cv2.putText(img,"Azul",(int(cx),int(cy)),
                    cv2.FONT_HERSHEY_COMPLEX,0.9,(255,0,0),1)
            # Desenha circulo
            cv2.circle(img,(int(cx),int(cy)),int(raio),(255,0,0),3)
            
    # repeto porcesso para cor laranja mais pegamos apena um objeto
    mask_laranja = cv2.inRange(hsv_img, np.array(laranja[0]), np.array(laranja[1]))
    cnt_laranja = cv2.findContours(mask_laranja,
                                   cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]
    cnt_laranja = sorted(cnt_laranja, key=cv2.contourArea, reverse=True)[:1]

    if cnt_laranja:
        (cx, cy), raio = cv2.minEnclosingCircle(cnt_laranja[0])
        cv2.putText(img, "Laranja", (int(cx), int(cy)),
                    cv2.FONT_HERSHEY_COMPLEX, 0.9, (28, 153, 206), 1)
        cv2.circle(img, (int(cx), int(cy)), int(raio),(28, 153, 206),3)

    cv2.imshow("img",img) #atualiza janela
    k=cv2.waitKey(30) # aguarda
    if k==ord("q"): # finaliza de a tecla q for precionada
        break

Aqui esta o resultado.

Nesse artigo mapeamos apenas a cor Azul e laranja, seguindo os mesmos paços você pode mapear as cores que desejar.

Caso tenho alguma dúvida ou problema para executar os scripts, deixe nos comentários, Obrigado!

6 Replies to “Segmentação usando espaço de cor”

  1. A person necessarily help to make significantly articles I would state.
    This is the first time I frequented your website page and thus far?
    I amazed with the analysis you made to make this particular put up incredible.
    Magnificent process!

  2. Parabéns!

    Fiz um código para encontrar a cor azul em imagens de células e está funcionando muito bem.
    Porém, preciso informar uma faixa de azul inicial e final.

    Acontece que existe uma variabilidade de tons azuis e me foi determinado que eu preciso olhar a imagem, identificar o azul inicial e final dessa imagem de forma automática e não arbitrária em HSV e RGB para fazer comparações. Pode ajudar?

    1. Marcos, que bom que conseguiu segmentar.
      você pode aplicar algum algoritmo de correção, tipo uma equalização para tentar manter sua cor em um intervalo previsível. Porém tenho que salientar que a segmentação como descrita aqui, embora apresenta algumas vantagens, ela tem limitações, normalmente não funciona bem em ambientes dinâmicos.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *