python 图像变化检测_霍夫变换检测图像直线算法python实现

创作不易,如果对您有帮助,帮忙点赞哦!

一. 霍夫变换理解:

二. 霍夫变换简介:

霍夫变换,是将坐标由直角坐标系变换到极坐标系,然后再根据数学表达式检测某些形状(如直线和圆)的方法。当 l1直线 上的某些点变换到极坐标系下时,表现为某些线(和前面点数量一致),这些线交于一点,通过该点的坐标就能表示原先的 l1直线。

三. 霍夫变换用于检测图像直线算法实现:

① 提取图像边缘(可使用Canny算法等)[我也实现了它,前面Canny算法有问题可以参考我的另一篇文章:https://www.cnblogs.com/wojianxin/p/12533526.html]

② 实现二值图像霍夫变换

1. 求出图像对角线长:r_max

2. 在边缘点 (x,y) 处,t 取[0,180),步长设为1,根据下式进行霍夫变换

霍夫变换,(r_ho,t) 表示极坐标,(x,y) 表示直角坐标 ↑

3. 做一个大小为 r_max * 180 的表,变换后一个值落在表内某坐标,就将该坐标表内值 + 1,简言之,就是在进行投票,统计通过哪个点的直线的数量最多(即在原图像上越趋近于一条直线)。

③ 进行非极大值抑制(NMS)操作,使找出的直线落在不同的地点

NMS 的算法如下:

1. 遍历该表,如果遍历到的像素的投票数大于其8近邻的像素投票值,则它不变。

2. 如果遍历到的像素的投票数小于其8近邻的像素投票值,则将其设置为0。

④ 找到20个投票数最多的点(即:直角坐标系下20条直线)准备进行输出

1. np.ravel   将多维数组降为1维

2. np.argsort   将数组元素从小到大排序,返回索引值

3. [::-1]   数组反序 -> 得到从大到小索引值

4. [:20]   前20个最大投票值的索引

5. 根据索引得到坐标(r,t)

⑤ 霍夫反变换后,画出原图中的20条直线,输出图像

霍夫逆变换公式 ↑

四. 纯手工实现 ——> 利用霍夫变换检测图像中的直线

1 importcv22 importnumpy as np3 importmatplotlib.pyplot as plt4

5 #Canny算法:提取图像边缘

6 defCanny(img):7

8 #Gray scale

9 defBGR2GRAY(img):10 b =img[:, :, 0].copy()11 g = img[:, :, 1].copy()12 r = img[:, :, 2].copy()13

14 #Gray scale

15 out = 0.2126 * r + 0.7152 * g + 0.0722 *b16 out =out.astype(np.uint8)17

18 returnout19

20

21 #Gaussian filter for grayscale

22 def gaussian_filter(img, K_size=3, sigma=1.3):23

24 if len(img.shape) == 3:25 H, W, C =img.shape26 gray =False27 else:28 img = np.expand_dims(img, axis=-1)29 H, W, C =img.shape30 gray =True31

32 ## Zero padding

33 pad = K_size // 2

34 out = np.zeros([H + pad * 2, W + pad * 2, C], dtype=np.float)35 out[pad : pad + H, pad : pad + W] =img.copy().astype(np.float)36

37 ## prepare Kernel

38 K = np.zeros((K_size, K_size), dtype=np.float)39 for x in range(-pad, -pad +K_size):40 for y in range(-pad, -pad +K_size):41 K[y + pad, x + pad] = np.exp( - (x ** 2 + y ** 2) / (2 * sigma *sigma))42 #K /= (sigma * np.sqrt(2 * np.pi))

43 K /= (2 * np.pi * sigma *sigma)44 K /=K.sum()45

46 tmp =out.copy()47

48 #filtering

49 for y inrange(H):50 for x inrange(W):51 for c inrange(C):52 out[pad + y, pad + x, c] = np.sum(K * tmp[y : y + K_size, x : x +K_size, c])53

54 out = np.clip(out, 0, 255)55 out = out[pad : pad + H, pad : pad +W]56 out =out.astype(np.uint8)57

58 ifgray:59 out =out[..., 0]60

61 returnout62

63

64 #sobel filter

65 def sobel_filter(img, K_size=3):66 if len(img.shape) == 3:67 H, W, C =img.shape68 else:69 H, W =img.shape70

71 #Zero padding

72 pad = K_size // 2

73 out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)74 out[pad : pad + H, pad : pad + W] =img.copy().astype(np.float)75 tmp =out.copy()76

