No busques más en otros sitios ya que llegaste al lugar perfecto, tenemos la respuesta que necesitas pero sin problema.
Solución:
Aquí hay una solución de muestra basada en OpenCV 3.2
y Python 2.7
.
Para contar los puntos de colores, repita los siguientes 4 pasos una vez por tipo de color.
- Aplicar filtro mediano para reducir el ruido –
cv2.medianBlur()
. - Aplicar umbral de color para segmentar los puntos de color – utilizar
cv2.inRange()
. - Use Hough Circle Transform para detectar los círculos – use
circles = cv2.HoughCircles(mask,cv2.HOUGH_GRADIENT,...)
- Recorra cada círculo detectado para dibujar su centro y un círculo a su alrededor, y cuente el número de puntos de colores.
Imágenes de muestra de puntos detectados:
Rojo – 10 puntos
Verde – 39 puntos
Amarillo – 30 puntos
Tenga en cuenta que no se han detectado los últimos puntos amarillos del lado derecho con menos de medio círculo. Esta es probablemente una limitación de la Transformada de círculo de Hough 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 = numpy.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++
Sin embargo, su imagen tendría que ser una imagen PNG, como señaló @Mark.
Además, esto supone que los colores de los puntos rojo, verde y amarillo no aparecen en ningún otro lugar de la imagen.
Como no parece estar recibiendo mucha ayuda con una solución OpenCV / Python, pensé en publicar de una manera diferente: usando bash
y ImageMagick. Te mostraré el bash
guión primero, luego explíquelo un poco después.
ImageMagick está instalado 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 código para esto y no es necesario ningún compilador.
#!/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
los convert
El comando es parte del ImageMagick suite. Echemos un vistazo a cómo funciona ese comando la primera vez a través del ciclo cuando colour
es red
. Inicialmente, veamos solo las primeras 2 líneas del convert
mando:
convert dots.jpg -fuzz 20%
-fill white -opaque red -fill black +opaque white intermediate.png
Con suerte, puede ver que llena de blanco todos los píxeles dentro del 20% del rojo, y luego llena de negro puro todos los píxeles que no son blancos.
El resto del convert
comando pone la imagen de arriba a través de un “Análisis de componentes conectados” y enumera todas las manchas con un área superior a 800 píxeles, que es aproximadamente la mitad del tamaño promedio de sus manchas y es por eso que pregunté en la sección de comentarios sobre las manchas parciales. Veamos qué sucede cuando ejecutamos eso:
convert intermediate.png
-define connected-components:verbose=true
-define connected-components:area-threshold=800
-connected-components 8 -auto-level output.png
Producción
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)
Con suerte, puede 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). Todos tienen alrededor de 39x39 píxeles (es decir, circulares en un cuadro cuadrado) con un área de alrededor de 1150 píxeles; si imagina un radio de 19 píxeles, entonces Pi * r ^ 2 = 1150. Sus tamaños (como ancho y alto) y ubicaciones (como xey desde la esquina superior izquierda) están en la segunda columna.
Si quisiera contar 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 de blob completo natural) o 287, en lugar de los 800 que calculé.
El resto del script 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 "Lima" en el esquema de nomenclatura X11 que ImageMagick usos.
Solo por diversión, completemos con azul semitransparente la mancha 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
Espero que ayude a hacer el trabajo y muestre un método incluso si no son las herramientas que esperaba usar. Tenga en cuenta que OpenCV
tiene Connected Components
y algoritmos similares: ¡simplemente no hablo Python y una versión C ++ ya no es de ayuda para usted!
Reseñas y valoraciones
Recuerda mostrar este ensayo si te valió la pena.