contar puntos de colores en la imagen

En primer lugar, disculpe si este tema ya existe (creo que esta es una tarea común, pero no pude encontrar nada).

El punto, es que tengo una imagen que muestra diferentes puntos de diferentes colores. Y necesito un script para contar cuántos puntos rojos, verdes y amarillos son. Los colores son rojo puro (ff0000), verde (00ff00) y amarillo (ffff00). Lo que hace esto más fácil, y la forma está bien definida.

introduzca la descripción de la imagen aquí

Mi enfoque actual es seleccionar la forma redonda (puntos), seleccionarlas y luego, una vez que tenga todos los puntos alejados de la imagen de fondo, lea su color para contarlos …

El punto es que estoy tan perdido con esto. Sé que esto se puede hacer con OpenCV pero no sé cómo (y no pude encontrar ningún tutorial agradable).

¿Alguna idea?

Aquí hay una solución de ejemplo basada en OpenCV 3.2 y Python 2.7 .

Para contar los puntos de color, repita debajo de 4 pasos una vez por tipo de color.

  1. Aplique el filtro de mediana para reducir el ruido – cv2.medianBlur() .
  2. Aplique el umbral de color para segmentar los puntos de color: use cv2.inRange() .
  3. Use Hough Circle Transform para detectar los círculos – use circles = cv2.HoughCircles(mask,cv2.HOUGH_GRADIENT,...)
  4. Recorra cada círculo detectado para dibujar su centro y un círculo a su alrededor, y cuente los números de puntos de colores.

Imágenes de muestra de puntos detectados:

Rojo – 10 puntos introduzca la descripción de la imagen aquí

Verde – 39 puntos introduzca la descripción de la imagen aquí

Amarillo – 30 puntos introduzca la descripción de la imagen aquí

Tenga en cuenta que los últimos puntos amarillos en el lado derecho con menos de medio círculo no se han detectado. Esta es probablemente una limitación de la Hough Circle Transform cv2.HoughCircles() . Por lo tanto, debe decidir cómo manejar este tipo de problema si ocurre.

Aquí está el código de ejemplo:

 import cv2 import numpy red = [(0,0,240),(10,10,255)] # lower and upper green = [(0,240,0),(10,255,10)] yellow = [(0,240,250),(10,255,255)] dot_colors = [red, green, yellow] img = cv2.imread('./imagesStackoverflow/count_colored_dots.jpg') # apply medianBlur to smooth image before threshholding blur= cv2.medianBlur(img, 7) # smooth image by 7x7 pixels, may need to adjust a bit for lower, upper in dot_colors: output = img.copy() # apply threshhold color to white (255,255, 255) and the rest to black(0,0,0) mask = cv2.inRange(blur,lower,upper) circles = cv2.HoughCircles(mask,cv2.HOUGH_GRADIENT,1,20,param1=20,param2=8, minRadius=0,maxRadius=60) index = 0 if circles is not None: # convert the (x, y) coordinates and radius of the circles to integers circles = np.round(circles[0, :]).astype("int") # loop over the (x, y) coordinates and radius of the circles for (x, y, r) in circles: # draw the circle in the output image, # then draw a rectangle corresponding to the center of the circle cv2.circle(output, (x, y), r, (255, 0, 255), 2) cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (255, 0, 255), -1) index = index + 1 #print str(index) + " : " + str(r) + ", (x,y) = " + str(x) + ', ' + str(y) print 'No. of circles detected = {}'.format(index) 

Espero que esto ayude.

Como ya conoce los colores que está buscando, segmentaría la imagen en función del color. Los pasos que seguiría son:

 red_dot_count = 0 yellow_dot_count = 0 green_dot_count = 0 For each pixel in the image: if pixel color is red: floodfill using this pixel as seed pixel and target_color as black red_dot_count++ if pixel color is green: floodfill using this pixel as seed pixel and target_color as black green_dot_count++ if pixel is yellow: floodfill using this pixel as seed pixel and target_color as black yellow_dot_count++ 

Tu imagen tendría que ser una imagen PNG, aunque como lo señaló @Mark.

Además, esto supone que los colores en los puntos rojo, verde y amarillo no aparecen en ninguna otra parte de la imagen.

Como parece que no recibes mucha ayuda con una solución OpenCV / Python, pensé que publicaría de otra forma: usando bash e ImageMagick . Primero mostraré el script de bash y luego lo explicaré un poco.