77 out_v =out.copy()78 out_h =out.copy()79

80 ## Sobel vertical

81 Kv = [[1., 2., 1.],[0., 0., 0.], [-1., -2., -1.]]82 ## Sobel horizontal

83 Kh = [[1., 0., -1.],[2., 0., -2.],[1., 0., -1.]]84

85 #filtering

86 for y inrange(H):87 for x inrange(W):88 out_v[pad + y, pad + x] = np.sum(Kv * (tmp[y : y + K_size, x : x +K_size]))89 out_h[pad + y, pad + x] = np.sum(Kh * (tmp[y : y + K_size, x : x +K_size]))90

91 out_v = np.clip(out_v, 0, 255)92 out_h = np.clip(out_h, 0, 255)93

94 out_v = out_v[pad : pad + H, pad : pad +W]95 out_v =out_v.astype(np.uint8)96 out_h = out_h[pad : pad + H, pad : pad +W]97 out_h =out_h.astype(np.uint8)98

99 returnout_v, out_h100

101

102 defget_edge_angle(fx, fy):103 #get edge strength

104 edge = np.sqrt(np.power(fx.astype(np.float32), 2) + np.power(fy.astype(np.float32), 2))105 edge = np.clip(edge, 0, 255)106

107 fx = np.maximum(fx, 1e-10)108 #fx[np.abs(fx) <= 1e-5] = 1e-5

109

110 #get edge angle

111 angle = np.arctan(fy /fx)112

113 returnedge, angle114

115

116 defangle_quantization(angle):117 angle = angle / np.pi * 180

118 angle[angle < -22.5] = 180 + angle[angle < -22.5]119 _angle = np.zeros_like(angle, dtype=np.uint8)120 _angle[np.where(angle <= 22.5)] =0121 _angle[np.where((angle > 22.5) & (angle <= 67.5))] = 45

122 _angle[np.where((angle > 67.5) & (angle <= 112.5))] = 90

123 _angle[np.where((angle > 112.5) & (angle <= 157.5))] = 135

124

125 return_angle126

127

128 defnon_maximum_suppression(angle, edge):129 H, W =angle.shape130 _edge =edge.copy()131

132 for y inrange(H):133 for x inrange(W):134 if angle[y, x] ==0:135 dx1, dy1, dx2, dy2 = -1, 0, 1, 0136 elif angle[y, x] == 45:137 dx1, dy1, dx2, dy2 = -1, 1, 1, -1

138 elif angle[y, x] == 90:139 dx1, dy1, dx2, dy2 = 0, -1, 0, 1

140 elif angle[y, x] == 135:141 dx1, dy1, dx2, dy2 = -1, -1, 1, 1

142 if x ==0:143 dx1 =max(dx1, 0)144 dx2 =max(dx2, 0)145 if x == W-1:146 dx1 =min(dx1, 0)147 dx2 =min(dx2, 0)148 if y ==0:149 dy1 =max(dy1, 0)150 dy2 =max(dy2, 0)151 if y == H-1:152 dy1 =min(dy1, 0)153 dy2 =min(dy2, 0)154 if max(max(edge[y, x], edge[y + dy1, x + dx1]), edge[y + dy2, x + dx2]) !=edge[y, x]:155 _edge[y, x] =0156

157 return_edge158

159 def hysterisis(edge, HT=100, LT=30):160 H, W =edge.shape161

162 #Histeresis threshold

163 edge[edge >= HT] = 255

164 edge[edge <= LT] =0165

166 _edge = np.zeros((H + 2, W + 2), dtype=np.float32)167 _edge[1 : H + 1, 1 : W + 1] =edge168

169 ## 8 - Nearest neighbor

170 nn = np.array(((1., 1., 1.), (1., 0., 1.), (1., 1., 1.)), dtype=np.float32)171

172 for y in range(1, H+2):173 for x in range(1, W+2):174 if _edge[y, x] < LT or _edge[y, x] >HT:175 continue

176 if np.max(_edge[y-1:y+2, x-1:x+2] * nn) >=HT:177 _edge[y, x] = 255

178 else:179 _edge[y, x] =0180

181 edge = _edge[1:H+1, 1:W+1]182

183 returnedge184

185 #grayscale

186 gray =BGR2GRAY(img)187

188 #gaussian filtering

189 gaussian = gaussian_filter(gray, K_size=5, sigma=1.4)190

