diff --git a/.gitignore b/.gitignore index aba02a1..6aaf2ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +/test.py diff --git a/bim_im.png b/bim_im.png index c85ae8b..d6fc3f2 100644 Binary files a/bim_im.png and b/bim_im.png differ diff --git a/data_sub/test_1/data_sub_full.json b/data_sub/test_1/data_sub_full.json deleted file mode 100644 index 847e9ff..0000000 --- a/data_sub/test_1/data_sub_full.json +++ /dev/null @@ -1,202 +0,0 @@ -[ - { - "label": 0, - "prob": 0.9336103200912476, - "x": 325, - "y": 217, - "width": 68, - "height": 71 - }, - { - "label": 0, - "prob": 0.9302101731300354, - "x": 561, - "y": 222, - "width": 56, - "height": 66 - }, - { - "label": 0, - "prob": 0.9269363284111023, - "x": 440, - "y": 115, - "width": 54, - "height": 55 - }, - { - "label": 0, - "prob": 0.9259827136993408, - "x": 495, - "y": 269, - "width": 41, - "height": 42 - }, - { - "label": 0, - "prob": 0.915646493434906, - "x": 430, - "y": 321, - "width": 166, - "height": 38 - }, - { - "label": 0, - "prob": 0.9102611541748047, - "x": 276, - "y": 94, - "width": 43, - "height": 41 - }, - { - "label": 0, - "prob": 0.9072883129119873, - "x": 451, - "y": 220, - "width": 80, - "height": 38 - }, - { - "label": 0, - "prob": 0.9049834609031677, - "x": 179, - "y": 323, - "width": 183, - "height": 38 - }, - { - "label": 0, - "prob": 0.8983769416809082, - "x": 512, - "y": 102, - "width": 40, - "height": 41 - }, - { - "label": 0, - "prob": 0.8979458212852478, - "x": 71, - "y": 216, - "width": 67, - "height": 66 - }, - { - "label": 0, - "prob": 0.8557734489440918, - "x": 579, - "y": 157, - "width": 31, - "height": 34 - }, - { - "label": 0, - "prob": 0.8004537224769592, - "x": 201, - "y": 218, - "width": 87, - "height": 39 - }, - { - "label": 0, - "prob": 0.7972114682197571, - "x": 195, - "y": 110, - "width": 52, - "height": 55 - }, - { - "label": 0, - "prob": 0.7899783849716187, - "x": 350, - "y": 97, - "width": 43, - "height": 41 - }, - { - "label": 0, - "prob": 0.789060115814209, - "x": 34, - "y": 93, - "width": 42, - "height": 39 - }, - { - "label": 0, - "prob": 0.7720834612846375, - "x": 573, - "y": 107, - "width": 37, - "height": 40 - }, - { - "label": 0, - "prob": 0.753940761089325, - "x": 247, - "y": 267, - "width": 46, - "height": 45 - }, - { - "label": 0, - "prob": 0.7526902556419373, - "x": 304, - "y": 170, - "width": 36, - "height": 34 - }, - { - "label": 0, - "prob": 0.7418428063392639, - "x": 103, - "y": 142, - "width": 37, - "height": 35 - }, - { - "label": 0, - "prob": 0.7005344033241272, - "x": 53, - "y": 167, - "width": 36, - "height": 36 - }, - { - "label": 0, - "prob": 0.6595599055290222, - "x": 353, - "y": 146, - "width": 38, - "height": 37 - }, - { - "label": 0, - "prob": 0.6562734842300415, - "x": 103, - "y": 91, - "width": 45, - "height": 41 - }, - { - "label": 0, - "prob": 0.6161856651306152, - "x": 540, - "y": 175, - "width": 33, - "height": 36 - }, - { - "label": 0, - "prob": 0.07473669946193695, - "x": 122, - "y": 33, - "width": 314, - "height": 358 - }, - { - "label": 0, - "prob": 0.056293122470378876, - "x": 0, - "y": 216, - "width": 43, - "height": 37 - } -] \ No newline at end of file diff --git a/data_sub/test_2/data_sub.json b/data_sub/test_2/data_sub.json new file mode 100644 index 0000000..a3270a0 --- /dev/null +++ b/data_sub/test_2/data_sub.json @@ -0,0 +1,130 @@ +[ + { + "label": 0, + "prob": 0.9288522601127625, + "x": 212, + "y": 112, + "width": 54, + "height": 52 + }, + { + "label": 0, + "prob": 0.9224857687950134, + "x": 337, + "y": 215, + "width": 64, + "height": 65 + }, + { + "label": 0, + "prob": 0.9219771027565002, + "x": 289, + "y": 96, + "width": 40, + "height": 40 + }, + { + "label": 0, + "prob": 0.92093825340271, + "x": 94, + "y": 214, + "width": 68, + "height": 67 + }, + { + "label": 0, + "prob": 0.8973387479782104, + "x": 358, + "y": 96, + "width": 41, + "height": 40 + }, + { + "label": 0, + "prob": 0.8777830600738525, + "x": 217, + "y": 213, + "width": 88, + "height": 39 + }, + { + "label": 0, + "prob": 0.8754808902740479, + "x": 196, + "y": 314, + "width": 180, + "height": 39 + }, + { + "label": 0, + "prob": 0.8678174614906311, + "x": 262, + "y": 262, + "width": 45, + "height": 42 + }, + { + "label": 0, + "prob": 0.7945911288261414, + "x": 362, + "y": 147, + "width": 36, + "height": 35 + }, + { + "label": 0, + "prob": 0.7796808481216431, + "x": 0, + "y": 116, + "width": 38, + "height": 55 + }, + { + "label": 0, + "prob": 0.7364567518234253, + "x": 0, + "y": 216, + "width": 65, + "height": 36 + }, + { + "label": 0, + "prob": 0.5554796457290649, + "x": 48, + "y": 311, + "width": 87, + "height": 42 + }, + { + "label": 0, + "prob": 0.5389373898506165, + "x": 315, + "y": 168, + "width": 37, + "height": 36 + }, + { + "label": 0, + "prob": 0.38828131556510925, + "x": 55, + "y": 98, + "width": 43, + "height": 41 + }, + { + "label": 0, + "prob": 0.3368460536003113, + "x": 123, + "y": 98, + "width": 44, + "height": 39 + }, + { + "label": 0, + "prob": 0.07753150165081024, + "x": 74, + "y": 168, + "width": 40, + "height": 37 + } +] \ No newline at end of file diff --git a/data_sub/test_2/wide_image.png b/data_sub/test_2/wide_image.png new file mode 100644 index 0000000..342a553 Binary files /dev/null and b/data_sub/test_2/wide_image.png differ diff --git a/data_sub/test_3/return_objs_data.json b/data_sub/test_3/return_objs_data.json new file mode 100644 index 0000000..8b57942 --- /dev/null +++ b/data_sub/test_3/return_objs_data.json @@ -0,0 +1,90 @@ +[ + { + "label": 0, + "prob": 0.917050302028656, + "x": 189, + "y": 415, + "width": 196, + "height": 40 + }, + { + "label": 0, + "prob": 0.9155016541481018, + "x": 214, + "y": 212, + "width": 53, + "height": 48 + }, + { + "label": 0, + "prob": 0.9061460494995117, + "x": 338, + "y": 309, + "width": 68, + "height": 71 + }, + { + "label": 0, + "prob": 0.9045385122299194, + "x": 92, + "y": 309, + "width": 70, + "height": 69 + }, + { + "label": 0, + "prob": 0.8958920240402222, + "x": 262, + "y": 358, + "width": 46, + "height": 45 + }, + { + "label": 0, + "prob": 0.8823522329330444, + "x": 219, + "y": 311, + "width": 85, + "height": 37 + }, + { + "label": 0, + "prob": 0.8750882744789124, + "x": 289, + "y": 197, + "width": 39, + "height": 36 + }, + { + "label": 0, + "prob": 0.7151791453361511, + "x": 0, + "y": 212, + "width": 48, + "height": 48 + }, + { + "label": 0, + "prob": 0.569022536277771, + "x": 354, + "y": 198, + "width": 42, + "height": 36 + }, + { + "label": 0, + "prob": 0.4601861834526062, + "x": 314, + "y": 265, + "width": 36, + "height": 36 + }, + { + "label": 0, + "prob": 0.3012613356113434, + "x": 360, + "y": 244, + "width": 35, + "height": 33 + } +] \ No newline at end of file diff --git a/data_sub/test_3/wide_image.png b/data_sub/test_3/wide_image.png new file mode 100644 index 0000000..e1a54fb Binary files /dev/null and b/data_sub/test_3/wide_image.png differ diff --git a/search.py b/search.py index 5bb0e29..11d1a82 100644 --- a/search.py +++ b/search.py @@ -1,6 +1,6 @@ import cv2 -from utils import filter_points +from utils import filter_rectangle print(cv2.__version__) # 4.9.0 import json @@ -116,26 +116,30 @@ def cal_c1c2c3c4(param, heigt): def gen_im_from_params(params, type="lines"): # 依据bim数据生成bim图 - # type: line points - ## 计算bim图长和宽 - max_y = -999999 - max_y_idx = -1 - max_x = -999999 - max_x_idx = -1 + # type: # line points + ## 确定整个bim图的长度和宽度边界 + max_y = -999999 # y坐标最大值 + max_y_idx = -1 # y坐标最大值的索引 + max_x = -999999 # x坐标最大值 + max_x_idx = -1 # x坐标最大值的索引 + + # 遍历,找到矩形x坐标最大值和矩形y坐标最大值 for i, param in enumerate(params): + # x中心点坐标加上宽度的一半 = 当前矩形的x最大坐标 if param["x"] + param["w"] / 2 > max_x: + # 如果是最大的x坐标就更新 max_x = param["x"] + param["w"] / 2 max_x_idx = i + # y中心点坐标加上高度的一半 = 当前矩形的y最大坐标 if param["center"] + param["h"] / 2 > max_y: + # 如果是最大的y坐标就更新 max_y = param["center"] + param["h"] / 2 max_y_idx = i - ## 为了不贴边,x,y固定加 500 - FILL_VALUE = 0 - bim_width = int(max_x) - bim_height = int(max_y) - bim_width += FILL_VALUE - bim_height += FILL_VALUE - bim_channels = 1 + + padding_value = 0 # 内边距,避免整个bim图片贴着边缘展示 + bim_width = int(max_x) + padding_value + bim_height = int(max_y) + padding_value + bim_channels = 3 im = np.zeros((bim_height, bim_width, bim_channels), dtype=np.uint8) for i, param in enumerate(params): @@ -145,7 +149,7 @@ def gen_im_from_params(params, type="lines"): [param['x2'], param['y2']], [param['x3'], param['y3']], [param['x4'], param['y4']]]) - cv2.polylines(im, [pts], True, (255,0,0), 8) + cv2.polylines(im, [pts], True, (255,255,0), 8) elif type == "points": cv2.circle(im, (param['x1'], param['y1']), 1, 255, 20) cv2.circle(im, (param['x2'], param['y2']), 1, 255, 20) @@ -155,9 +159,31 @@ def gen_im_from_params(params, type="lines"): return im -def gen_points_from_params(params): + +""" +判断点是否在区域内部 + True 在 + False 不在 +如果没有提供区域,不做判断,返回True +""" +def is_inside_roi(point, roi_w, roi_h): + if (roi_w != None and roi_h != None): + x = point[0] + y = point[1] + if (x <= 0 or y <= 0 or y >= roi_h or x >= roi_w ): + # 不在区域内部 + return False + else: + # 在区域内部 + return True + else: + # 没有提供区域,不做判断,默认返回True + return True + + +def gen_points_from_params(params,roi_w=None,roi_h=None): # 依据bim数据生成bim图 - # type: line points + # type line points ## 计算bim图长和宽 max_y = -999999 max_y_idx = -1 @@ -170,19 +196,26 @@ def gen_points_from_params(params): if param["center"] + param["h"] / 2 > max_y: max_y = param["center"] + param["h"] / 2 max_y_idx = i - ## 为了不贴边,x,y固定加 500 bim_height = int(max_y) + points = [] - adjacency = [] # 邻接矩阵 for i, param in enumerate(params): - cal_c1c2c3c4(param, bim_height) - points.append([param['x1'], param['y1'], i]) - points.append([param['x2'], param['y2'], i]) - points.append([param['x3'], param['y3'], i]) - points.append([param['x4'], param['y4'], i]) - # points.append([param['x'], int((param['y3'] + param['y2']) / 2 )]) - points.append([param['x_center'], param['y_center'], i]) - # 过滤框框之外的点 + # 排序点 按照上左、上右、下右、下左的顺时针顺序 + if (roi_w == None and roi_h == None): + cal_c1c2c3c4(param, bim_height) + # 过滤点,把在roi区域之外的点全部过滤掉. + if(is_inside_roi([param['x1'], param['y1']], roi_w, roi_h)): + points.append([param['x1'], param['y1'], i]) + if(is_inside_roi([param['x2'], param['y2']], roi_w, roi_h)): + points.append([param['x2'], param['y2'], i]) + if(is_inside_roi([param['x3'], param['y3']], roi_w, roi_h)): + points.append([param['x3'], param['y3'], i]) + if(is_inside_roi([param['x4'], param['y4']], roi_w, roi_h)): + points.append([param['x4'], param['y4'], i]) + if(is_inside_roi([param['x_center'], param['y_center']], roi_w, roi_h)): + points.append([param['x_center'], param['y_center'], i]) + if (roi_w != None and roi_h != None): + print(f"[经区域过滤之后的点数一共为] ====== [{len(points)}]") return points def topological_similarity(adj1, adj2): @@ -302,19 +335,12 @@ if __name__ == "__main__": # _im_edge_sobel = _sobel(sub_zero) # _, _im_thresh = cv2.threshold(_im_edge_sobel, 5, 255, cv2.THRESH_BINARY) # cnts = _findContours(_im_thresh) - sub_im = cv2.imread("data_sub/test_1/wide_image.png") - sub_im2 = cv2.imread("data_sub/test_1/wide_image.png") + original_rectangle = read_from_json("data_sub/test_2/data_sub.json") + # 过滤矩形 + # cnts 过滤之后的矩形 + # sub_im 裁剪之后的图像 + cnts,sub_im = filter_rectangle("data_sub/test_2/wide_image.png", original_rectangle) sub_zero = np.zeros_like(sub_im) - cnts = read_from_json("data_sub/test_1/data_sub.json") - # cnts的矩形画在sub_im 上 - for i in range(len(cnts)): - p = cnts[i] - cv2.rectangle(sub_im2, (p['x'], p['y']), (p['x'] + p['width'], p['y'] + p['height']), (0, 0, 255), 2) - # 写编号 - cv2.putText(sub_im2, str(i), (p['x'], p['y']), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) - cv2.imshow("sub_im_before_filter", sub_im2) - # 过滤点 - cnts = filter_points("data_sub/test_1/wide_image.png",cnts) for contour in cnts: # x, y, w, h = cv2.boundingRect(contour) x = contour["x"] @@ -323,12 +349,12 @@ if __name__ == "__main__": h = contour["height"] # 由于定位框大小大于预埋件大小,因此这里需要做缩放处理 - k = int(h*0.01) # roi2 - k = int(h*0.01) # roi1 - x += k - y += k - w -= int(k) # - h -= int(k) # 2k + kh = int(h * 0.01) # roi1 + kw = int(w * 0.01) # roi1 + x += int(kw) + y += int(kh) + w -= int(kw) + h -= int(kh) param = {} param["x1"] = x param["y1"] = y @@ -403,7 +429,21 @@ if __name__ == "__main__": ## 1.3计算所有点到该预埋件左上点的,点个数,平均极半径 和 平均极角度 sum_r, sum_theta = 0.0,0 count = 0 - pts = gen_points_from_params(_sub_sort_params) + # 测试,画出所有的pts + # for i, p in enumerate(_sub_sort_params): + # # 画点 + # cv2.circle(sub_im, (p["x_center"], p["y_center"]), 2, (0, 255, 255), -1) + # cv2.imshow("_sub_sort_params", sub_im) + # cv2.waitKey(0) + pts = gen_points_from_params(_sub_sort_params,sub_roi_width,sub_roi_height) + # # 测试,画出所有的pts + for i, p in enumerate(pts): + # 画点 + cv2.circle(sub_im, (p[0], p[1]), 2, (0, 255, 255), -1) + # 写编号 + cv2.putText(sub_im, str(i), (p[0], p[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + cv2.imshow("sub_im_points", sub_im) + # cv2.waitKey(0) polar_list = [] for i, pt in enumerate(pts): r, theta = cartesian_to_polar(polar_origin_x, polar_origin_y, pt[0], pt[1]) @@ -414,6 +454,9 @@ if __name__ == "__main__": sum_r /= count * sub_roi_w_base_len sum_theta /= count print(count, sum_r, sum_theta) + print(f"[所有点到该预埋件左上点的个数] ====== [{count}]") + print(f"[所有点到该预埋件左上点的平均极半径] ====== [{sum_r}]") + print(f"[所有点到该预埋件左上点的平均极角] ====== [{sum_theta}]") # 初始化候选预埋件 candi_params = [] @@ -428,7 +471,6 @@ if __name__ == "__main__": bim_im = gen_im_from_params(data_bim["params"]) # sub_im = gen_im_from_params(data_sub["params"])# 需要读取 min_match_score = 999999 - times = 0 for i, param in enumerate(candi_params): tmp_roi_w_base_len = param['x2'] - param['x1'] scale = tmp_roi_w_base_len / sub_roi_w_base_len @@ -509,7 +551,7 @@ if __name__ == "__main__": print(f"起始预埋件ID:{id},置信度为:{score[0]},点数量:{score[1]},平均长度为:{score[2]},平均角度为:{score[3]}") print(f"match_sscore为:{match_score}") bim_im = cv2.rectangle(bim_im, param["start_point"], \ - param["end_point"], 255, 6) + param["end_point"], 100 * (i+1), 6) elapsed_time = time.time() - start_time print(f"Execution time: {elapsed_time:.4f} seconds") diff --git a/utils.py b/utils.py index a833601..9b82d3a 100644 --- a/utils.py +++ b/utils.py @@ -4,58 +4,92 @@ import logging import cv2 +""" +根据裁剪之后的图片,每个点的坐标需要重新计算,以新的图片的宽高作为坐标系 +""" +def re_cal_point(point,offset): + # 相当于所有的x坐标向左平移了offset个距离 + point['x'] = point['x'] - offset -def filter_points(image_path,points): - # 高度过大点过滤参数 + + +""" +过滤矩形 + 1 高度过大的不要 + 2 整个矩形全部身体都在裁剪区域之外的不要 + + 返回值: + 1 过滤之后的矩形 + 2 裁剪之后的图片 +""" +def filter_rectangle(image_path, points): + # 高度过大矩形过滤参数 max_height_rate = 0.5 # 矩形高度占整个画面高度的最大比例,如果超过该比例,则认为是无效矩形 - # x范围过滤,只保留中间部分的点,只保留矩形完整出现在在画面中间的那部分矩形。 - left_x_cut_rate=0.2 # 左边界的裁剪比例,从左边开始裁剪百分之多少 - right_x_cut_rate=0.2 # 右边界的裁剪比例,从右边开始裁剪百分之多少 + # 裁剪参数 + left_x_cut_rate=0.15 # 左边界的裁剪比例,从左边开始裁剪百分之多少 + right_x_cut_rate=0.15 # 右边界的裁剪比例,从右边开始裁剪百分之多少 image = cv2.imread(image_path) - image_height = image.shape[0] - image_width = image.shape[1] - image_x_min = image_width * left_x_cut_rate - image_x_max = image_width * (1 - right_x_cut_rate) + image_height = image.shape[0] # 获取图片高度 + image_width = image.shape[1] # 获取图片宽度 + image_x_min = int(image_width * left_x_cut_rate) # 左边界的裁剪点 + image_x_max = int(image_width * (1 - right_x_cut_rate)) # 右边界的裁剪点 - #开始过滤点 + #开始过滤矩形 bad_point_index = [] - print(f'开始过滤点,原有点数为{len(points)}') + print(f'开始过滤矩形,原有矩形数为{len(points)}') for index in range(len(points)): point = points[index] + # 高度过大过滤 if point['height'] > image_height * max_height_rate: bad_point_index.append(index) continue - - # x坐标范围过滤 - # 原point中的x和y,是矩形左上角的坐标 - x_min = point['x'] # 矩形四个点坐标中x的最小值 - x_max = point['x'] + point['width'] # 矩形四个点坐标中x的最大值 - - # 如果矩形x的最小值小于左边界,去除这个矩形 - if x_min < image_x_min: + # x坐标范围过滤,整个矩形全部身体都在裁剪区域之外的不要 + x_min = point['x'] # 矩形四个矩形坐标中x的最小值 + x_max = point['x'] + point['width'] # 矩形四个矩形坐标中x的最大值 + # 如果矩形x的 最大值 小于 左边界,去除这个矩形 + if x_max < image_x_min: bad_point_index.append(index) continue - # 如果矩形x的最大值大于右边界,去除这个矩形 - if x_max > image_x_max: + # 如果矩形x的 最小值 大于 右边界,去除这个矩形 + if x_min > image_x_max: bad_point_index.append(index) continue - # 删除bad_point_index + # 过滤,只保留有效矩形 filtered_points = [] for i, point in enumerate(points): + # 如果当前矩形的索引在bad_point_index中,则去除这个矩形 if i not in bad_point_index: + # 重新计算点的坐标 + re_cal_point(point,image_x_min) + # 塞入结果 filtered_points.append(point) - print(f'过滤点结束,过滤之后的点数为{len(filtered_points)}') - return filtered_points + print(f'过滤矩形结束,过滤之后的矩形数为{len(filtered_points)}') + + # 图片裁剪 + # 裁剪图片 (height方向不变,宽度方向裁剪) + cropped_image = image[:, image_x_min:image_x_max] + # 展示 + # cv2.imshow("cropped_image", cropped_image) + # cv2.imshow("image", image) + # for i in range(len(filtered_points)): + # p = filtered_points[i] + # cv2.rectangle(cropped_image, (p['x'], p['y']), (p['x'] + p['width'], p['y'] + p['height']), (0, 0, 255), 2) + # # 写编号 + # cv2.putText(cropped_image, str(i), (p['x'], p['y']), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) + # cv2.imshow("cropped_image_draw", cropped_image) + # cv2.waitKey(0) + return filtered_points, cropped_image +# 测试代码 # def read_from_json(file_path): # with open(file_path, 'r') as f: # loaded_array = json.load(f) # return loaded_array # cnts = read_from_json("data_sub/test_1/data_sub.json") -# filter_points("data_sub/test_1/wide_image.png",cnts) \ No newline at end of file +# filter_rectangle("data_sub/test_1/wide_image.png",cnts) \ No newline at end of file