利用python进行图像角点探测

前言

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

一、轮廓探测

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

1
2
3
4
5
6
7
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,我使用了尖锐度检测的方式求得角点。原理通俗一点就是通过相邻几个点构成的向量计算其半角正弦值,结合近似原则进行近似计算。下面是我的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# =============================================================================
# 点类
# =============================================================================
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)

三、效果展示


由效果来看,程序很好的识别出四个角点,这个时候我们就探测出了该轮廓的四个顶点。

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 前言
  2. 2. 一、轮廓探测
  3. 3. 二、角点探测
  4. 4. 三、效果展示
,