Opencv和python获取文档正确的轮廓并在图像上绘制

Posted

技术标签:

【中文标题】Opencv和python获取文档正确的轮廓并在图像上绘制【英文标题】:Opencv and python get document correct contur and draw on image 【发布时间】:2020-05-08 14:18:50 【问题描述】:

这里使用opencv和python是document conture的输出

我使用的是opencv_python-4.2.0.34,左下角不像其他角那样锐利。如何使它正确? (自动编辑左下角以使其看起来清晰,尽可能远离其他人)

这里是绘制轮廓的代码:

img = cv2.imread(imagePath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
invGamma = 1.0 / 0.3
table = np.array([((i / 255.0) ** invGamma) * 255
                  for i in np.arange(0, 256)]).astype("uint8")

# apply gamma correction using the lookup table
gray = cv2.LUT(gray, table)

ret, thresh1 = cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY)

contours, hierachy = cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# except:
#     print('exception occurred')

def biggestRectangle(conts):
    biggest = None
    max_area = 0
    indexReturn = -1
    for index in range(len(conts)):
        i = conts[index]
        area = cv2.contourArea(i)
        if area > 100:
            peri = cv2.arcLength(i, True)
            approx = cv2.approxPolyDP(i, 0.1 * peri, True)
            if area > max_area and len(approx) == 4:
                biggest = approx
                max_area = area
                indexReturn = index
    return indexReturn

indexReturn = biggestRectangle(contours)
hull = cv2.convexHull(contours[indexReturn])

print(indexReturn)
print(contours[indexReturn])
print(hull)

# copyImg = img.copy()

cv2.imwrite(os.path.join('path_to_save', imageName),
            cv2.drawContours(img, [hull], 0, (0, 255, 0), 3))

如何使它正确。我尝试了另一种方法:

x, y, w, h = cv2.boundingRect(hull)

    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
    newImageName = imageName.split('.')
    newImageName = newImageName[0] + '_rect.' + newImageName[1]
    print(newImageName)
    cv2.imwrite(os.path.join('path_to_save', newImageName), img)

但它给了我这个(蓝色轮廓):

这也是错误的。如何纠正?

【问题讨论】:

你所说的锐利是什么意思?如果可以,请更具体;附上所需轮廓的基本事实。 我看到你构建了一个convex_hull,只需在遍历hull 时,避开具有大角度的连续点并进行插值,这可能只会给你尖角。 应该怎么做呢?请提供代码示例 【参考方案1】:

既然你知道你感兴趣的轮廓是一张纸,也许你可以使用更系统的方法来使用OpenCV的cv2.minAreaRect(link)找到最大的旋转矩形。它将返回最紧密地包围您的轮廓的矩形的中心、大小和旋转。由于您的图像具有相当困难的背景,因此在抓取轮廓之前,我必须使用OpenCV's morphologyEx function 应用更多处理步骤,但这段代码我可以看到更好的输出(如下所示)。

# first, do some processing
kernel1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (27, 27))
kernel2 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13, 13))
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_ERODE, kernel1)
thresh1 = cv2.morphologyEx(thresh1, cv2.MORPH_DILATE, kernel2)

# find all contours
contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_LIST, 
                                       cv2.CHAIN_APPROX_SIMPLE)
# Find the largest ('max' using the key of the contour area)
biggest_contour = max(contours, key=cv2.contourArea)

# Calculate the minimum enclosing rectangle: format ((x, y), (length, width), angle)
rectangle = cv2.minAreaRect(biggest_contour)

# conver the minAreaRect output to points
pts = cv2.boxPoints(rectangle)
# contours must be of shape (n, 1, 2) and dtype integer
pts = pts.reshape(-1, 1, 2)
pts = pts.astype(int)

# draw contours and display
cv2.drawContours(img, [pts], -1, (255, 0, 0), 2)
cv2.imshow('img', img)
k = cv2.waitKey(0)    

输出:

【讨论】:

有什么办法可以改善吗? Quadrilateral 的手臂不需要像前一个那样平行。其实我只需要修复弯曲的形状。所以从 x2,y2 到左边和从 x1,y1 到底部,我不想使用那样的线,然后我将使用四点变换(这将取决于 conture)来变换图像。 (我有转换的代码) 如果你能得到一个更好的图像,不包括你的手覆盖图像的一部分,那将有助于得到更好的矩形 我只想画一个四边形,哪边可能不平行,但是有尖角,可以吗? 不幸的是,据我所知,OpenCV 没有允许您使用固定点数的轮廓来近似轮廓的功能。唯一的选择是使用您在问题中显示的approxPolyDP

以上是关于Opencv和python获取文档正确的轮廓并在图像上绘制的主要内容,如果未能解决你的问题,请参考以下文章

opencv中的重复轮廓

获取轮廓Opencv Python内的区域?

OpenCV在轮廓边界内获取黑色像素

Python-OpenCV中的图像轮廓检测

使用 OpenCV (Python) 改进轮廓检测

在 Python 中使用 OpenCV 访问轮廓边界内的像素值