ImageMagick se instala en la mayoría de las distribuciones de Linux y está disponible para macOS y Windows de forma gratuita. También tiene enlaces C / C ++, Perl, Python, PHP, Ruby, Java. Tenga en cuenta que no es necesario escribir ningún código para esto y que no es necesario ningún comstackdor.

 #!/bin/bash for colour in red yellow lime ; do echo -n "Colour: $colour " convert dots.jpg -fuzz 20% \ -fill white -opaque $colour -fill black +opaque white \ -define connected-components:verbose=true \ -define connected-components:area-threshold=800 \ -connected-components 8 output.png | grep -c "rgb(255,255,255)" done 

La salida se ve así:

 Colour: red 10 Colour: yellow 30 Colour: lime 37 

El comando de convert es parte de la suite ImageMagick . Veamos cómo funciona ese comando la primera vez que pasa por el bucle cuando el colour es red . Inicialmente, veamos solo las primeras 2 líneas del comando de convert :

 convert dots.jpg -fuzz 20% \ -fill white -opaque red -fill black +opaque white intermediate.png 

Esperamos que pueda ver que se llena con todos los píxeles en blanco dentro del 20% del rojo, y luego con todos los píxeles que no son blancos en negro puro.

introduzca la descripción de la imagen aquí

El rest del comando de convert coloca la imagen en la parte superior a través de un “Análisis de Componentes Conectados” y enumera todas las manchas con un área que excede los 800 píxeles, que es aproximadamente la mitad del tamaño promedio de las manchas y es por eso que en la sección de comentarios le pregunté sobre manchas parciales . Veamos que pasa cuando ejecutamos eso:

 convert intermediate.png \ -define connected-components:verbose=true \ -define connected-components:area-threshold=800 \ -connected-components 8 -auto-level output.png 

Salida

 Objects (id: bounding-box centroid area mean-color): 0: 1342x858+0+0 670.0,426.9 1140186 srgb(0,0,0) 191: 39x39+848+595 866.9,614.1 1165 srgb(255,255,255) <--- DRAW THIS ONE 192: 39x39+482+664 500.9,682.9 1165 srgb(255,255,255) 117: 38x39+4+292 22.5,311.0 1155 srgb(255,255,255) 194: 39x38+1250+732 1268.9,750.5 1154 srgb(255,255,255) 178: 39x38+824+512 843.0,530.1 1154 srgb(255,255,255) 186: 39x38+647+549 666.0,567.5 1152 srgb(255,255,255) 197: 38x39+1270+796 1288.5,815.0 1150 srgb(255,255,255) 173: 38x38+811+444 829.5,462.5 1143 srgb(255,255,255) 195: 38x39+711+783 729.6,801.5 1138 srgb(255,255,255) 107: 27x39+0+223 11.5,242.0 874 srgb(255,255,255) 

Esperamos que pueda ver que la primera línea es un encabezado que describe las columnas, y hay 10 líneas que son srgb blancas (255,255,255) y cada línea corresponde a un blob, es decir, uno de sus discos rojos (que hicimos en blanco). Son alrededor de 39x39 píxeles (es decir, circulares en una caja cuadrada) con un área de alrededor de 1150 píxeles. Si imaginas un radio de 19 píxeles, entonces Pi * r ^ 2 = 1150. Sus tamaños (como ancho y alto) y las ubicaciones (como xey de la esquina superior izquierda) están en la segunda columna.

Si quisiera contar con blobs parciales tan pequeños como el 25% de un blob de tamaño completo, cambiaría el umbral al 25% de 1150 (el tamaño del blob natural, total) o 287, en lugar de los 800 I estimados.

El rest de la secuencia de comandos simplemente cuenta las líneas con manchas blancas en ellas ( grep -c ) y repite el proceso para los otros colores que busca. Tenga en cuenta que su "verde" corresponde a "cal" en el esquema de nombres X11 que utiliza ImageMagick .

Solo por diversión, completemos con un azul semitransparente el blob que he marcado con una flecha en la lista de salida anterior:

 convert dots.jpg -fill "rgba(0,0,255,0.5)" -draw "rectangle 848,595 887,634" temp.png 

introduzca la descripción de la imagen aquí

Espero que esto ayude a hacer el trabajo y muestre un método, incluso si no son las herramientas que esperaba utilizar. Tenga en cuenta que OpenCV tiene Connected Components y algoritmos similares. Simplemente no hablo Python y una versión de C ++ no es más útil para usted.