Image processing 照片中纸张角点的检测算法

Image processing 照片中纸张角点的检测算法,image-processing,opencv,edge-detection,hough-transform,image-segmentation,Image Processing,Opencv,Edge Detection,Hough Transform,Image Segmentation,检测照片中发票/收据/纸张角落的最佳方法是什么?这将用于OCR之前的后续透视校正 我目前的做法是: RGB>灰度>带阈值的Canny边缘检测>放大(1)>移除小对象(6)>清除边界对象>基于凸面区域拾取大对象博客。>[角点检测-未实施] 我忍不住认为,必须有一种更强大的“智能”或统计方法来处理这种类型的细分。我没有太多的训练例子,但我可能会得到100张图片 更广泛的背景: 我正在使用matlab进行原型设计,并计划在OpenCV和OCR中实现该系统。这是我需要为这个特定应用解决的许多图像处理问题

检测照片中发票/收据/纸张角落的最佳方法是什么?这将用于OCR之前的后续透视校正

我目前的做法是: RGB>灰度>带阈值的Canny边缘检测>放大(1)>移除小对象(6)>清除边界对象>基于凸面区域拾取大对象博客。>[角点检测-未实施]

我忍不住认为,必须有一种更强大的“智能”或统计方法来处理这种类型的细分。我没有太多的训练例子,但我可能会得到100张图片

更广泛的背景: 我正在使用matlab进行原型设计,并计划在OpenCV和OCR中实现该系统。这是我需要为这个特定应用解决的许多图像处理问题中的第一个。因此,我希望推出自己的解决方案,重新熟悉图像处理算法

下面是一些我希望算法能够处理的示例图像:如果你想接受挑战,大图像就在这里


(来源:)


(来源:)


(来源:)


(来源:)

最好的情况是:
(来源:)


(来源:)


(来源:)

但是,在其他情况下,它很容易失败:
(来源:)


(来源:)


(来源:)

提前感谢所有伟大的想法!我爱死你了

编辑:Hough变换进度 Q:用什么算法对hough线进行聚类以找到角点? 根据答案中的建议,我能够使用Hough变换、拾取线并过滤它们。我目前的做法相当粗糙。我假设发票与图像的偏差始终小于15度。如果是这样的话,我最终得到了行的合理结果(见下文)。但我并不完全确定是否有合适的算法来对线条进行聚类(或投票)以推断角点。霍夫线不是连续的。在噪声图像中,可能存在平行线,因此需要某种形式或距离线原点的度量。有什么想法吗



(来源:)

我所在大学的一个学生小组最近演示了一个iPhone应用程序(和python OpenCV应用程序),他们就是为了实现这一点而编写的。我记得,步骤是这样的:

  • 中值滤波器完全去除纸张上的文本(这是白纸上的手写文本,光线相当好,可能无法处理打印文本,效果非常好)。原因是它使角点检测更加容易
  • 直线的Hough变换
  • 在Hough变换累加器空间中找到峰值,并在整个图像上绘制每条线
  • 分析管路并移除彼此非常接近且角度相似的管路(将管路组合成一个)。这是必要的,因为Hough变换不是完美的,因为它在离散样本空间中工作
  • 找到大致平行且与其他线对相交的线对,以查看哪些线形成四边形

这似乎工作得相当好,他们能够拍摄一张纸或一本书的照片,执行角点检测,然后几乎实时地将图像中的文档映射到平面上(只有一个OpenCV函数来执行映射)。当我看到它工作时,没有OCR。

边缘检测后,使用Hough变换。
然后,将这些点与它们的标签一起放在支持向量机(SVM)中,如果示例上有平滑的线条,SVM将不会有任何困难来划分示例的必要部分和其他部分。我对支持向量机的建议是,输入连通性和长度等参数。也就是说,若这些点相互连接且很长,那个么它们很可能是一条收据行。然后,您可以消除所有其他点

我是马丁的朋友,今年早些时候在做这个。这是我的第一个编码项目,结束时有点匆忙,所以代码需要一些错误…解码。。。 我将从您已经在做的事情中给出一些提示,然后在明天休息时对我的代码进行排序

第一个提示,
OpenCV
python
非常棒,请尽快使用它们:D

与其移除小对象或噪声,不如降低canny约束,使其接受更多边,然后找到最大的闭合轮廓(在OpenCV中使用
findcontour()
和一些简单参数,我想我使用了
CV\u RETR\u LIST
)。当它出现在一张白纸上时,它可能仍在挣扎,但肯定提供了最好的结果

对于
Houghline2()
变换,尝试使用
CV_-HOUGH_标准
而不是
CV_-HOUGH_概率
,它将给出rho和theta值,在极坐标中定义直线,然后您可以将直线分组在特定公差范围内

我的分组作为一个查找表,对于从hough变换输出的每一行,它将给出一个ρ和θ对。如果这些值在表中一对值的5%以内,则丢弃这些值;如果这些值在该5%之外,则向表中添加一个新条目

然后,您可以更轻松地分析平行线或线之间的距离


希望这有帮助。

您可以使用角点检测,而不是从边缘检测开始

为此目的提供了Moravec算法的实现。你可以找到报纸的角落作为起点。下面是Moravec算法的输出:


以下是我经过一点实验后得出的结论:

import cv, cv2, numpy as np
import sys

def get_new(old):
    new = np.ones(old.shape, np.uint8)
    cv2.bitwise_not(new,new)
    return new

if __name__ == '__main__':
    orig = cv2.imread(sys.argv[1])

    # these constants are carefully picked
    MORPH = 9
    CANNY = 84
    HOUGH = 25

    img = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)
    cv2.GaussianBlur(img, (3,3), 0, img)


    # this is to recognize white on white
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(MORPH,MORPH))
    dilated = cv2.dilate(img, kernel)

    edges = cv2.Canny(dilated, 0, CANNY, apertureSize=3)

    lines = cv2.HoughLinesP(edges, 1,  3.14/180, HOUGH)
    for line in lines[0]:
         cv2.line(edges, (line[0], line[1]), (line[2], line[3]),
                         (255,0,0), 2, 8)

    # finding contours
    contours, _ = cv2.findContours(edges.copy(), cv.CV_RETR_EXTERNAL,
                                   cv.CV_CHAIN_APPROX_TC89_KCOS)
    contours = filter(lambda cont: cv2.arcLength(cont, False) > 100, contours)
    contours = filter(lambda cont: cv2.contourArea(cont) > 10000, contours)

    # simplify contours down to polygons
    rects = []
    for cont in contours:
        rect = cv2.approxPolyDP(cont, 40, True).copy().reshape(-1, 2)
        rects.append(rect)

    # that's basically it
    cv2.drawContours(orig, rects,-1,(0,255,0),1)

    # show only contours
    new = get_new(img)
    cv2.drawContours(new, rects,-1,(0,255,0),1)
    cv2.GaussianBlur(new, (9,9), 0, new)
    new = cv2.Canny(new, 0, CANNY, apertureSize=3)

    cv2.namedWindow('result', cv2.WINDOW_NORMAL)
    cv2.imshow('result', orig)
    cv2.waitKey(0)
    cv2.imshow('result', dilated)
    cv2.waitKey(0)
    cv2.imshow('result', edges)
    cv2.waitKey(0)
    cv2.imshow('result', new)
    cv2.waitKey(0)

    cv2.destroyAllWindows()
不完美,但至少适用于所有样品:


这里有@Vanuan使用C++编写的代码:

cv::cvt颜色(垫、垫、cv_bgr2灰色);
cv::GaussianBlur(mat,mat,cv::Size(3,3),0);
cv::Mat kernel=cv::getStructuringE