This commit is contained in:
leon 2025-02-28 15:15:33 +08:00
parent 60985d84bc
commit 304d9422e3
9 changed files with 370 additions and 275 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
.idea/
/test.py

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -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
}
]

View File

@ -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
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 KiB

View File

@ -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
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

138
search.py
View File

@ -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
## 为了不贴边xy固定加 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
## 为了不贴边xy固定加 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")

View File

@ -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)
# filter_rectangle("data_sub/test_1/wide_image.png",cnts)