fix: update point.py logic

This commit is contained in:
Yao Yi Zhe 2025-07-28 16:12:59 +08:00
parent 8d61f7f78c
commit 395dfec375
1 changed files with 92 additions and 22 deletions

View File

@ -28,13 +28,14 @@ def save_eroded(mask_color, out_path, kernel_size=(5, 5), erode_iter=10, dilate_
cv2.imwrite(out_path, morphed_bgr)
return morphed_bgr
def detect_circles(image_input, min_radius=50, max_radius=60, min_dist=200, param1=50, param2=17):
def detect_circles(image_input, bounding_box=None, min_radius=40, max_radius=100, min_dist=20, param1=50, param2=17):
"""
对给定的图像进行霍夫圆检测返回圆心坐标和半径
参数
----
image_input : 图像文件路径或图像数组
bounding_box: 可选(top_left, top_right, bottom_right, bottom_left) 形式的矩形框
"""
# 读取图像并转换为灰度图
if isinstance(image_input, str):
@ -46,6 +47,37 @@ def detect_circles(image_input, min_radius=50, max_radius=60, min_dist=200, para
# 如果是图像数组
image = cv2.cvtColor(image_input, cv2.COLOR_BGR2GRAY) if image_input.ndim == 3 else image_input.copy()
# 根据图像宽度动态调整max_radius
h, w = image.shape[:2]
if max(h, w) < 700:
max_radius = 60
min_radius = 30
# 如果提供了矩形框则只在框内去除左右10%)的区域检测
if bounding_box:
top_left, top_right, _, _ = bounding_box
x_min = top_left[0]
x_max = top_right[0]
box_width = x_max - x_min
# 计算要保留的区域
start_x = int(x_min + box_width * 0.1)
end_x = int(x_max - box_width * 0.1)
# 创建一个全黑的掩膜
mask = np.zeros_like(image)
# 将保留区域设为白色
mask[:, start_x:end_x] = 255
# 将原图与掩膜相乘,只保留目标区域
image = cv2.bitwise_and(image, mask)
else:
# 兼容旧逻辑屏蔽整张图的左右10%
w = image.shape[1]
image[:, :int(w * 0.05)] = 0
image[:, int(w * 0.9):] = 0
# 图像模糊处理,减少噪声
blurred = cv2.GaussianBlur(image, (9, 9), 2)
@ -57,9 +89,25 @@ def detect_circles(image_input, min_radius=50, max_radius=60, min_dist=200, para
# 如果检测到圆
if circles is not None:
# 将坐标和半径转换为整数并返回
circles = np.uint16(np.around(circles))
centers = [(c[0], c[1], c[2]) for c in circles[0]]
# 检查前两个圆心距离
if len(centers) >= 2:
x1, y1, _ = centers[0]
x2, y2, _ = centers[1]
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
dist = abs(x1 - x2) + abs(y1 - y2)
if dist <= 200:
# 增大max_radius并重新检测
new_max_radius = max_radius + 20
circles2 = cv2.HoughCircles(
blurred, cv2.HOUGH_GRADIENT, dp=1.2, minDist=min_dist,
param1=param1, param2=param2, minRadius=min_radius, maxRadius=new_max_radius
)
if circles2 is not None:
circles2 = np.uint16(np.around(circles2))
centers2 = [(c[0], c[1], c[2]) for c in circles2[0]]
return centers2
return centers # 返回 [(x1, y1, r1), (x2, y2, r2), ...]
else:
print("[Circle] 未检测到圆")
@ -247,9 +295,9 @@ def find_EFH(A, B, G, bottom_line):
return E, F, H
# ------------------------- 找 G 点 -------------------------
def find_G(image, line_info,
kernel_size=(7, 7),
erode_iter=10,
dilate_iter=11,
kernel_size=(3, 3),
erode_iter=3,
dilate_iter=3,
adj=3):
"""
侧视图汽车最高点 G沿直线从左到右或上到下找到遇到的第一个白色像素
@ -257,28 +305,32 @@ def find_G(image, line_info,
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 形态学处理(固定参数版本)
gray = apply_morphology(gray,
kernel_size=kernel_size,
erode_iter=erode_iter,
dilate_iter=dilate_iter)
# gray = apply_morphology(gray,
# kernel_size=kernel_size,
# erode_iter=erode_iter,
# dilate_iter=dilate_iter)
# 【调试】保存形态学处理后的图像,检查车顶是否被腐蚀
cv2.imwrite("debug_G_morphed_mask.png", gray)
if line_info[0] is None: # 垂直线 x = const
_, x, y1, y2 = line_info
for y in range(int(min(y1, y2)), int(max(y1, y2))):
if gray[y, int(x)] == 255:
if gray[y, int(x)] >= 150:
return int(x), y + adj
elif line_info[0] == 0: # 水平线 y = const
_, y, x1, x2 = line_info
for x in range(int(min(x1, x2)), int(max(x1, x2))):
if gray[int(y), x] == 255:
if gray[int(y), x] >= 150:
return x, int(y) + adj
else: # 斜率线 y = ax + b
a, b, x1, x2 = line_info
for x in range(int(x1), int(x2) + 1):
y = int(a * x + b)
if 0 <= y < gray.shape[0] and gray[y, x] == 255:
if 0 <= y < gray.shape[0] and gray[y, x] >= 150:
return x, y + adj
return None
@ -345,6 +397,14 @@ def find_bottom_gap_midpoint(mask_color, bottom_line, gap=20, direction='left'):
print(f"[find_bottom_gap_midpoint] direction={direction}, 左端点=({dy_list[left_idx][0]}, {dy_list[left_idx][1]}), 右端点=({dy_list[right_idx][0]}, {dy_list[right_idx][1]})")
return (int(dy_list[mid_idx][0]), int(dy_list[mid_idx][1]))
def preprocess_mask(mask_color, kernel_size=(3, 3), erode_iter=2, dilate_iter=2):
gray = cv2.cvtColor(mask_color, cv2.COLOR_BGR2GRAY)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)
eroded = cv2.erode(gray, kernel, iterations=erode_iter)
morphed = cv2.dilate(eroded, kernel, iterations=dilate_iter)
return cv2.cvtColor(morphed, cv2.COLOR_GRAY2BGR)
def process_side(mask_path, rgb_path, out_dir):
"""
处理侧视图检测并标注 A-H
@ -355,12 +415,17 @@ def process_side(mask_path, rgb_path, out_dir):
if mask_color is None or rgb_color is None:
raise FileNotFoundError("无法读取 mask 或 RGB 图像")
# 缩放图像到1000*600
# mask_color = resize_image(mask_color, (1000, 600))
# rgb_color = resize_image(rgb_color, (1000, 600))
# 先对mask做轻微腐蚀膨胀预处理
mask_color = preprocess_mask(mask_color, kernel_size=(3, 3), erode_iter=2, dilate_iter=2)
circles = detect_circles(mask_color)
# 1. 先获取外接矩形
top_left, top_right, bottom_right, bottom_left = get_bounding_box(mask_color)
# 2. 将矩形框传入霍夫圆检测,只在框内特定区域检测
bounding_box_coords = (top_left, top_right, bottom_right, bottom_left)
circles = detect_circles(mask_color, bounding_box=bounding_box_coords)
# 3. 计算边线
top_line, right_line, bottom_line, left_line = calculate_lines(
top_left, top_right, bottom_right, bottom_left
)
@ -371,6 +436,7 @@ def process_side(mask_path, rgb_path, out_dir):
E, F, H = find_EFH(A, B, G, bottom_line)
points = {'A': A, 'B': B, 'C': C, 'D': D, 'E': E, 'F': F, 'G': G, 'H': H}
# 用原始mask_color和rgb_color做可视化
for canvas in (mask_color, rgb_color):
draw_line_equation(canvas, top_line)
draw_line_equation(canvas, right_line)
@ -379,8 +445,12 @@ def process_side(mask_path, rgb_path, out_dir):
for label, pt in points.items():
if pt is not None:
cv2.circle(canvas, pt, 3, (0, 0, 255), -1)
cv2.putText(canvas, label, (pt[0]+5, pt[1]-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
if label == 'H':
cv2.putText(canvas, label, (pt[0]+5, pt[1]+20),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
else:
cv2.putText(canvas, label, (pt[0]+5, pt[1]-5),
cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
cv2.imwrite(os.path.join(out_dir, 'side_output_mask.png'), mask_color)
cv2.imwrite(os.path.join(out_dir, 'side_output_rgb.png'), rgb_color)
print("A =", A, " B =", B,"C =", C, " D =", D," G =", G , "E =", E ,"F =", F ,"H =", H )
@ -524,8 +594,8 @@ def process_front(mask_path, rgb_path, out_dir):
print(f"[front] 结果已保存到 {out_dir}")
if __name__ == '__main__':
side_mask = '../segment-anything-main/output/2_mask.png'
side_rgb = '../ultralytics-main/input/2.png'
side_mask = '../segment-anything-main/output/5_mask.png'
side_rgb = '../ultralytics-main/input/5.jpg'
front_mask = '../segment-anything-main/output/00213_mask.png'
front_rgb = '../ultralytics-main/input/00213.jpg'
@ -536,5 +606,5 @@ if __name__ == '__main__':
out_dir = './result'
process_side(side_mask, side_rgb, out_dir)
process_front(front_mask, front_rgb, out_dir)
process_rear(rear_mask, rear_rgb, out_dir)
# process_front(front_mask, front_rgb, out_dir)
# process_rear(rear_mask, rear_rgb, out_dir)