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”
Awesome blog. Really looking forward to read more. Much obliged. Annadiana Asher Ebsen
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!
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?
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.
I’m gone to convey my little brother, that he should also pay a visit this blog on regular
basis to obtain updated from newest reports.