我有以下问题:我需要可靠地检测图像中的图标。该图像还包含文本,并且图标有各种尺寸。
目前,我使用 Python 和 cv2 库来完成此任务。然而,不幸的是,当前使用
cv2.findContours
的轮廓检测算法不太可靠。这是我目前正在做的事情:
gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
binary = cv2.adaptiveThreshold(self.gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 17, 1)
contours, _ = cv2.findContours(self.binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
然后进行轮廓过滤,合并过滤后的轮廓,再次过滤。
然而,事实证明这种方法并不可靠。
我也尝试过使用
getStructuringElement
,但它为白色背景上的图标提供了不可靠的结果。
我无法透露真实的输入数据,但我使用了亚马逊徽标并创建了一个示例来演示该问题。
对于彩色图标,当使用轮廓时,我经常会得到两个或三个尺寸不正确的图标,并且合并它们会失去精确的尺寸。对于白色背景上的图标,使用
getStructuringElement
的方法不能很好地检测边界。
我的问题: 你有什么建议? 我的想法:
我愿意接受任何建议,或者让我知道是否有人有解决此类问题的经验。
为了提高可靠性,请使用轮廓数据来检查轮廓面积。图标的面积似乎比文本更大,因此您可以为该区域设置阈值以将其过滤掉。
我认为边缘检测在这里可以很好地工作,我做了一个现在有效的小例子:
im = cv2.imread("logos.jpg")
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(imGray,5, 20)
这给出了以下结果:
在此之后,检测轮廓并按区域过滤将非常有效,因为徽标的方块似乎都是相同大小的:
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
sortedContours = sorted(contours, key = cv2.contourArea, reverse = True)
for c in sortedContours:
print(cv2.contourArea(c))
我们看到,面积最大的三个轮廓确实都有 10500 像素左右:
10787.0
10715.0
10128.0
7391.5
4555.5
3539.0
3420.0
.
.
.
填充前三个轮廓:
im1 = cv2.drawContours(im.copy(), sortedContours, 2, (255,0,0), -1)
im2 = cv2.drawContours(im.copy(), sortedContours, 1, (0,255,0), -1)
im3 = cv2.drawContours(im.copy(), sortedContours, 0, (0,0,255), -1)
这就是您将得到的:
我假设你想要的是一个布尔掩码来获取这些像素。所以类似
mask = np.zeros_like(imGray)
mask = cv2.drawContours(mask, sortedContours, 2, 1, -1)
firstLogo = cv2.bitwise_and(im, im, mask = mask)
可以胜任这项工作。您可以通过过滤轮廓轻松地实现自动化,我只是向您推送一个 POC。