Merge branch 'main' of ssh://120.27.199.238:222/Havoc420mac/mi-task into main
This commit is contained in:
commit
1d0ca47e3b
57
logs/robot_2025-05-19.log
Normal file
57
logs/robot_2025-05-19.log
Normal file
@ -0,0 +1,57 @@
|
||||
2025-05-19 20:41:09 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_204109_537087.jpg
|
||||
2025-05-19 20:41:09 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_204109_537087', 'edge_point': (397, 816), 'distance_to_center': -563, 'slope': 0.0, 'distance_to_bottom': 264.0, 'intersection_point': (960, 816), 'is_truncated': False}
|
||||
2025-05-19 20:44:06 | DEBUG | utils.log_helper - 🐞 步骤1: 原始图像已加载
|
||||
2025-05-19 20:44:07 | DEBUG | utils.log_helper - 🐞 步骤2: 创建黄色掩码
|
||||
2025-05-19 20:44:08 | DEBUG | utils.log_helper - 🐞 步骤3: 提取黄色部分
|
||||
2025-05-19 20:44:09 | DEBUG | utils.log_helper - 🐞 检测底部和顶部边缘点
|
||||
2025-05-19 20:44:10 | DEBUG | utils.log_helper - 🐞 步骤4: 边缘检测
|
||||
2025-05-19 20:44:11 | DEBUG | utils.log_helper - 🐞 步骤5: 检测到 15 条直线
|
||||
2025-05-19 20:44:12 | DEBUG | utils.log_helper - 🐞 步骤6: 找到 13 条水平线
|
||||
2025-05-19 20:44:13 | DEBUG | utils.log_helper - 👁️ 步骤7: 找到边缘点 (397, 816)
|
||||
2025-05-19 20:44:14 | DEBUG | utils.log_helper - 🐞 显示边缘斜率和中线交点
|
||||
2025-05-19 20:44:15 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_204415_945888.jpg
|
||||
2025-05-19 20:44:15 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_204415_945888', 'edge_point': (397, 816), 'distance_to_center': -563, 'slope': 0.0, 'distance_to_bottom': 264.0, 'intersection_point': (960, 816), 'is_truncated': False}
|
||||
2025-05-19 20:44:57 | DEBUG | utils.log_helper - 🐞 步骤1: 原始图像已加载
|
||||
2025-05-19 20:44:58 | DEBUG | utils.log_helper - 🐞 步骤2: 创建黄色掩码
|
||||
2025-05-19 20:44:59 | DEBUG | utils.log_helper - 🐞 步骤3: 提取黄色部分
|
||||
2025-05-19 20:45:00 | DEBUG | utils.log_helper - 🐞 检测底部和顶部边缘点
|
||||
2025-05-19 20:45:01 | DEBUG | utils.log_helper - 🐞 步骤4: 边缘检测
|
||||
2025-05-19 20:45:02 | DEBUG | utils.log_helper - 🐞 步骤5: 检测到 10 条直线
|
||||
2025-05-19 20:45:03 | DEBUG | utils.log_helper - 🐞 步骤6: 找到 8 条水平线
|
||||
2025-05-19 20:45:04 | DEBUG | utils.log_helper - 👁️ 步骤7: 找到边缘点 (831, 971)
|
||||
2025-05-19 20:45:05 | DEBUG | utils.log_helper - 🐞 显示边缘斜率和中线交点
|
||||
2025-05-19 20:45:06 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_204506_674753.jpg
|
||||
2025-05-19 20:45:06 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_204506_674753', 'edge_point': (831, 971), 'distance_to_center': -129, 'slope': -0.07004830917874397, 'distance_to_bottom': 118.036231884058, 'intersection_point': (960, 961), 'is_truncated': False}
|
||||
2025-05-19 20:45:37 | DEBUG | utils.log_helper - 🐞 步骤1: 原始图像已加载
|
||||
2025-05-19 20:45:39 | DEBUG | utils.log_helper - 🐞 步骤2: 创建黄色掩码
|
||||
2025-05-19 20:45:40 | DEBUG | utils.log_helper - 🐞 步骤3: 提取黄色部分
|
||||
2025-05-19 20:45:41 | DEBUG | utils.log_helper - 🐞 检测底部和顶部边缘点
|
||||
2025-05-19 20:45:42 | DEBUG | utils.log_helper - 🐞 步骤4: 边缘检测
|
||||
2025-05-19 20:45:43 | DEBUG | utils.log_helper - 🐞 步骤5: 检测到 17 条直线
|
||||
2025-05-19 20:45:44 | DEBUG | utils.log_helper - 🐞 步骤6: 找到 12 条水平线
|
||||
2025-05-19 20:45:45 | DEBUG | utils.log_helper - 👁️ 步骤7: 找到边缘点 (923, 849)
|
||||
2025-05-19 20:45:46 | DEBUG | utils.log_helper - 🐞 显示边缘斜率和中线交点
|
||||
2025-05-19 20:45:47 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_204547_188654.jpg
|
||||
2025-05-19 20:45:47 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_204547_188654', 'edge_point': (923, 849), 'distance_to_center': -37, 'slope': 0.0, 'distance_to_bottom': 231.0, 'intersection_point': (960, 849), 'is_truncated': False}
|
||||
2025-05-19 20:47:53 | DEBUG | utils.log_helper - 🐞 步骤1: 原始图像已加载
|
||||
2025-05-19 20:47:55 | DEBUG | utils.log_helper - 🐞 步骤2: 创建黄色掩码
|
||||
2025-05-19 20:47:56 | DEBUG | utils.log_helper - 🐞 步骤3: 提取黄色部分
|
||||
2025-05-19 20:47:57 | DEBUG | utils.log_helper - 🐞 检测底部和顶部边缘点
|
||||
2025-05-19 20:47:58 | DEBUG | utils.log_helper - 🐞 步骤4: 边缘检测
|
||||
2025-05-19 20:47:59 | DEBUG | utils.log_helper - 🐞 步骤5: 检测到 17 条直线
|
||||
2025-05-19 20:48:00 | DEBUG | utils.log_helper - 🐞 步骤6: 找到 12 条水平线
|
||||
2025-05-19 20:48:01 | DEBUG | utils.log_helper - 👁️ 步骤7: 找到边缘点 (923, 849)
|
||||
2025-05-19 20:48:02 | DEBUG | utils.log_helper - 🐞 显示边缘斜率和中线交点
|
||||
2025-05-19 20:48:03 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_204803_276122.jpg
|
||||
2025-05-19 20:48:03 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_204803_276122', 'edge_point': (923, 849), 'distance_to_center': -37, 'slope': 0.0, 'distance_to_bottom': 231.0, 'intersection_point': (960, 849), 'is_truncated': False}
|
||||
2025-05-19 20:50:32 | DEBUG | utils.log_helper - 🐞 步骤1: 原始图像已加载
|
||||
2025-05-19 20:50:33 | DEBUG | utils.log_helper - 🐞 步骤2: 创建黄色掩码
|
||||
2025-05-19 20:50:34 | DEBUG | utils.log_helper - 🐞 步骤3: 提取黄色部分
|
||||
2025-05-19 20:50:35 | DEBUG | utils.log_helper - 🐞 检测底部和顶部边缘点
|
||||
2025-05-19 20:50:36 | DEBUG | utils.log_helper - 🐞 步骤4: 边缘检测
|
||||
2025-05-19 20:50:37 | DEBUG | utils.log_helper - 🐞 步骤5: 检测到 25 条直线
|
||||
2025-05-19 20:50:38 | DEBUG | utils.log_helper - 🐞 步骤6: 找到 18 条水平线
|
||||
2025-05-19 20:50:39 | DEBUG | utils.log_helper - 👁️ 步骤7: 找到边缘点 (92, 1077)
|
||||
2025-05-19 20:50:40 | DEBUG | utils.log_helper - 🐞 显示边缘斜率和中线交点
|
||||
2025-05-19 20:50:41 | INFO | utils.log_helper - ℹ️ 保存横向边缘检测结果图像到: logs/image/horizontal_edge_20250519_205041_583040.jpg
|
||||
2025-05-19 20:50:41 | INFO | utils.log_helper - ℹ️ 横向边缘检测结果: {'timestamp': '20250519_205041_583040', 'edge_point': (92, 1077), 'distance_to_center': -868, 'slope': -0.07008086253369272, 'distance_to_bottom': 63.83018867924534, 'intersection_point': (960, 1016), 'is_truncated': False}
|
BIN
res/path/test-1.jpg
Normal file
BIN
res/path/test-1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
@ -44,7 +44,7 @@ def process_image(image_path, save_dir=None, show_steps=False):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='黄色赛道检测演示程序')
|
||||
parser.add_argument('--input', type=str, default='res/path/image_20250514_024313.png', help='输入图像或视频的路径')
|
||||
parser.add_argument('--input', type=str, default='res/path/test-1.jpg', help='输入图像或视频的路径')
|
||||
parser.add_argument('--output', type=str, default='res/path/test/result_image_20250514_024313.png', help='输出结果的保存路径')
|
||||
parser.add_argument('--type', type=str, choices=['image', 'video'], help='输入类型,不指定会自动检测')
|
||||
parser.add_argument('--show', default=True, action='store_true', help='显示处理步骤')
|
||||
|
@ -8,6 +8,7 @@ from utils.log_helper import get_logger, debug, info, warning, error, success
|
||||
def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True):
|
||||
"""
|
||||
检测正前方横向黄色赛道的边缘,并返回y值最大的边缘点
|
||||
优先检测下方横线,但在遇到下方线截断的情况时会考虑上边缘
|
||||
|
||||
参数:
|
||||
image: 输入图像,可以是文件路径或者已加载的图像数组
|
||||
@ -18,7 +19,7 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
edge_point: 赛道前方边缘点的坐标 (x, y)
|
||||
edge_info: 边缘信息字典
|
||||
"""
|
||||
observe = False # TSET
|
||||
# observe = False # TSET
|
||||
# 如果输入是字符串(文件路径),则加载图像
|
||||
if isinstance(image, str):
|
||||
img = cv2.imread(image)
|
||||
@ -91,142 +92,240 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
bottom_row = np.max(col_points)
|
||||
bottom_points.append((left_bound + col, top_bound + bottom_row))
|
||||
|
||||
if len(bottom_points) < 3:
|
||||
# 如果找不到足够的底部点,使用canny+霍夫变换
|
||||
edges = cv2.Canny(mask, 50, 150, apertureSize=3)
|
||||
|
||||
# 寻找每列的最顶部点(上边缘点)
|
||||
top_points = []
|
||||
for col in non_zero_cols:
|
||||
col_points = np.where(search_mask[:, col] > 0)[0]
|
||||
if len(col_points) > 0:
|
||||
top_row = np.min(col_points)
|
||||
top_points.append((left_bound + col, top_bound + top_row))
|
||||
|
||||
if observe:
|
||||
debug("检测底部和顶部边缘点", "处理")
|
||||
edge_points_img = img.copy()
|
||||
for point in bottom_points:
|
||||
cv2.circle(edge_points_img, point, 3, (0, 255, 0), -1)
|
||||
for point in top_points:
|
||||
cv2.circle(edge_points_img, point, 3, (255, 0, 255), -1)
|
||||
cv2.imshow("边缘点", edge_points_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 边缘检测
|
||||
edges = cv2.Canny(mask, 50, 150, apertureSize=3)
|
||||
|
||||
if observe:
|
||||
debug("步骤4: 边缘检测", "处理")
|
||||
cv2.imshow("边缘检测", edges)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 使用霍夫变换检测直线
|
||||
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=30,
|
||||
minLineLength=width*0.1, maxLineGap=30)
|
||||
|
||||
if lines is None or len(lines) == 0:
|
||||
if observe:
|
||||
debug("步骤3.1: 边缘检测", "处理")
|
||||
cv2.imshow("边缘检测", edges)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 使用霍夫变换检测直线 - 调低阈值以检测短线段
|
||||
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=30,
|
||||
minLineLength=width*0.1, maxLineGap=30)
|
||||
|
||||
if lines is None or len(lines) == 0:
|
||||
if observe:
|
||||
error("未检测到直线", "失败")
|
||||
return None, None
|
||||
|
||||
if observe:
|
||||
debug(f"步骤4: 检测到 {len(lines)} 条直线", "处理")
|
||||
lines_img = img.copy()
|
||||
for line in lines:
|
||||
x1, y1, x2, y2 = line[0]
|
||||
cv2.line(lines_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
||||
cv2.imshow("检测到的直线", lines_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 筛选水平线,但放宽斜率条件
|
||||
horizontal_lines = []
|
||||
error("未检测到直线", "失败")
|
||||
return None, None
|
||||
|
||||
if observe:
|
||||
debug(f"步骤5: 检测到 {len(lines)} 条直线", "处理")
|
||||
lines_img = img.copy()
|
||||
for line in lines:
|
||||
x1, y1, x2, y2 = line[0]
|
||||
|
||||
# 计算斜率 (避免除零错误)
|
||||
if abs(x2 - x1) < 5: # 几乎垂直的线
|
||||
continue
|
||||
|
||||
slope = (y2 - y1) / (x2 - x1)
|
||||
|
||||
# 筛选接近水平的线 (斜率接近0),但容许更大的倾斜度
|
||||
if abs(slope) < 0.3:
|
||||
# 确保线在搜索区域内
|
||||
if ((left_bound <= x1 <= right_bound and top_bound <= y1 <= bottom_bound) or
|
||||
(left_bound <= x2 <= right_bound and top_bound <= y2 <= bottom_bound)):
|
||||
# 计算线的中点y坐标
|
||||
mid_y = (y1 + y2) / 2
|
||||
line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2)
|
||||
# 保存线段、其y坐标和长度
|
||||
horizontal_lines.append((line[0], mid_y, slope, line_length))
|
||||
cv2.line(lines_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
||||
cv2.imshow("检测到的直线", lines_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 筛选水平线,但放宽斜率条件
|
||||
horizontal_lines = []
|
||||
for line in lines:
|
||||
x1, y1, x2, y2 = line[0]
|
||||
|
||||
if not horizontal_lines:
|
||||
if observe:
|
||||
error("未检测到水平线", "失败")
|
||||
return None, None
|
||||
# 计算斜率 (避免除零错误)
|
||||
if abs(x2 - x1) < 5: # 几乎垂直的线
|
||||
continue
|
||||
|
||||
slope = (y2 - y1) / (x2 - x1)
|
||||
|
||||
# 筛选接近水平的线 (斜率接近0),但容许更大的倾斜度
|
||||
if abs(slope) < 0.3:
|
||||
# 确保线在搜索区域内
|
||||
if ((left_bound <= x1 <= right_bound and top_bound <= y1 <= bottom_bound) or
|
||||
(left_bound <= x2 <= right_bound and top_bound <= y2 <= bottom_bound)):
|
||||
# 计算线的中点y坐标
|
||||
mid_y = (y1 + y2) / 2
|
||||
line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2)
|
||||
# 保存线段、其y坐标和长度
|
||||
horizontal_lines.append((line[0], mid_y, slope, line_length))
|
||||
|
||||
if not horizontal_lines:
|
||||
if observe:
|
||||
debug(f"步骤4.1: 找到 {len(horizontal_lines)} 条水平线", "处理")
|
||||
h_lines_img = img.copy()
|
||||
for line_info in horizontal_lines:
|
||||
line, _, slope, _ = line_info
|
||||
x1, y1, x2, y2 = line
|
||||
cv2.line(h_lines_img, (x1, y1), (x2, y2), (0, 255, 255), 2)
|
||||
# 显示斜率
|
||||
cv2.putText(h_lines_img, f"{slope:.2f}", ((x1+x2)//2, (y1+y2)//2),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
|
||||
cv2.imshow("水平线", h_lines_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
error("未检测到水平线", "失败")
|
||||
return None, None
|
||||
|
||||
if observe:
|
||||
debug(f"步骤6: 找到 {len(horizontal_lines)} 条水平线", "处理")
|
||||
h_lines_img = img.copy()
|
||||
for line_info in horizontal_lines:
|
||||
line, _, slope, _ = line_info
|
||||
x1, y1, x2, y2 = line
|
||||
cv2.line(h_lines_img, (x1, y1), (x2, y2), (0, 255, 255), 2)
|
||||
# 显示斜率
|
||||
cv2.putText(h_lines_img, f"{slope:.2f}", ((x1+x2)//2, (y1+y2)//2),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
|
||||
cv2.imshow("水平线", h_lines_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 将水平线分为上边缘线和下边缘线(按y坐标排序)
|
||||
bottom_line = None
|
||||
top_line = None
|
||||
is_truncated = False # 标记下方线是否被截断
|
||||
|
||||
if len(horizontal_lines) > 1:
|
||||
# 按y坐标排序 (从大到小,底部的线排在前面)
|
||||
horizontal_lines.sort(key=lambda x: x[1], reverse=True)
|
||||
|
||||
# 取最靠近底部且足够长的线作为横向赛道线
|
||||
selected_line = None
|
||||
selected_slope = 0
|
||||
for line_info in horizontal_lines:
|
||||
line, _, slope, length = line_info
|
||||
if length > width * 0.1: # 确保线足够长
|
||||
selected_line = line
|
||||
selected_slope = slope
|
||||
break
|
||||
# 提取最底部和次底部的线段
|
||||
bottom_line = horizontal_lines[0]
|
||||
|
||||
if selected_line is None and horizontal_lines:
|
||||
# 如果没有足够长的线,就取最靠近底部的线
|
||||
selected_line = horizontal_lines[0][0]
|
||||
selected_slope = horizontal_lines[0][2]
|
||||
# 检查是否有明显的上下边缘
|
||||
y_coords = [line[1] for line in horizontal_lines]
|
||||
y_diffs = [y_coords[i] - y_coords[i+1] for i in range(len(y_coords)-1)]
|
||||
|
||||
if selected_line is None:
|
||||
if observe:
|
||||
error("无法选择合适的线段", "失败")
|
||||
return None, None
|
||||
if len(y_diffs) > 0 and max(y_diffs) > height * 0.05: # 如果有明显的高度差
|
||||
# 找到高度差最大的位置
|
||||
split_idx = y_diffs.index(max(y_diffs))
|
||||
|
||||
x1, y1, x2, y2 = selected_line
|
||||
# 分别获取下边缘线和上边缘线
|
||||
bottom_line = horizontal_lines[0] # 最底部的线
|
||||
top_line = horizontal_lines[split_idx+1] # 上边缘线
|
||||
|
||||
# 检查上下两条线是否平行 - 计算斜率差异
|
||||
bottom_slope = bottom_line[2]
|
||||
top_slope = top_line[2]
|
||||
slope_diff = abs(bottom_slope - top_slope)
|
||||
|
||||
# 计算两线的交点(如果存在)
|
||||
bottom_x1, bottom_y1, bottom_x2, bottom_y2 = bottom_line[0]
|
||||
top_x1, top_y1, top_x2, top_y2 = top_line[0]
|
||||
|
||||
# 根据斜率差异判断是否平行
|
||||
# 如果斜率差异很小,认为基本平行
|
||||
if slope_diff > 0.05: # 斜率差异超过阈值
|
||||
# 计算两条线延长后的交点
|
||||
# 线段方程: y = mx + b
|
||||
# 计算两条线的截距b
|
||||
bottom_b = bottom_y1 - bottom_slope * bottom_x1
|
||||
top_b = top_y1 - top_slope * top_x1
|
||||
|
||||
# 检查交点是否在图像范围内或者附近
|
||||
# 求解 y = m1*x + b1 = m2*x + b2
|
||||
if abs(bottom_slope - top_slope) > 1e-6: # 避免除以接近0的值
|
||||
intersection_x = (top_b - bottom_b) / (bottom_slope - top_slope)
|
||||
intersection_y = bottom_slope * intersection_x + bottom_b
|
||||
|
||||
# 判断交点是否在图像宽度的2倍范围内
|
||||
if -width <= intersection_x <= width * 2:
|
||||
is_truncated = True
|
||||
if observe:
|
||||
debug(f"检测到上下边缘线不平行,交点: ({intersection_x:.1f}, {intersection_y:.1f})", "分析")
|
||||
debug("判断下方线被截断", "分析")
|
||||
|
||||
# 显示上下边缘线及其延长线和交点
|
||||
intersect_img = img.copy()
|
||||
# 画原始线段
|
||||
cv2.line(intersect_img, (bottom_x1, bottom_y1), (bottom_x2, bottom_y2), (0, 255, 0), 2)
|
||||
cv2.line(intersect_img, (top_x1, top_y1), (top_x2, top_y2), (255, 0, 255), 2)
|
||||
|
||||
# 延长线段以显示交点
|
||||
ext_left_x = max(0, int(intersection_x - width/2))
|
||||
ext_right_x = min(width-1, int(intersection_x + width/2))
|
||||
|
||||
# 计算延长线上的点
|
||||
bottom_ext_left_y = int(bottom_slope * ext_left_x + bottom_b)
|
||||
bottom_ext_right_y = int(bottom_slope * ext_right_x + bottom_b)
|
||||
top_ext_left_y = int(top_slope * ext_left_x + top_b)
|
||||
top_ext_right_y = int(top_slope * ext_right_x + top_b)
|
||||
|
||||
# 绘制延长线
|
||||
cv2.line(intersect_img, (ext_left_x, bottom_ext_left_y),
|
||||
(ext_right_x, bottom_ext_right_y), (0, 255, 0), 1, cv2.LINE_DASHED)
|
||||
cv2.line(intersect_img, (ext_left_x, top_ext_left_y),
|
||||
(ext_right_x, top_ext_right_y), (255, 0, 255), 1, cv2.LINE_DASHED)
|
||||
|
||||
# 标记交点
|
||||
if 0 <= intersection_x < width and 0 <= intersection_y < height:
|
||||
cv2.circle(intersect_img, (int(intersection_x), int(intersection_y)),
|
||||
10, (0, 0, 255), -1)
|
||||
|
||||
cv2.imshow("上下边缘线交点分析", intersect_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 如果检测到下方线被截断,使用上边缘线来估计实际的下边缘线
|
||||
if is_truncated and top_line is not None:
|
||||
if observe:
|
||||
debug("使用上边缘估计真实的下边缘", "处理")
|
||||
|
||||
# 获取赛道平均宽度(可以是预先测量的固定值,或根据未截断部分测量)
|
||||
# 这里假设赛道宽度是固定的,可以根据实际情况调整
|
||||
track_width_pixels = height * 0.15 # 假设赛道宽度是图像高度的15%
|
||||
|
||||
# 计算一个修正后的底部线段,方向与上边缘线平行,但位置下移
|
||||
corrected_bottom_slope = top_slope # 使用上边缘的斜率
|
||||
|
||||
# 计算上边缘线的方程: y = mx + b
|
||||
top_b = top_y1 - top_slope * top_x1
|
||||
|
||||
# 计算修正后的下边缘线的截距,使其下移track_width_pixels距离
|
||||
# 由于是在图像坐标系,y轴向下,所以是加法
|
||||
corrected_bottom_b = top_b + track_width_pixels
|
||||
|
||||
# 计算修正后的下边缘线的两个端点
|
||||
corrected_bottom_x1 = left_bound
|
||||
corrected_bottom_y1 = int(corrected_bottom_slope * corrected_bottom_x1 + corrected_bottom_b)
|
||||
corrected_bottom_x2 = right_bound
|
||||
corrected_bottom_y2 = int(corrected_bottom_slope * corrected_bottom_x2 + corrected_bottom_b)
|
||||
|
||||
# 创建修正后的底部线段
|
||||
corrected_bottom_line = (
|
||||
[corrected_bottom_x1, corrected_bottom_y1, corrected_bottom_x2, corrected_bottom_y2],
|
||||
(corrected_bottom_y1 + corrected_bottom_y2) / 2, # mid_y
|
||||
corrected_bottom_slope,
|
||||
np.sqrt((corrected_bottom_x2-corrected_bottom_x1)**2 + (corrected_bottom_y2-corrected_bottom_y1)**2) # length
|
||||
)
|
||||
|
||||
if observe:
|
||||
# 显示修正后的线段
|
||||
corrected_img = img.copy()
|
||||
# 原始线段
|
||||
cv2.line(corrected_img, (bottom_x1, bottom_y1), (bottom_x2, bottom_y2), (0, 255, 0), 2)
|
||||
cv2.line(corrected_img, (top_x1, top_y1), (top_x2, top_y2), (255, 0, 255), 2)
|
||||
# 修正后的线段
|
||||
cv2.line(corrected_img, (corrected_bottom_x1, corrected_bottom_y1),
|
||||
(corrected_bottom_x2, corrected_bottom_y2), (0, 0, 255), 2)
|
||||
|
||||
cv2.putText(corrected_img, "截断的底边", (bottom_x1, bottom_y1 - 10),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
|
||||
cv2.putText(corrected_img, "上边缘", (top_x1, top_y1 - 10),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 255), 2)
|
||||
cv2.putText(corrected_img, "修正后的底边", (corrected_bottom_x1, corrected_bottom_y1 - 10),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
|
||||
|
||||
cv2.imshow("修正后的边缘线", corrected_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 使用修正后的底部线作为选定的线
|
||||
bottom_line = corrected_bottom_line
|
||||
else:
|
||||
# 使用底部点拟合直线
|
||||
if observe:
|
||||
debug("正在处理底部边缘点", "处理")
|
||||
bottom_points_img = img.copy()
|
||||
for point in bottom_points:
|
||||
cv2.circle(bottom_points_img, point, 3, (0, 255, 0), -1)
|
||||
cv2.imshow("底部边缘点", bottom_points_img)
|
||||
cv2.waitKey(delay)
|
||||
|
||||
# 使用RANSAC拟合直线以去除异常值
|
||||
x_points = np.array([p[0] for p in bottom_points]).reshape(-1, 1)
|
||||
y_points = np.array([p[1] for p in bottom_points])
|
||||
|
||||
# 如果点过少或分布不够宽,返回None
|
||||
if len(bottom_points) < 3 or np.max(x_points) - np.min(x_points) < width * 0.1:
|
||||
if observe:
|
||||
warning("底部点太少或分布不够宽", "警告")
|
||||
return None, None
|
||||
|
||||
ransac = linear_model.RANSACRegressor(residual_threshold=5.0)
|
||||
ransac.fit(x_points, y_points)
|
||||
|
||||
# 获取拟合参数
|
||||
selected_slope = ransac.estimator_.coef_[0]
|
||||
intercept = ransac.estimator_.intercept_
|
||||
|
||||
# 检查斜率是否在合理范围内
|
||||
if abs(selected_slope) > 0.3:
|
||||
if observe:
|
||||
warning(f"拟合斜率过大: {selected_slope:.4f}", "警告")
|
||||
return None, None
|
||||
|
||||
# 使用拟合的直线参数计算线段端点
|
||||
x1 = left_bound
|
||||
y1 = int(selected_slope * x1 + intercept)
|
||||
x2 = right_bound
|
||||
y2 = int(selected_slope * x2 + intercept)
|
||||
|
||||
if observe:
|
||||
debug("显示拟合线段", "处理")
|
||||
fitted_line_img = img.copy()
|
||||
cv2.line(fitted_line_img, (x1, y1), (x2, y2), (0, 255, 255), 2)
|
||||
cv2.imshow("拟合线段", fitted_line_img)
|
||||
cv2.waitKey(delay)
|
||||
# 只有一条水平线
|
||||
bottom_line = horizontal_lines[0]
|
||||
|
||||
# 使用底部线段作为最终选择
|
||||
selected_line = bottom_line[0]
|
||||
selected_slope = bottom_line[2]
|
||||
|
||||
# 提取线段端点
|
||||
x1, y1, x2, y2 = selected_line
|
||||
|
||||
# 确保x1 < x2
|
||||
if x1 > x2:
|
||||
@ -248,7 +347,7 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
selected_points.append((x, y))
|
||||
|
||||
if observe:
|
||||
debug(f"步骤5: 找到边缘点 {bottom_edge_point}", "检测")
|
||||
debug(f"步骤7: 找到边缘点 {bottom_edge_point}", "检测")
|
||||
edge_img = img.copy()
|
||||
# 画线
|
||||
cv2.line(edge_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
||||
@ -297,6 +396,9 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
||||
cv2.putText(slope_img, f"中线交点: ({intersection_point[0]}, {intersection_point[1]})", (10, 150),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
||||
if is_truncated:
|
||||
cv2.putText(slope_img, "下方线被截断(已修正)", (10, 190),
|
||||
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
|
||||
|
||||
if observe:
|
||||
debug("显示边缘斜率和中线交点", "显示")
|
||||
@ -327,7 +429,8 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
"distance_to_center": distance_to_center,
|
||||
"slope": selected_slope,
|
||||
"distance_to_bottom": distance_to_bottom,
|
||||
"intersection_point": intersection_point
|
||||
"intersection_point": intersection_point,
|
||||
"is_truncated": is_truncated
|
||||
}
|
||||
info(f"横向边缘检测结果: {log_info}", "日志")
|
||||
|
||||
@ -341,6 +444,7 @@ def detect_horizontal_track_edge(image, observe=False, delay=1000, save_log=True
|
||||
"points_count": len(selected_points), # 该组中点的数量
|
||||
"intersection_point": intersection_point, # 中线与横向线的交点
|
||||
"distance_to_bottom": distance_to_bottom, # 交点到图像底部的距离
|
||||
"is_truncated": is_truncated, # 下方线是否被截断并修正
|
||||
# "points": selected_points # 添加选定的点组
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user