如何从图像中裁剪出最大的矩形
image-processing
opencv
python
5
0

我在桌子上有几页纸的图像。我想从图像中裁剪页面。通常,页面将是图像中最大的矩形,但是,在某些情况下,矩形的所有四个边可能都不可见。

我正在执行以下操作,但未获得期望的结果:

import cv2
import numpy as np

im = cv2.imread('images/img5.jpg')
gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
_,contours,_ = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
areas = [cv2.contourArea(c) for c in contours]
max_index = np.argmax(areas)
cnt=contours[max_index]
x,y,w,h = cv2.boundingRect(cnt)
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow("Show",im)
cv2.imwrite("images/img5_rect.jpg", im)
cv2.waitKey(0)

以下是一些示例:

第一个示例 :我可以在此图像中找到矩形,但是,如果也可以裁剪出木材的其余部分,我想。 在此处输入图片说明

在此处输入图片说明

第二个示例 :在此图像中找不到矩形的正确尺寸。 在此处输入图片说明

在此处输入图片说明

第三个示例 :在此图像中也找不到正确的尺寸。 在此处输入图片说明 在此处输入图片说明

第四例 :与此相同。 在此处输入图片说明 在此处输入图片说明

参考资料:
Stack Overflow
收藏
评论
共 2 个回答
高赞 时间 活跃

正如我以前做过的类似事情一样,我经历了霍夫变换,但要比使用轮廓更难于适合我的情况。我有以下建议可帮助您入门:

  1. 通常,纸张(至少边缘)是白色的,因此,您可以通过进入YUV之类的颜色空间更好地分离光度来获得更好的运气:

     image_yuv = cv2.cvtColor(image,cv2.COLOR_BGR2YUV) image_y = np.zeros(image_yuv.shape[0:2],np.uint8) image_y[:,:] = image_yuv[:,:,0] 
  2. 纸上的文字有问题。使用模糊效果,以(希望)消除这些高频噪声。您也可以使用形态运算,例如膨胀。

     image_blurred = cv2.GaussianBlur(image_y,(3,3),0) 
  3. 您可以尝试应用精巧的边缘检测器,而不是简单的阈值。不一定,但可以帮助您:

      edges = cv2.Canny(image_blurred,100,300,apertureSize = 3) 
  4. 然后找到轮廓。就我而言,我只使用了极端的外部轮廓。您可以使用CHAIN_APPROX_SIMPLE标志来压缩轮廓

     contours,hierarchy = cv2.findContours(edges,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 
  5. 现在您应该有一堆轮廓。是时候找到合适的了。对于每个轮廓cnt ,首先找到凸包,然后使用approaxPolyDP尽可能简化轮廓。

     hull = cv2.convexHull(cnt) simplified_cnt = cv2.approxPolyDP(hull,0.001*cv2.arcLength(hull,True),True) 
  6. 现在,我们应该使用这个简化的轮廓来找到封闭的四边形。您可能会尝试很多规则。最简单的方法是选取轮廓的四个最长最长的线段,然后通过将这四条线相交来创建封闭的四边形。根据您的情况,您可以根据线条的对比度,它们形成的角度以及类似的东西找到这些线条。

  7. 现在您有一堆四边形。现在,您可以执行两步方法来找到所需的四边形。首先,您删除那些可能是错误的。例如,四边形的一个角度大于175度。然后,您可以选择面积最大的一个作为最终结果。您可以看到橙色轮廓是我此时得到的结果之一: 所有轮廓

  8. 找到(希望)右四边形之后的最后一步是变回矩形。为此,您可以使用findHomography提出转换矩阵。

     (H,mask) = cv2.findHomography(cnt.astype('single'),np.array([[[0., 0.]],[[2150., 0.]],[[2150., 2800.]],[[0.,2800.]]],dtype=np.single)) 

    数字假定投射到信纸上。您可能会想出更好更好的数字来使用。您还需要重新排列轮廓点以匹配信纸的坐标顺序。然后调用warpPerspective创建最终图像:

     final_image = cv2.warpPerspective(image,H,(2150, 2800)) 

    这种扭曲应导致如下所示(根据我之前的结果): 翘曲

我希望这可以帮助您找到适合您情况的方法。

收藏
评论

这是一个非常复杂的任务,仅通过搜索轮廓就无法解决。例如,《经济学人》封面只显示了杂志的1个边缘,可将图像分成两半。您的计算机应该如何知道杂志是哪一本和桌子是哪一本?因此,您必须为程序添加更多的智能。

您可能会在图像中寻找线条。例如霍夫变换。然后找到几组或多或少的平行线或正交线,一定长度的线...通过检查典型的打印颜色或通常在桌子上找不到的颜色来查找打印件。搜索印刷文本产生的高对比度频率...想象一下您作为人类如何识别印刷纸...

总而言之,这对于StackOverflow来说是一个太广泛的问题。尝试将其分解为较小的子问题,尝试解决它们,如果碰壁,请回到此处。

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号