如何从imag中裁剪出最大的矩形

2024-04-25 23:08:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我桌上有几张纸的图片。我想把这张照片的页数剪下来。通常,页面将是图像中最大的矩形,但是,在某些情况下,矩形的所有四条边可能都不可见。

我正在做以下工作,但没有得到理想的结果:

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)

下面是几个例子:

第一个例子:我可以在这个图像中找到矩形,但是,如果木材的剩余部分也可以裁剪出来的话。 enter image description here

enter image description here

第二个示例:未在此图像中找到矩形的正确尺寸。 enter image description here

enter image description here

第三个示例:在此图像中也找不到正确的尺寸。 enter image description hereenter image description here

第四个示例:与此相同。 enter image description hereenter image description here


Tags: 图像import示例npcv2maxjpgimages
2条回答

正如我以前做过类似的事情一样,我也经历过hough变换,但它们比使用等高线更难适合我的情况。我有以下建议可以帮助您开始:

  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 flag压缩轮廓

    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度。然后你可以选择面积最大的那一个作为最终结果。你可以看到橙色轮廓是我在这一点上得到的结果之一: All Contours

  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))
    

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

我希望这能帮助你找到适合你的方法。

这是一个相当复杂的任务,不能简单地通过搜索轮廓来解决。例如,《经济学人》的封面只显示了杂志的一个边缘,将图像分成两半。你的电脑怎么知道哪个是杂志,哪个是桌子?所以你必须给你的程序增加更多的智能。

你可以在图像中寻找线条。例如Hough变换。然后找到一组或多或少平行或正交的线,一定长度的线。。。 通过检查典型的印刷颜色或通常在桌子上找不到的颜色来找到印刷品。搜索由打印文本创建的高对比度频率。。。 想象一下你作为一个人类是如何认出一张印刷纸的。。。

总之,对于StackOverflow来说,这是一个太宽泛的问题。试着把它分解成更小的子问题,试着解决它们,如果你碰壁了,就回来这里。

相关问题 更多 >