地物分类项目代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
11KB

  1. import os
  2. import cv2
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. from rdp_alg import rdp
  6. from cal_dist_ang import cal_ang, cal_dist, azimuthAngle
  7. from rotate_ang import Nrotation_angle_get_coor_coordinates, Srotation_angle_get_coor_coordinates
  8. from line_intersection import line, intersection, par_line_dist, point_in_line
  9. def boundary_regularization(img, epsilon=6):
  10. h, w = img.shape[0:2]
  11. # 轮廓定位
  12. contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 检索所有轮廓
  13. # contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 只检索最外面的轮廓
  14. contours = np.squeeze(contours[0]) # [[x1,y1], [x2, y2],...]
  15. # print("line17", contours)
  16. # 轮廓精简(DP)
  17. contours = rdp(contours, epsilon=epsilon)
  18. # print("line20", contours[:, 1], h) # [ 409, 415, 539, 573, 610], 27710
  19. contours[:, 1] = h - contours[:, 1]
  20. # 轮廓规则化
  21. dists = []
  22. azis = []
  23. azis_index = []
  24. # 获取每条边的长度和方位角
  25. for i in range(contours.shape[0]):
  26. cur_index = i
  27. next_index = i+1 if i < contours.shape[0]-1 else 0
  28. prev_index = i-1
  29. cur_point = contours[cur_index]
  30. nest_point = contours[next_index]
  31. prev_point = contours[prev_index]
  32. dist = cal_dist(cur_point, nest_point) # 当前点到下一个点的距离
  33. azi = azimuthAngle(cur_point, nest_point) # 计算线条的方位角,线条的方位角是线条的逆时针方向与水平方向的夹角
  34. dists.append(dist)
  35. azis.append(azi)
  36. azis_index.append([cur_index, next_index])
  37. # 以最长的边的方向作为主方向
  38. longest_edge_idex = np.argmax(dists)
  39. main_direction = azis[longest_edge_idex] # 主方向与水平线在逆时针方向上的夹角
  40. # 方向纠正,绕中心点旋转到与主方向垂直或者平行
  41. correct_points = []
  42. para_vetr_idxs = [] # 0平行 1垂直
  43. for i, (azi, (point_0_index, point_1_index)) in enumerate(zip(azis, azis_index)):
  44. if i == longest_edge_idex:
  45. correct_points.append([contours[point_0_index], contours[point_1_index]])
  46. para_vetr_idxs.append(0)
  47. else:
  48. # 确定旋转角度
  49. rotate_ang = main_direction - azi
  50. if np.abs(rotate_ang) < 180/4:
  51. rotate_ang = rotate_ang
  52. para_vetr_idxs.append(0)
  53. elif np.abs(rotate_ang) >= 90-180/4:
  54. rotate_ang = rotate_ang + 90
  55. para_vetr_idxs.append(1)
  56. # 执行旋转任务
  57. point_0 = contours[point_0_index] # 当前点
  58. point_1 = contours[point_1_index] # 当前点的下一个点
  59. point_middle = (point_0 + point_1) / 2
  60. if rotate_ang > 0:
  61. rotate_point_0 = Srotation_angle_get_coor_coordinates(point_0, point_middle, np.abs(rotate_ang))
  62. rotate_point_1 = Srotation_angle_get_coor_coordinates(point_1, point_middle, np.abs(rotate_ang))
  63. elif rotate_ang < 0:
  64. rotate_point_0 = Nrotation_angle_get_coor_coordinates(point_0, point_middle, np.abs(rotate_ang))
  65. rotate_point_1 = Nrotation_angle_get_coor_coordinates(point_1, point_middle, np.abs(rotate_ang))
  66. else:
  67. rotate_point_0 = point_0
  68. rotate_point_1 = point_1
  69. correct_points.append([rotate_point_0, rotate_point_1])
  70. correct_points = np.array(correct_points)
  71. # 相邻边校正,垂直取交点,平行平移短边或者加线
  72. final_points = []
  73. final_points.append(correct_points[0][0])
  74. for i in range(correct_points.shape[0]-1):
  75. cur_index = i
  76. next_index = i + 1 if i < correct_points.shape[0] - 1 else 0
  77. cur_edge_point_0 = correct_points[cur_index][0]
  78. cur_edge_point_1 = correct_points[cur_index][1]
  79. next_edge_point_0 = correct_points[next_index][0]
  80. next_edge_point_1 = correct_points[next_index][1]
  81. cur_para_vetr_idx = para_vetr_idxs[cur_index]
  82. next_para_vetr_idx = para_vetr_idxs[next_index]
  83. if cur_para_vetr_idx != next_para_vetr_idx:
  84. # 垂直取交点
  85. L1 = line(cur_edge_point_0, cur_edge_point_1)
  86. L2 = line(next_edge_point_0, next_edge_point_1)
  87. point_intersection = intersection(L1, L2) # 交点
  88. final_points.append(point_intersection)
  89. elif cur_para_vetr_idx == next_para_vetr_idx:
  90. # 平行分两种,一种加短线,一种平移,取决于距离阈值
  91. L1 = line(cur_edge_point_0, cur_edge_point_1)
  92. L2 = line(next_edge_point_0, next_edge_point_1)
  93. marg = par_line_dist(L1, L2) # 两个平行线之间的距离
  94. if marg < 3:
  95. # 平移
  96. point_move = point_in_line(next_edge_point_0[0], next_edge_point_0[1], cur_edge_point_0[0], cur_edge_point_0[1], cur_edge_point_1[0], cur_edge_point_1[1])
  97. final_points.append(point_move)
  98. # 更新平移之后的下一条边
  99. correct_points[next_index][0] = point_move
  100. correct_points[next_index][1] = point_in_line(next_edge_point_1[0], next_edge_point_1[1], cur_edge_point_0[0], cur_edge_point_0[1], cur_edge_point_1[0], cur_edge_point_1[1])
  101. else:
  102. # 加线
  103. add_mid_point = (cur_edge_point_1 + next_edge_point_0) / 2
  104. add_point_1 = point_in_line(add_mid_point[0], add_mid_point[1], cur_edge_point_0[0], cur_edge_point_0[1], cur_edge_point_1[0], cur_edge_point_1[1])
  105. add_point_2 = point_in_line(add_mid_point[0], add_mid_point[1], next_edge_point_0[0], next_edge_point_0[1], next_edge_point_1[0], next_edge_point_1[1])
  106. final_points.append(add_point_1)
  107. final_points.append(add_point_2)
  108. final_points.append(final_points[0])
  109. final_points = np.array(final_points)
  110. final_points[:, 1] = h - final_points[:, 1]
  111. return final_points
  112. imgPath = "./input"
  113. imgList = os.listdir(imgPath)
  114. for i in range(len(imgList)):
  115. img = cv2.imread(imgPath + os.sep + imgList[i]) # 读取彩色的分割图像
  116. imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  117. imgDB = imgGray.copy()
  118. imgDB[imgDB == 38] = 0 # 删除建筑物 filterBuilding.png
  119. # imgDB = cv2.cvtColor(imgDB, cv2.COLOR_BGR2GRAY)
  120. imgGray[imgGray != 38] = 0
  121. ori_img1 = cv2.cvtColor(imgGray, cv2.COLOR_GRAY2BGR) # rgb值相同的24位图像
  122. h, w = ori_img1.shape[0], ori_img1.shape[1]
  123. # 中值滤波,去噪
  124. ori_img = cv2.medianBlur(ori_img1, 5) # 滤波核大小为5
  125. ori_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
  126. ret, ori_img = cv2.threshold(ori_img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
  127. # 连通域分析
  128. num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(ori_img, connectivity=8) # 参数8表示8连通。返回值:所有连通域的数目,图像上每一像素的标记,每一个标记的统计信息,连通域的中心点
  129. # 遍历连通域
  130. allCnt = []
  131. for i in range(1, num_labels):
  132. img = np.zeros_like(labels)
  133. index = np.where(labels == i)
  134. img[index] = 255
  135. img = np.array(img, dtype=np.uint8)
  136. regularization_contour = boundary_regularization(img).astype(np.int32)
  137. # cv2.polylines(img=ori_img1, pts=[regularization_contour], isClosed=True, color=(255, 0, 0), thickness=5) # 原始
  138. # print("line153", type(regularization_contour)) # [[999, 666], [222, 111],... ]
  139. # single_out = np.zeros_like(ori_img1)
  140. # cv2.polylines(img=single_out, pts=[regularization_contour], isClosed=True, color=(255, 0, 0), thickness=5)
  141. # cv2.imwrite('./middle/' + 'single_out_{}.jpg'.format(i), single_out)
  142. rows = regularization_contour.shape[0]
  143. regularization_contour = regularization_contour.reshape(rows, 1, 2)
  144. regularization_contour = regularization_contour.astype(int)
  145. allCnt.append(regularization_contour)
  146. # print("line162", regularization_contour)
  147. # print("line162", regularization_contour.shape)
  148. buildingMask = np.zeros((h, w), dtype='uint8')
  149. cv2.fillPoly(buildingMask, allCnt, color=38)
  150. img2 = buildingMask.copy()
  151. cv2.imwrite("./output/building.png", img2)
  152. buildingMask[buildingMask == 0] = 255
  153. buildingMask[buildingMask == 38] = 0 # step2.png
  154. img3 = cv2.bitwise_and(imgDB, imgDB, mask=buildingMask) # 在去掉建筑物区域的图像中,再去掉“优化后的建筑物”边界范围内的区域
  155. finalResult = cv2.bitwise_or(img2, img3)
  156. cv2.imwrite('./output/finalResult.png', finalResult)
  157. # imgPath = "./input"
  158. # imgList = os.listdir(imgPath)
  159. # for i in range(len(imgList)):
  160. # img = cv2.imread(imgPath + os.sep + imgList[i]) # 读取彩色的分割图像
  161. # imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  162. # img = cv2.cvtColor(imgGray, cv2.COLOR_GRAY2BGR) # rgb值相同的24位图像
  163. #
  164. #
  165. # ori_img1 = cv2.imread('./input/1.png')
  166. # h, w = ori_img1.shape[0], ori_img1.shape[1]
  167. # # 中值滤波,去噪
  168. # ori_img = cv2.medianBlur(ori_img1, 5)
  169. # ori_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2GRAY)
  170. # ret, ori_img = cv2.threshold(ori_img, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
  171. #
  172. # # 连通域分析
  173. # num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(ori_img, connectivity=8)
  174. #
  175. #
  176. # # 遍历联通域
  177. # allCnt = []
  178. # for i in range(1, num_labels):
  179. # img = np.zeros_like(labels)
  180. # index = np.where(labels==i)
  181. # img[index] = 255
  182. # img = np.array(img, dtype=np.uint8)
  183. #
  184. # regularization_contour = boundary_regularization(img).astype(np.int32)
  185. # # cv2.polylines(img=ori_img1, pts=[regularization_contour], isClosed=True, color=(255, 0, 0), thickness=5) # 原始
  186. # # print("line153", type(regularization_contour)) # [[999, 666], [222, 111],... ]
  187. #
  188. # # single_out = np.zeros_like(ori_img1)
  189. # # cv2.polylines(img=single_out, pts=[regularization_contour], isClosed=True, color=(255, 0, 0), thickness=5)
  190. # # cv2.imwrite('./middle/' + 'single_out_{}.jpg'.format(i), single_out)
  191. #
  192. # rows = regularization_contour.shape[0]
  193. # regularization_contour = regularization_contour.reshape(rows, 1, 2)
  194. # regularization_contour = regularization_contour.astype(int)
  195. # allCnt.append(regularization_contour)
  196. # # print("line162", regularization_contour)
  197. # # print("line162", regularization_contour.shape)
  198. #
  199. # mask = np.zeros((h, w), dtype='uint8')
  200. # cv2.fillPoly(mask, allCnt, color=38)
  201. # cv2.imwrite("./output/new.png", mask)
  202. #
  203. # # cv2.imwrite('./output/result.png', ori_img1)