改編自詳解利用OpenCV提取圖像中的矩形區(qū)域(PPT屏幕等) 原文是c++版,我改成了python版,供大家參考學習。
主要思想:邊緣檢測—》輪廓檢測—》找出最大的面積的輪廓—》找出頂點—》投影變換
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
import numpy as np import cv2 # 這個成功的扣下了ppt白板 srcPic = cv2.imread( '2345.jpg' ) length = srcPic.shape[ 0 ] depth = srcPic.shape[ 1 ] polyPic = srcPic shrinkedPic = srcPic greyPic = cv2.cvtColor(shrinkedPic, cv2.COLOR_BGR2GRAY) ret, binPic = cv2.threshold(greyPic, 130 , 255 , cv2.THRESH_BINARY) print (binPic.shape) median = cv2.medianBlur(binPic, 5 ) # 進行邊緣檢測 cannyPic = cv2.Canny(median, 10 , 200 ) cv2.namedWindow( "binary" , 0 ) cv2.namedWindow( "binary2" , 0 ) cv2.imshow( "binary" , cannyPic) # 找出輪廓 contours, hierarchy = cv2.findContours(cannyPic, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) cv2.imwrite( 'binary2.png' , cannyPic) cv2.imshow( "binary2" , cannyPic) i = 0 maxArea = 0 # 挨個檢查看那個輪廓面積最大 for i in range ( len (contours)): if cv2.contourArea(contours[i]) > cv2.contourArea(contours[maxArea]): maxArea = i #檢查輪廓得到分布在四個角上的點 hull = cv2.convexHull(contours[maxArea]) s = [[ 1 , 2 ]] z = [[ 2 , 3 ]] for i in hull: s.append([i[ 0 ][ 0 ],i[ 0 ][ 1 ]]) z.append([i[ 0 ][ 0 ],i[ 0 ][ 1 ]]) del s[ 0 ] del z[ 0 ] #現(xiàn)在的目標是從一堆點中挑出分布在四個角落的點,決定把圖片分為四等份,每個區(qū)域的角度來劃分點, #默認四個角分別分布在圖像的四等分的區(qū)間上,也就是矩形在圖像中央 # 我們把所有點的坐標,都減去圖片中央的那個點(當成原點),然后按照x y坐標值的正負 判斷屬于哪一個區(qū)間 center = [length / 2 ,depth / 2 ] # 可以得到小數(shù) for i in range ( len (s)): s[i][ 0 ] = s[i][ 0 ] - center[ 0 ] s[i][ 1 ] = s[i][ 1 ] - center[ 1 ] one = [] two = [] three = [] four = [] # 判斷是那個區(qū)間的 for i in range ( len (z)): if s[i][ 0 ] < = 0 and s[i][ 1 ] < 0 : one.append(i) elif s[i][ 0 ] > 0 and s[i][ 1 ] < 0 : two.append(i) elif s[i][ 0 ] > = 0 and s[i][ 1 ] > 0 : four.append(i) else :three.append(i) p = [] distance = 0 temp = 0 # 下面開始判斷每個區(qū)間的極值,要選擇距離中心點最遠的點,就是角點 for i in one : x = z[i][ 0 ] - center[ 0 ] y = z[i][ 1 ] - center[ 1 ] d = x * x + y * y if d > distance : temp = i distance = d p.append([z[temp][ 0 ],z[temp][ 1 ]]) distance = 0 temp = 0 for i in two : x = z[i][ 0 ] - center[ 0 ] y = z[i][ 1 ] - center[ 1 ] d = x * x + y * y if d > distance : temp = i distance = d p.append([z[temp][ 0 ],z[temp][ 1 ]]) distance = 0 temp = 0 for i in three : x = z[i][ 0 ] - center[ 0 ] y = z[i][ 1 ] - center[ 1 ] d = x * x + y * y if d > distance : temp = i distance = d p.append([z[temp][ 0 ],z[temp][ 1 ]]) distance = 0 temp = 0 for i in four : x = z[i][ 0 ] - center[ 0 ] y = z[i][ 1 ] - center[ 1 ] d = x * x + y * y if d > distance : temp = i distance = d p.append([z[temp][ 0 ],z[temp][ 1 ]]) for i in p: cv2.circle(polyPic, (i[ 0 ],i[ 1 ]), 2 ,( 0 , 255 , 0 ), 2 ) # 給四個點排一下順序 a = [] b = [] st = [] for i in p: a.append(i[ 0 ]) b.append(i[ 1 ]) index = np.lexsort((b, a)) for i in index: st.append(p[i]) p = st print (p) pts1 = np.float32([[p[ 0 ][ 0 ],p[ 0 ][ 1 ]],[p[ 1 ][ 0 ],p[ 1 ][ 1 ]],[p[ 2 ][ 0 ],p[ 2 ][ 1 ]],[p[ 3 ][ 0 ],p[ 3 ][ 1 ]]]) # dst=np.float32([[0,0],[0,srcPic.shape[1]],[srcPic.shape[0],0],[srcPic.shape[0],srcPic.shape[1]]]) dst = np.float32([[ 0 , 0 ],[ 0 , 600 ],[ 400 , 0 ],[ 400 , 600 ]]) # 投影變換 M = cv2.getPerspectiveTransform(pts1,dst) cv2.namedWindow( "srcPic2" , 0 ) cv2.imshow( "srcPic2" , srcPic) #dstImage = cv2.warpPerspective(srcPic,M,(srcPic.shape[0],srcPic.shape[1])) dstImage = cv2.warpPerspective(srcPic,M,( 400 , 600 )) # 在原圖上畫出紅色的檢測痕跡,先生成一個黑色圖 black = np.zeros((shrinkedPic.shape[ 0 ], shrinkedPic.shape[ 1 ]), dtype = np.uint8) # 二值圖轉(zhuǎn)為三通道圖 black3 = cv2.merge([black, black, black]) # black=black2 cv2.drawContours(black, contours, maxArea, 255 , 11 ) cv2.drawContours(black3, contours, maxArea, ( 255 , 0 , 0 ), 11 ) cv2.imwrite( 'cv.png' , black) cv2.namedWindow( "cannyPic" , 0 ) cv2.imshow( "cannyPic" , black) cv2.namedWindow( "shrinkedPic" , 0 ) cv2.imshow( "shrinkedPic" , polyPic) cv2.namedWindow( "dstImage" , 0 ) cv2.imshow( "dstImage" , dstImage) # 等待一個按下鍵盤事件 cv2.waitKey( 0 ) # 銷毀所有創(chuàng)建出的窗口 |
運行效果
用到的圖片
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/c19961227/article/details/90693098