计算图像中有多少个彩色点

7

首先,如果已经有这个主题,我很抱歉(我认为这是一个常见的任务,但找不到任何东西)。

问题是,我有一张图片,显示不同颜色的不同点。我需要一个脚本来计算有多少红色、绿色和黄色的点。 颜色是纯红(ff0000)、绿色(00ff00)和黄色(ffff00)。 这使得这更容易,并且形状定义明确。

enter image description here

我的当前方法是选择圆形(点)形状,选择它们,然后一旦我将所有点从背景图像中移开,读取它们的颜色来计数...

问题是我非常迷失。我知道这可以使用OpenCV完成,但不知道如何做(也找不到任何好的教程)。

有什么想法吗?


1
你一定要使用JPEG格式吗?难道不可以简单点,使用PNG格式吗? - Mark Setchell
然后对于每种不同的颜色(最好在HSV空间中),使用inRange函数,并计算连通组件的数量。可能再进行一些研究也无妨。 - Miki
不完整的点算不算? - Mark Setchell
你是否熟练掌握Python和OpenCV?这可以用四行bash代码实现,其中两行是for ... done循环,另一行是echo输出标签。 - Mark Setchell
欢迎来到StackOverflow。请阅读并遵守帮助文档中的发布指南。关于主题提问方式同样适用于这里。 StackOverflow不是设计、编码、研究或教程服务。 - Prune
3个回答

8
以下是基于OpenCV 3.2Python 2.7的示例解决方案。
为了计算有色点的数量,请按照以下四个步骤之一重复执行。
  1. 应用中值滤波器来减少噪声 - cv2.medianBlur()
  2. 应用颜色阈值来分割有色点 - 使用cv2.inRange()
  3. 使用霍夫圆变换检测圆形 - 使用circles = cv2.HoughCircles(mask,cv2.HOUGH_GRADIENT,...)
  4. 循环遍历每个检测到的圆以绘制其中心和周围的圆,并计算有色点的数量。

检测到的点的示例图像:

红色 - 10个点 enter image description here

绿色 - 39个点 enter image description here

黄色 - 30个点 enter image description here

请注意,最右侧带有不到半个圆的黄点未被检测到。这可能是Hough圆变换cv2.HoughCircles()的限制。因此,如果发生此类问题,您需要决定如何处理它。

以下是示例代码:

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)

希望这能有所帮助。

5
由于您似乎没有得到有关OpenCV/Python解决方案的太多帮助,我想发布一种不同的方法-使用和ImageMagick。我将首先展示脚本,然后稍后解释一下它。
大多数Linux发行版都安装有ImageMagick,并可免费在macOS和Windows上使用。它还具有C/C++、Perl、Python、PHP、Ruby、Java绑定。请注意,不需要编写任何代码,也不需要编译器。
#!/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

输出结果如下:

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

convert 命令是 ImageMagick 套件的一部分。让我们来看看当 colourred 时,第一次循环中该命令如何工作。最初,我们只看 convert 命令的前两行:

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

希望您能看到,它会填充所有红色范围内20%的像素为白色,然后将不是白色的所有像素填充为纯黑色。

enter image description here

< p > convert 命令的其余部分对上面的图像执行“连接组件分析”,并列出所有面积超过800像素的 blob - 这大约是您的 blob 平均大小的一半,这就是我在评论部分询问部分 blob 的原因。让我们看看运行时会发生什么:

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

输出

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)

希望您能看到第一行是描述列的标题,有10行白色srgb(255,255,255),每行对应一个圆形块(即我们将其变为白色的红色磁盘之一)。它们都约为39x39像素(即正方形中的圆形),面积约为1150像素 - 如果想象半径为19像素,则Pi*r^2=1150。它们的大小(作为宽度和高度)和位置(作为从左上角的x和y)在第二列中。
如果您想计算至少25%全尺寸块大小的部分块,则需要将阈值更改为1150(自然,完整块大小)的25%或287,而不是我估计的800。
剩余的脚本只是计算具有白色块的行数(grep -c),并为您寻找的其他颜色重复此过程。请注意,您的“绿色”对应于X11命名方案中ImageMagick使用的“酸橙色”。
仅供娱乐,让我们用半透明蓝色填充上面输出列表中我标记的块所在位置:
convert dots.jpg -fill "rgba(0,0,255,0.5)" -draw "rectangle 848,595 887,634" temp.png

enter image description here

我希望这有助于完成工作并展示一种方法,即使它不是你期望使用的工具。请注意,OpenCV具有Connected Components和类似的算法-我只是不会说Python,而C++版本对你也没有更多的帮助!

1
非常详细的解释,马克。你也可以通过将除了三种颜色以外的所有东西都变成白色来避免循环,然后运行连接组件,它会列出每种颜色的区域。但是,然后你就必须对该列表进行后处理以计算每种颜色的数量。所以我认为你的方法可能更简单和直接。 - fmw42

5

既然您已经知道要寻找的颜色,我会根据颜色对图像进行分割。我会按照以下步骤进行:

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++

正如 @Mark 指出的那样,您的图像必须是 PNG 格式。

此外,这也假设红色、绿色和黄色圆点中的颜色不会在图像的其他部分出现。


@Akiru 如果这里发布的任何答案有帮助解决了你的问题,请标记适当的答案为已接受。 - Shawn Mathew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接