利用python进行纸质文档识别(二)轮廓角点探测

前言

上次我们发现,只要找到了矩形的四个角点,进行旋转变换后就能够很完美的得到一个横平竖直的矩形。那如何得到四个角点呢?现在比较常见的方式是通过canny算子去探测角点,但是由于角点众多,其实canny算子并不适合表格类型的角点探测。还有一种是通过hough圆变换得到所有直线,然后计算最外围轮廓直线的交点得到角点,但同样的,也因为表格类型的直线较多,且容易在二值化的时候丢失线段,所以处理效果也比较差。
这里介绍另外一种方式去探测角点,先确定最大轮廓,然后在这个轮廓里寻找四个角点。

一、轮廓探测

轮廓探测比较轻松,opencv里有现成的函数cv2.findContours(),但是要注意输入图像只能二值图像。所以我们需要一定的预处理。下面是我预处理和轮廓探测的代码:

	gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 彩色图像转为灰度图像
    highthreshold,banary_img= cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY|cv2.THRESH_OTSU )  
	# 利用自适应阀值转化为二值图像
	# 参数参考http://blog.csdn.net/on2way/article/details/46812121
    #cv2.findContours()
    contours = cv2.findContours(banary_img,cv2.RETR_LIST,cv2.CHAIN_APPROX_TC89_L1)
    #将探测到的所有轮廓赋值给contours,方法是不压缩轮廓点,方便下面寻找

二、角点探测

角点探测比较麻烦,通过几篇论文和一位大佬的blog,我使用了尖锐度检测的方式求得角点。原理通俗一点就是通过相邻几个点构成的向量计算其半角正弦值,结合近似原则进行近似计算。下面是我的实现。

# =============================================================================
# 点类
# =============================================================================
class Point:
    def __init__(self, point):
        # x1, y1, x2, y2 = l # 前两个数为起点,后两个数为终点
        self.x = point[0]
        self.y = point[1]
        
    def copy(self):
        return self
    
    def toList(self):
        #将点类转化为list类型
        return [int (self.x),int(self.y)]
    
    def lenth(self):
        return 1.*(self.x*self.x+self.y*self.y)**0.5
    
    def measureAngle(self,lastPoint,nextPoint):
        #计算尖锐度,参考 https://www.cnblogs.com/jsxyhelu/p/5106760.html
        vect1=[self.x-lastPoint.x,self.y-lastPoint.y]
        
        vect2=[self.x-nextPoint.x,self.y-nextPoint.y]
        
        vect3=[lastPoint.x-nextPoint.x,lastPoint.y-nextPoint.y]
        
        sin=1.0*Point(vect3).lenth()/(Point(vect1).lenth()+Point(vect2).lenth())
        return 1-sin
    
    def printf(self):
        print((self.x,self.y))
        
# =============================================================================
# 轮廓类
# =============================================================================
class Contour(Point):
    def __init__(self,contour):
        self.contour=[]
        for p in contour:
            self.contour.append(Point(p[0]))
        self.length=len(contour)
      
    def pickLeftPoint(self,currentLocation,setp):
        #防止取左边相邻点时越界
            if currentLocation-setp<0:
                #print(currentLocation-setp+self.length)
                return currentLocation-setp+self.length
            else:
                #print(currentLocation-setp)
                return currentLocation-setp
        
    def pickRightPoint(self,currentLocation,setp):
        #防止取右边相邻点时越界
            if currentLocation+setp>self.length-1:
                #print(currentLocation+setp-self.length+1)
                return currentLocation+setp-self.length+1
            else:
                #print(currentLocation+setp)
                return currentLocation+setp
    
    def getAngle(self,p,setp):
        #print(p)
        return self.contour[p].measureAngle(self.contour[self.pickRightPoint(p,setp)],
                                       self.contour[self.pickLeftPoint(p,setp)])
        
def sortPoint(rowdata):
    x=0
    y=0
    for p in rowdata:
        x=p.x+x
        y=p.y+y
    x=x/4
    y=y/4
    sorteddata=[[0,0]]*4
    for p in rowdata:
        if p.x<x and p.y<y:
            sorteddata[0]=p.toList()
        if p.x>x and p.y<y:
            sorteddata[1]=p.toList()
        if p.x>x and p.y>y:
            sorteddata[2]=p.toList()
        if p.x<x and p.y>y:
            sorteddata[3]=p.toList()
    return sorteddata
    
def getPoint(contours):
    index=0
    contour = contours[1]
    j=0
    size=0
    for i in contour:
        if i.size>size:
            size=i.size
            index=j
        j=j+1    
    maxContour=Contour(contour[index])
    data=[]
    datas=[]
    for p in range(0,maxContour.length-1):
         y=maxContour.getAngle(p,5)
         datas.append(y)
         if   0.1 < y :
             data.append(maxContour.contour[p])
    plt.plot(datas)
    plt.show()    
	
if __name__ == '__main__':
	old_img = cv2.imread('1.jpg')
    t_points = img_process(old_img)
    

三、效果展示

利用python进行纸质文档识别(二)轮廓角点探测_第1张图片
由效果来看,程序很好的识别出四个角点,这个时候我们就探测出了该轮廓的四个顶点。

你可能感兴趣的:(Python,opencv,角点探测)