191 #sobel filtering

192 fy, fx = sobel_filter(gaussian, K_size=3)193

194 #get edge strength, angle

195 edge, angle =get_edge_angle(fx, fy)196

197 #angle quantization

198 angle =angle_quantization(angle)199

200 #non maximum suppression

201 edge =non_maximum_suppression(angle, edge)202

203 #hysterisis threshold

204 out = hysterisis(edge, 100, 30)205

206 returnout207

208 #霍夫变换实现检测图像中的20条直线

209 defHough_Line(edge, img):210 ## Voting

211 defvoting(edge):212 H, W =edge.shape213

214 drho = 1

215 dtheta = 1

216

217 #get rho max length

218 rho_max = np.ceil(np.sqrt(H ** 2 + W ** 2)).astype(np.int)219

220 #hough table

221 hough = np.zeros((rho_max, 180), dtype=np.int)222

223 #get index of edge

224 #ind[0] 是 符合条件的纵坐标,ind[1]是符合条件的横坐标

225 ind = np.where(edge == 255)226

227 ## hough transformation

228 #zip函数返回元组

229 for y, x in zip(ind[0], ind[1]):230 for theta in range(0, 180, dtheta):231 #get polar coordinat4s

232 t = np.pi / 180 *theta233 rho = int(x * np.cos(t) + y *np.sin(t))234

235 #vote

236 hough[rho, theta] += 1

237

238 out =hough.astype(np.uint8)239

240 returnout241

242 #non maximum suppression

243 defnon_maximum_suppression(hough):244 rho_max, _ =hough.shape245

246 ## non maximum suppression

247 for y inrange(rho_max):248 for x in range(180):249 #get 8 nearest neighbor

250 x1 = max(x-1, 0)251 x2 = min(x+2, 180)252 y1 = max(y-1, 0)253 y2 = min(y+2, rho_max-1)254 if np.max(hough[y1:y2, x1:x2]) == hough[y,x] and hough[y, x] !=0:255 pass

256 #hough[y,x] = 255

257 else:258 hough[y,x] =0259

260 returnhough261

262 definverse_hough(hough, img):263 H, W, _=img.shape264 rho_max, _ =hough.shape265

266 out =img.copy()267

268 #get x, y index of hough table

269 #np.ravel 将多维数组降为1维

270 #argsort 将数组元素从小到大排序,返回索引

271 #[::-1] 反序->从大到小

272 #[:20] 前20个

273 ind_x = np.argsort(hough.ravel())[::-1][:20]274 ind_y =ind_x.copy()275 thetas = ind_x % 180

276 rhos = ind_y // 180

277

278 #each theta and rho

279 for theta, rho inzip(thetas, rhos):280 #theta[radian] -> angle[degree]

281 t = np.pi / 180. *theta282

283 #hough -> (x,y)

284 for x inrange(W):285 if np.sin(t) !=0:286 y = - (np.cos(t) / np.sin(t)) * x + (rho) /np.sin(t)287 y =int(y)288 if y >= H or y <0:289 continue

290 out[y, x] = [0,255,255]291 for y inrange(H):292 if np.cos(t) !=0:293 x = - (np.sin(t) / np.cos(t)) * y + (rho) /np.cos(t)294 x =int(x)295 if x >= W or x <0:296 continue

297 out[y, x] = [0,0,255]298

299 out =out.astype(np.uint8)300

301 returnout302

303

304 #voting

305 hough =voting(edge)306

307 #non maximum suppression

308 hough =non_maximum_suppression(hough)309

310 #inverse hough

311 out =inverse_hough(hough, img)312

313 returnout314

315

316 #Read image

317 img = cv2.imread("../paojie.jpg").astype(np.float32)318

319 #Canny

320 edge =Canny(img)321

322 #Hough

323 out =Hough_Line(edge, img)324

325 out =out.astype(np.uint8)326

327 #Save result

328 cv2.imwrite("out.jpg", out)329 cv2.imshow("result", out)330 cv2.waitKey(0)331 cv2.destroyAllWindows()

View Code

五. 实验结果:

原图 ↑

霍夫变换检测到的直线 ↑

六. 参考内容:

七. 版权声明:

未经作者允许,请勿随意转载抄袭,抄袭情节严重者,作者将考虑追究其法律责任,创作不易,感谢您的理解和配合!

你可能感兴趣的:(python,图像变化检测)