diff --git a/main/point.py b/main/point.py index 0794ad4..c5a676d 100644 --- a/main/point.py +++ b/main/point.py @@ -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)