我正在使用OpenCV帮助我将边界框放在手写的数学方程输入上。当前,我的代码有时会在单个图像的不同部分周围放置多个较小的边界框,而不是在图像周围创建一个较大的框。我不确定为什么会这样。我当前用于过滤图像并找到轮廓绘制边框的代码如下:
img = cv2.imread(imgpath)
morph = img.copy()
morph = cv2.fastNlMeansDenoising(img)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)
morph = cv2.morphologyEx(morph, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 15))
# take morphological gradient
gradient_image = cv2.morphologyEx(morph, cv2.MORPH_GRADIENT, kernel)
gray = cv2.cvtColor(gradient_image, cv2.COLOR_BGR2GRAY)
img_grey = cv2.morphologyEx(gray, cv2.MORPH_CLOSE, kernel)
blur = cv2.medianBlur(img_grey,3)
ret, thing = cv2.threshold(blur, 0.0, 255.0, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
img_dilation = cv2.dilate(thing, kernel, iterations=3)
conturs_lst = cv2.findContours(img_dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
实际结果示例如下:
OG图片:
答案 0 :(得分:4)
您的想法正确,但我认为您过度使用cv2.morphologyEx
来不断侵蚀和扩大图像。您提到您的问题:
当前,我的代码有时会在单个图像的不同部分周围放置多个较小的边界框,而不是在图像周围创建一个大框。
使用cv2.findContours
时,它可以正常工作,但是由于轮廓实际上是斑点,而不是一个互连的奇异图像,因此它会创建多个边界框。要解决此问题,您可以扩大图像以将斑点连接在一起。
我已经重写了您的代码,没有多余的cv2.morphologyEx
重复。主要思想如下:
阈值图像可隔离所需部分。请注意,某些轮廓的连接已断开。为了解决这个问题,我们将图像放大以连接斑点。
放大图像以形成奇异对象。现在请注意,我们在底部有不需要的水平部分,我们可以找到轮廓,然后使用区域进行过滤以删除该部分。
结果
import numpy as np
import cv2
original_image = cv2.imread("1.jpg")
image = original_image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
thresh = cv2.threshold(blurred, 160, 255, cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
dilate = cv2.dilate(thresh, kernel , iterations=4)
cv2.imshow("thresh", thresh)
cv2.imshow("dilate", dilate)
# Find contours in the image
cnts = cv2.findContours(dilate.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
contours = []
threshold_min_area = 400
threshold_max_area = 3000
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
area = cv2.contourArea(c)
if area > threshold_min_area and area < threshold_max_area:
# cv2.drawContours(original_image,[c], 0, (0,255,0), 3)
cv2.rectangle(original_image, (x,y), (x+w, y+h), (0,255,0),1)
contours.append(c)
cv2.imshow("detected", original_image)
print('contours detected: {}'.format(len(contours)))
cv2.waitKey(0)