获得更干净的斑点以进行计数

Getting cleaner blobs for counting

还在学习图像遮罩的路上。

我正在计算图像中红点的数量。

这是输入图像

遮住红色后,得到这张图

问题是,有些斑点不完整,所以它不计算所有斑点,例如在这个特定图像中,它不计算数字 6 和 9。(假设左上角是 1)

如何改进掩蔽过程以获得更准确的斑点?

屏蔽码:

import cv2, os
import numpy as np

os.chdir('C:\Program Files\Python\projects\Blob')

#Get image input
image_input = cv2.imread('realbutwithacrylic.png')
image_input = np.copy(image_input)
rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB)

#Range of color wanted
lower_red = np.array([125, 1, 0])
upper_red = np.array([200, 110, 110])

#Masking the Image
first_mask = cv2.inRange(rgb, lower_red, upper_red)

#Output
cv2.imshow('first_mask', first_mask)
cv2.waitKey()

使用 Blob 计数器屏蔽代码

import cv2, os
import numpy as np

#Some Visual Studio Code bullshit because it cant find the image????
os.chdir('C:\Program Files\Python\projects\Blob')

#Get image input
image_input = cv2.imread('realbutwithacrylic.png')
image_input = np.copy(image_input)
rgb = cv2.cvtColor(image_input, cv2.COLOR_BGR2RGB)

#Range of color wanted
lower_red = np.array([125, 1, 0])
upper_red = np.array([200, 110, 110])

#Masking the Image
first_mask = cv2.inRange(rgb, lower_red, upper_red)

#Initial masking counter
cv2.imshow('first_mask', first_mask)
cv2.waitKey()

#Blob Counter
thresh = cv2.threshold(first_mask,0,255,cv2.THRESH_OTSU + cv2.THRESH_BINARY)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=5)

cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

#Couting the blobs
blobs = 0
for c in cnts:
    area = cv2.contourArea(c)
    cv2.drawContours(first_mask, [c], -1, (36,255,12), -1)
    if area > 13000:
        blobs += 2
    else:
        blobs += 1

#Blob Number Output
print('blobs:', blobs)

#Masking Output
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image_input)
cv2.imshow('mask', first_mask)
cv2.waitKey()

由于您正在寻找足够明亮的红色,因此您可能有更好的时间用 HSV 掩盖事物 space:

orig_image = cv2.imread("realbutwithacrylic.jpg")

image = orig_image.copy()
# Blur image to get rid of noise
image = cv2.GaussianBlur(image, (3, 3), cv2.BORDER_DEFAULT)
# Convert to hue-saturation-value
h, s, v = cv2.split(cv2.cvtColor(image, cv2.COLOR_BGR2HSV))
# "Roll" the hue value so reds (which would otherwise be at 0 and 255) are in the middle instead.
# This makes it easier to use `inRange` without needing to AND masks together.
image = cv2.merge(((h + 128) % 255, s, v))
# Select the correct hues with saturated-enough, bright-enough colors.
image = cv2.inRange(image, np.array([40, 128, 100]), np.array([140, 255, 255]))

对于你的图像,输出是

使用哪个应该更直接。

@AKX 有一个很好的建议,但我更喜欢 HSI(如 A. Hanbury and J. Serra, “Colour image analysis in 3D-polar coordinates”, Joint Pattern Recognition Symposium, 2003), which is typically more suited for image analysis than HSV. Note that this is not the same as another common conversion often also referred to as HSI, which involves an arc cosine operation -- this HSI does not involve trigonometry. For details, if you don't have access to the paper above, see an implementation in C++.

中所述

此外,高斯模糊应该更强一些。您有一张 JPEG 压缩图像,压缩率非常高。 JPEG 会破坏颜色,因为 we're not good at seeing color edges。我们对此图像的最佳解决方案是应用大量平滑处理。当然,更好的解决方案是改善成像。

色调通道上的适当阈值应该允许我们排除所有橙色,其色调不同于红色(根据定义,接近 0 度)。我们还必须排除饱和度低的像素,因为一些暗区可能有红色调。

我正在展示如何使用 DIPlib 执行此操作,因为我很熟悉它(披露:我是作者)。我相信你可以用 OpenCV 做同样的事情,尽管你可能需要从头开始实现 HSI 颜色 space 转换。

import diplib as dip

img = dip.ImageRead('aAvJj.jpg')
img = dip.Gauss(img, 2)    # sigma = 2
hsi = dip.ColorSpaceManager.Convert(img,'hsi')
h = hsi(0)
s = hsi(1)
h = (h + 180) % 360 - 180  # turn range [180,360] into [-180,0]
dots = (dip.Abs(h) < 5) & (s > 45)

要计算点数,您现在可以简单地:

lab = dip.Label(dots)
print(dip.MaximumAndMinimum(lab)[1])

...表示 10。

虽然这两个答案都提供了适当的解决方案,但提及以下内容可能很重要:

  • Cris Luengo 设法提供了 noise-free 面具,这要多得多 更容易对付
  • 两种解决方案都在某种程度上引入了 color difference/delta_E,这一点很重要(可能需要额外的依赖,但肯定会简化一切)
  • 这些红色标记可能不是那么重要(见下面的示例),但在可靠性方面很好

只是一个小的 PoC(没有代码,使用自定义分割管道):

和面具:

如果您认为 delta_E 是矫枉过正,只需检查 several examples with dynamic scenes and changing light conditions。任何对特定颜色进行硬编码的尝试都可能会失败。