From 365d59fe75ca41f3addff2567319da8759590722 Mon Sep 17 00:00:00 2001 From: Havoc <2993167370@qq.com> Date: Sat, 31 May 2025 12:33:28 +0800 Subject: [PATCH] vertical: step - 1 --- logs/robot_2025-05-31.log | 335 +++++++++++++++++++++++ test/test_image.py | 3 +- utils/base_line_handler.py | 166 ++++++++++++ utils/detect_dual_track_lines.py | 449 ++++++++++++++----------------- 4 files changed, 711 insertions(+), 242 deletions(-) create mode 100644 utils/base_line_handler.py diff --git a/logs/robot_2025-05-31.log b/logs/robot_2025-05-31.log index 596c872..de42d62 100644 --- a/logs/robot_2025-05-31.log +++ b/logs/robot_2025-05-31.log @@ -80,3 +80,338 @@ 2025-05-31 09:49:18 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_094918_337104.jpg 2025-05-31 09:49:18 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_094918_337104.jpg 2025-05-31 09:49:18 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_094918_337104', 'center_point': (944, 1080), 'deviation': -15.5, 'left_track_mid_x': 624.0, 'right_track_mid_x': 1219.0, 'track_width': 595.0, 'center_slope': 0.02132675438596272, 'stone_path_mode': False} +2025-05-31 10:29:14 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:29:16 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:29:18 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:29:20 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 49 条直线 +2025-05-31 10:29:22 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 19 条垂直线 +2025-05-31 10:29:24 | DEBUG | utils.log_helper - 🐞 步骤4.5: 合并后找到 10 条垂直线 +2025-05-31 10:29:26 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 5, 右侧候选线数量: 5 +2025-05-31 10:29:26 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.89 +2025-05-31 10:29:28 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_102928_778495.jpg +2025-05-31 10:29:28 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_102928_778495.jpg +2025-05-31 10:29:28 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_102928_778495', 'center_point': (952, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 528.0, 'right_track_mid_x': 1388.5, 'track_width': 860.5, 'center_slope': -0.0016446763600527115} +2025-05-31 10:29:37 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:29:39 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:29:41 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:29:44 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 10:29:46 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 10:29:48 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 10:29:48 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.02 +2025-05-31 10:29:50 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_102950_067699.jpg +2025-05-31 10:29:50 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_102950_067699.jpg +2025-05-31 10:29:50 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_102950_067699', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669, 'stone_path_mode': False} +2025-05-31 10:32:18 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:32:20 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:32:22 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:32:24 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 10:32:26 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 10:32:28 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 10:32:28 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.02 +2025-05-31 10:32:30 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_103230_706359.jpg +2025-05-31 10:32:30 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_103230_706359.jpg +2025-05-31 10:32:30 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_103230_706359', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 10:54:05 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:54:06 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:54:06 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:54:07 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 10:54:08 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 10:54:09 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 10:54:09 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 10:54:10 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_105410_128420.jpg +2025-05-31 10:54:10 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_105410_128420.jpg +2025-05-31 10:54:10 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_105410_128420', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 10:56:14 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:56:15 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:56:16 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:56:16 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 10:56:17 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 10:56:18 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 10:56:18 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 10:56:19 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_105619_406431.jpg +2025-05-31 10:56:19 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_105619_406431.jpg +2025-05-31 10:56:19 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_105619_406431', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 10:59:46 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 10:59:47 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 10:59:48 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 10:59:49 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 10:59:50 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 10:59:51 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 10:59:51 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 10:59:51 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_105951_966275.jpg +2025-05-31 10:59:51 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_105951_966275.jpg +2025-05-31 10:59:51 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_105951_966275', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:09:05 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:09:06 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:09:07 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:09:08 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:09:09 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 11:09:10 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 11:09:10 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:09:10 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_110910_854647.jpg +2025-05-31 11:09:10 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_110910_854647.jpg +2025-05-31 11:09:10 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_110910_854647', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:09:24 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:09:26 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:09:28 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:09:30 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:09:32 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 11:09:34 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 11:09:34 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:09:36 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_110936_844379.jpg +2025-05-31 11:09:36 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_110936_844379.jpg +2025-05-31 11:09:36 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_110936_844379', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:14:39 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:14:41 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:14:43 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:14:45 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:14:47 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 11:14:49 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 11:14:49 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:14:51 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_111451_964924.jpg +2025-05-31 11:14:51 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_111451_964924.jpg +2025-05-31 11:14:51 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_111451_964924', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:14:56 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:14:58 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:15:00 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:15:02 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:15:04 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 11:15:06 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 11:15:06 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:15:08 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_111508_434244.jpg +2025-05-31 11:15:08 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_111508_434244.jpg +2025-05-31 11:15:08 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_111508_434244', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:15:23 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:15:24 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:15:25 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:15:26 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:15:27 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 24 条垂直线 +2025-05-31 11:15:28 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 12, 右侧候选线数量: 12 +2025-05-31 11:15:28 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:15:29 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_111529_709703.jpg +2025-05-31 11:15:29 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_111529_709703.jpg +2025-05-31 11:15:29 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_111529_709703', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:15:35 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:15:36 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:15:37 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:15:38 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:15:39 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 27 条垂直线 +2025-05-31 11:15:40 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 15, 右侧候选线数量: 12 +2025-05-31 11:15:40 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:15:41 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_111541_404961.jpg +2025-05-31 11:15:41 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_111541_404961.jpg +2025-05-31 11:15:41 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_111541_404961', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:18:59 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:19:00 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:19:01 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:19:03 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:19:04 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 27 条垂直线 +2025-05-31 11:19:05 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 15, 右侧候选线数量: 12 +2025-05-31 11:19:05 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:19:06 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_111906_059419.jpg +2025-05-31 11:19:06 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_111906_059419.jpg +2025-05-31 11:19:06 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_111906_059419', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:20:17 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:20:19 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:20:20 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:20:21 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:20:22 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 27 条垂直线 +2025-05-31 11:20:23 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 15, 右侧候选线数量: 12 +2025-05-31 11:20:24 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:20:25 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_112025_176560.jpg +2025-05-31 11:20:25 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_112025_176560.jpg +2025-05-31 11:20:25 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_112025_176560', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:20:36 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:20:37 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:20:38 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:20:39 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 11:20:40 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 27 条垂直线 +2025-05-31 11:20:41 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 15, 右侧候选线数量: 12 +2025-05-31 11:20:42 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 11:20:43 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_112043_362415.jpg +2025-05-31 11:20:43 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_112043_362415.jpg +2025-05-31 11:20:43 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_112043_362415', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} +2025-05-31 11:47:40 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:47:42 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:47:43 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:47:44 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:47:44 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:47:44 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:47:45 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:47:46 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:47:47 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:47:48 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_114748_278587.jpg +2025-05-31 11:47:48 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_114748_278587.jpg +2025-05-31 11:47:48 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_114748_278587', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:47:50 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:47:51 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:47:52 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:47:53 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:47:53 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:47:53 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:47:54 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:47:55 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:47:56 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:47:57 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_114757_837088.jpg +2025-05-31 11:47:57 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_114757_837088.jpg +2025-05-31 11:47:57 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_114757_837088', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:49:15 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:49:16 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:49:17 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:49:18 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:49:18 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:49:18 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:49:19 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:49:20 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:49:21 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:49:22 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_114922_309402.jpg +2025-05-31 11:49:22 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_114922_309402.jpg +2025-05-31 11:49:22 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_114922_309402', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:54:18 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:54:19 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:54:20 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:54:21 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:54:21 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:54:21 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:54:22 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:54:23 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:54:24 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:54:25 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115425_535559.jpg +2025-05-31 11:54:25 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115425_535559.jpg +2025-05-31 11:54:25 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115425_535559', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:54:31 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:54:32 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:54:33 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:54:34 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:54:34 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:54:34 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:54:35 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:54:36 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:54:37 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:54:38 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115438_968316.jpg +2025-05-31 11:54:38 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115438_968316.jpg +2025-05-31 11:54:38 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115438_968316', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:54:42 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:54:43 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:54:44 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:54:45 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:54:45 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:54:45 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:54:46 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:54:47 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:54:48 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:54:49 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115449_602349.jpg +2025-05-31 11:54:49 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115449_602349.jpg +2025-05-31 11:54:49 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115449_602349', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 11:55:50 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:55:51 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:55:52 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:55:53 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:55:53 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:55:53 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:55:54 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:55:55 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:55:56 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:55:57 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115557_917521.jpg +2025-05-31 11:55:57 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115557_917521.jpg +2025-05-31 11:55:57 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115557_917521', 'center_point': (945, 1080), 'deviation': 0.10552257197241488, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02638064299316605} +2025-05-31 11:56:12 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:56:13 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:56:14 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:57:45 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:57:46 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:57:47 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:57:48 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:57:48 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:57:48 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:57:49 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 15 条垂直线 +2025-05-31 11:57:50 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 10, 右侧候选线数量: 5 +2025-05-31 11:57:51 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:57:52 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115752_281641.jpg +2025-05-31 11:57:52 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115752_281641.jpg +2025-05-31 11:57:52 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115752_281641', 'center_point': (945, 1080), 'deviation': 0.10552257197241488, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02638064299316605} +2025-05-31 11:58:36 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 11:58:37 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 11:58:38 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 11:58:39 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 11:58:39 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 11:58:39 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 11:58:40 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 11:58:41 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 4, 右侧候选线数量: 3 +2025-05-31 11:58:42 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 11:58:43 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_115843_399705.jpg +2025-05-31 11:58:43 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_115843_399705.jpg +2025-05-31 11:58:43 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_115843_399705', 'center_point': (945, 1080), 'deviation': 0.10552257197241488, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02638064299316605} +2025-05-31 12:14:32 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:14:33 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:14:35 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:14:36 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 12:14:36 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 12:14:36 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 12:14:37 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:14:38 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 4, 右侧候选线数量: 3 +2025-05-31 12:14:39 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 12:14:40 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_121440_131832.jpg +2025-05-31 12:14:40 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_121440_131832.jpg +2025-05-31 12:14:40 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_121440_131832', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 12:18:29 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:18:30 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:18:31 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:18:32 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 12:18:32 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 12:18:32 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 12:18:33 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:18:34 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 4, 右侧候选线数量: 3 +2025-05-31 12:18:35 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 12:18:37 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_121837_013535.jpg +2025-05-31 12:18:37 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_121837_013535.jpg +2025-05-31 12:18:37 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_121837_013535', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 12:18:46 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:18:47 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:18:48 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:18:49 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 12:18:49 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 12:18:49 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 12:18:50 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:18:51 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 4, 右侧候选线数量: 3 +2025-05-31 12:18:52 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 12:18:53 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_121853_427060.jpg +2025-05-31 12:18:53 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_121853_427060.jpg +2025-05-31 12:18:53 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_121853_427060', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 12:19:01 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:19:02 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:19:03 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:19:04 | DEBUG | utils.log_helper - 🐞 步骤2.5: 初始检测到 54 条直线,尝试合并 +2025-05-31 12:19:04 | DEBUG | utils.log_helper - 🐞 合并后剩余 31 条直线 +2025-05-31 12:19:04 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 31 条直线 +2025-05-31 12:19:05 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:19:06 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 4, 右侧候选线数量: 3 +2025-05-31 12:19:07 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 0.95 +2025-05-31 12:19:08 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_121908_570358.jpg +2025-05-31 12:19:08 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_121908_570358.jpg +2025-05-31 12:19:08 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_121908_570358', 'center_point': (945, 1080), 'deviation': 3.410605131648481e-13, 'left_track_mid_x': 608.5, 'right_track_mid_x': 1219.0, 'track_width': 610.5, 'center_slope': 0.02351973684210257} +2025-05-31 12:25:05 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:25:07 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:25:08 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:25:09 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 12:25:10 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:31:54 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:31:55 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:31:56 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:31:57 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 12:31:58 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:32:08 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:32:09 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:32:10 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:32:11 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 12:32:12 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 7 条垂直线 +2025-05-31 12:33:06 | DEBUG | utils.log_helper - 🐞 步骤1: 创建黄色掩码 +2025-05-31 12:33:07 | DEBUG | utils.log_helper - 🐞 步骤1.5: 底部区域掩码 +2025-05-31 12:33:09 | DEBUG | utils.log_helper - 🐞 步骤2: 边缘检测 +2025-05-31 12:33:10 | DEBUG | utils.log_helper - 🐞 步骤3: 检测到 54 条直线 +2025-05-31 12:33:11 | DEBUG | utils.log_helper - 🐞 步骤4: 找到 11 条垂直线 +2025-05-31 12:33:12 | DEBUG | utils.log_helper - 🐞 左侧候选线数量: 6, 右侧候选线数量: 5 +2025-05-31 12:33:13 | DEBUG | utils.log_helper - 🐞 选择最佳线对,评分: 1.01 +2025-05-31 12:33:14 | INFO | utils.log_helper - ℹ️ 保存双轨迹线检测结果图像到: logs/image/dual_track_20250531_123314_086361.jpg +2025-05-31 12:33:14 | INFO | utils.log_helper - ℹ️ 保存原始图像到: logs/image/dual_track_orig_20250531_123314_086361.jpg +2025-05-31 12:33:14 | INFO | utils.log_helper - ℹ️ 双轨迹线检测结果: {'timestamp': '20250531_123314_086361', 'center_point': (944, 1080), 'deviation': -1.1368683772161603e-13, 'left_track_mid_x': 565.0, 'right_track_mid_x': 1335.5, 'track_width': 770.5, 'center_slope': 0.01738261738261669} diff --git a/test/test_image.py b/test/test_image.py index ead0309..101a7ca 100644 --- a/test/test_image.py +++ b/test/test_image.py @@ -22,9 +22,8 @@ print("正在使用普通模式检测...") center_info, left_track_info, right_track_info = detect_dual_track_lines( image_path, observe=True, # 设置为True以查看处理过程和结果 - delay=2000, # 增加显示时间以便观察 + delay=1000, # 增加显示时间以便观察 save_log=True, - stone_path_mode=False ) if center_info: diff --git a/utils/base_line_handler.py b/utils/base_line_handler.py new file mode 100644 index 0000000..f9af663 --- /dev/null +++ b/utils/base_line_handler.py @@ -0,0 +1,166 @@ +import numpy as np +import cv2 + +def _are_lines_mergeable(line1_pts, line2_pts, + max_angle_diff_deg, + max_ep_gap_abs, max_ep_gap_factor, + max_p_dist_abs, max_p_dist_factor): + """ + 判断两条线段是否可以合并。 + lineX_pts: [x1, y1, x2, y2] + max_angle_diff_deg: 最大角度差 (度) + max_ep_gap_abs: 端点间最大绝对间隙 + max_ep_gap_factor: 端点间最大相对间隙 (基于较短线段长度的因子) + max_p_dist_abs: 最大绝对垂直距离 + max_p_dist_factor: 最大相对垂直距离 (基于较短线段长度的因子) + """ + x1a, y1a, x2a, y2a = line1_pts + x1b, y1b, x2b, y2b = line2_pts + + p1a, p2a = np.array([x1a, y1a]), np.array([x2a, y2a]) + p1b, p2b = np.array([x1b, y1b]), np.array([x2b, y2b]) + + len_a = np.linalg.norm(p2a - p1a) + len_b = np.linalg.norm(p2b - p1b) + + if len_a < 1e-3 or len_b < 1e-3: return False # 避免零长度线段 + shorter_len = min(len_a, len_b) + + # 1. 角度相似性 + angle_a = np.arctan2(y2a - y1a, x2a - x1a) + angle_b = np.arctan2(y2b - y1b, x2b - x1b) + angle_diff = np.degrees(angle_a - angle_b) + + while angle_diff <= -180: angle_diff += 360 + while angle_diff > 180: angle_diff -= 360 + + is_angle_similar = abs(angle_diff) < max_angle_diff_deg or \ + abs(abs(angle_diff) - 180) < max_angle_diff_deg + if not is_angle_similar: + return False + + # 2. 共线性: 检查一个线段的端点到另一个线段(无限延长)的垂直距离 + current_max_allowed_perp_dist = max(max_p_dist_abs, max_p_dist_factor * shorter_len) + + def get_perp_dist_point_to_inf_line(p, line_p1, line_p2, line_len): + if line_len < 1e-3: return np.linalg.norm(p - line_p1) # 线是点 + return abs((line_p2[1]-line_p1[1])*p[0] - (line_p2[0]-line_p1[0])*p[1] + \ + line_p2[0]*line_p1[1] - line_p2[1]*line_p1[0]) / line_len + + dist_b1_to_a_inf = get_perp_dist_point_to_inf_line(p1b, p1a, p2a, len_a) + dist_b2_to_a_inf = get_perp_dist_point_to_inf_line(p2b, p1a, p2a, len_a) + dist_a1_to_b_inf = get_perp_dist_point_to_inf_line(p1a, p1b, p2b, len_b) + dist_a2_to_b_inf = get_perp_dist_point_to_inf_line(p2a, p1b, p2b, len_b) + + # 如果两条线都很短,那么允许的垂直距离也应该小 + # 如果一条线的端点离另一条无限延长的线太远,则不合并 + if min(dist_b1_to_a_inf, dist_b2_to_a_inf) > current_max_allowed_perp_dist and \ + min(dist_a1_to_b_inf, dist_a2_to_b_inf) > current_max_allowed_perp_dist: + return False + + # 3. 邻近性/重叠性: 端点之间的最小距离 + min_ep_dist = min(np.linalg.norm(p1a-p1b), np.linalg.norm(p1a-p2b), + np.linalg.norm(p2a-p1b), np.linalg.norm(p2a-p2b)) + + current_max_allowed_ep_gap = max(max_ep_gap_abs, max_ep_gap_factor * shorter_len) + if min_ep_dist > current_max_allowed_ep_gap: + return False + + # 附加检查:确保线段确实是"连接的"或"重叠的" + # 计算一个端点到另一个 *线段* (非无限线) 的距离 + def dist_point_to_segment(p, seg_a, seg_b): + ap = p - seg_a + ab = seg_b - seg_a + ab_len_sq = np.dot(ab, ab) + if ab_len_sq < 1e-6: return np.linalg.norm(ap) + + t = np.dot(ap, ab) / ab_len_sq + if t < 0.0: closest_point = seg_a + elif t > 1.0: closest_point = seg_b + else: closest_point = seg_a + t * ab + return np.linalg.norm(p - closest_point) + + dist_p1a_to_seg_b = dist_point_to_segment(p1a, p1b, p2b) + dist_p2a_to_seg_b = dist_point_to_segment(p2a, p1b, p2b) + dist_p1b_to_seg_a = dist_point_to_segment(p1b, p1a, p2a) + dist_p2b_to_seg_a = dist_point_to_segment(p2b, p1a, p2a) + + if min(dist_p1a_to_seg_b, dist_p2a_to_seg_b, dist_p1b_to_seg_a, dist_p2b_to_seg_a) > current_max_allowed_ep_gap: + return False + + return True + +def _merge_two_lines(line1_pts, line2_pts): + points = np.array([ + line1_pts[:2], line1_pts[2:], + line2_pts[:2], line2_pts[2:] + ], dtype=np.float32) + + vx, vy, x0, y0 = cv2.fitLine(points.reshape(-1,1,2), cv2.DIST_L2, 0, 0.01, 0.01) + vx, vy, x0, y0 = vx[0], vy[0], x0[0], y0[0] + + projected_params = [] + line_origin = np.array([x0, y0]) + line_direction = np.array([vx, vy]) + + for i in range(4): + pt_vec = points[i] - line_origin + param = np.dot(pt_vec, line_direction) + projected_params.append(param) + + min_param = min(projected_params) + max_param = max(projected_params) + + p_start = line_origin + min_param * line_direction + p_end = line_origin + max_param * line_direction + + return [int(round(p_start[0])), int(round(p_start[1])), + int(round(p_end[0])), int(round(p_end[1]))] + +def _merge_collinear_lines_iterative(lines_from_hough, + min_initial_len, + max_angle_diff_deg, + max_ep_gap_abs, max_ep_gap_factor, + max_p_dist_abs, max_p_dist_factor): + if lines_from_hough is None: + return None + + # 将HoughLinesP的输出转换为Python列表 [[x1,y1,x2,y2], ...] + py_lines = [list(line[0]) for line in lines_from_hough] + + # 过滤掉初始太短的线 + current_lines = [line for line in py_lines if np.linalg.norm(np.array(line[:2]) - np.array(line[2:])) >= min_initial_len] + + if not current_lines or len(current_lines) < 2: + return np.array([[line] for line in current_lines]) if current_lines else np.array([]) + + made_change_in_pass = True + while made_change_in_pass: + made_change_in_pass = False + i = 0 + while i < len(current_lines): + j = i + 1 + merged_line_i = False + while j < len(current_lines): + if _are_lines_mergeable(current_lines[i], current_lines[j], + max_angle_diff_deg, + max_ep_gap_abs, max_ep_gap_factor, + max_p_dist_abs, max_p_dist_factor): + + merged_line = _merge_two_lines(current_lines[i], current_lines[j]) + current_lines[i] = merged_line # 更新第i条线 + current_lines.pop(j) # 移除第j条线 + made_change_in_pass = True + merged_line_i = True + # 由于current_lines[i]已改变,且列表长度已改变, + # 最安全的是从头开始或至少重新评估current_lines[i] + # 但对于这种贪心策略,继续尝试将(新的)current_lines[i]与后续线合并是可以的 + # j的位置不需要改变,因为它指向被删除元素后的下一个元素 + continue # j 现在指向下一条未检查的线,相对于更新后的i + j += 1 + + # 如果 line_i 在内部循环中被修改过,则外部的 i 也应该重新评估 + # 但由于我们是迭代地进行整个过程(while made_change_in_pass), 最终会收敛 + i += 1 + + return np.array([[line] for line in current_lines]) if current_lines else np.array([]) diff --git a/utils/detect_dual_track_lines.py b/utils/detect_dual_track_lines.py index 4d2723a..953ac62 100644 --- a/utils/detect_dual_track_lines.py +++ b/utils/detect_dual_track_lines.py @@ -3,9 +3,14 @@ import numpy as np import os import datetime +from utils.base_line_handler import _merge_collinear_lines_iterative from utils.log_helper import LogHelper, get_logger, section, info, debug, warning, error, success, timing -def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, stone_path_mode=False): +def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, + max_slope_threshold=2, + min_slope_threshold=0.5, + min_line_length=0.05, + max_line_gap=40): """ 检测左右两条平行的黄色轨道线,优化后能够更准确处理各种路况 @@ -14,7 +19,11 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto observe: 是否输出中间状态信息和可视化结果,默认为False delay: 展示每个步骤的等待时间(毫秒) save_log: 是否保存日志和图像 - stone_path_mode: 石板路模式,针对石板路上的黄线进行特殊处理 + + max_slope_threshold: 最大斜率阈值 + min_slope_threshold: 最小斜率阈值 + min_line_length: 最小线段长度 + max_line_gap: 最大线段间距 返回: tuple: (中心线信息, 左轨迹线信息, 右轨迹线信息) @@ -44,57 +53,24 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto # 转换到HSV颜色空间以便更容易提取黄色 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) - # 根据是否为石板路模式选择不同的参数 - if stone_path_mode: - # 石板路上的黄线通常对比度更低,需要更宽松的颜色范围 - lower_yellow = np.array([8, 50, 50]) # 更宽松的黄色下限 - upper_yellow = np.array([45, 255, 255]) # 更宽松的黄色上限 - else: - # 标准黄色的HSV范围 - lower_yellow = np.array([15, 80, 80]) - upper_yellow = np.array([35, 255, 255]) + # 标准黄色的HSV范围 + lower_yellow = np.array([15, 80, 80]) + upper_yellow = np.array([35, 255, 255]) # 创建黄色的掩码 mask = cv2.inRange(hsv, lower_yellow, upper_yellow) - # 应用对比度增强 - if stone_path_mode: - # 在处理掩码前先对原图像进行预处理 - # 对原图进行自适应直方图均衡化增强对比度 - lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB) - l, a, b = cv2.split(lab) - clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8)) - l = clahe.apply(l) - lab = cv2.merge((l, a, b)) - enhanced_img = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR) - - # 用增强后的图像重新检测黄色 - enhanced_hsv = cv2.cvtColor(enhanced_img, cv2.COLOR_BGR2HSV) - enhanced_mask = cv2.inRange(enhanced_hsv, lower_yellow, upper_yellow) - - # 组合原始掩码和增强掩码 - mask = cv2.bitwise_or(mask, enhanced_mask) - - if observe: - debug("增强对比度和颜色检测", "处理") - cv2.imshow("增强对比度", enhanced_img) - cv2.imshow("增强后的黄色掩码", enhanced_mask) - cv2.waitKey(delay) - - # 形态学操作以改善掩码 - if stone_path_mode: - # 石板路上的线条可能更细更断续,使用更大的膨胀核和更多的迭代次数 - kernel = np.ones((7, 7), np.uint8) - mask = cv2.dilate(mask, kernel, iterations=2) - mask = cv2.erode(mask, np.ones((3, 3), np.uint8), iterations=1) - else: - kernel = np.ones((5, 5), np.uint8) - mask = cv2.dilate(mask, kernel, iterations=1) - mask = cv2.erode(mask, np.ones((3, 3), np.uint8), iterations=1) + kernel = np.ones((5, 5), np.uint8) + mask = cv2.dilate(mask, kernel, iterations=1) + mask = cv2.erode(mask, np.ones((3, 3), np.uint8), iterations=1) if observe: debug("步骤1: 创建黄色掩码", "处理") - cv2.imshow("黄色掩码", mask) + mask_display = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) + cv2.putText(mask_display, "Step 1: Yellow Mask", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(mask_display, f"Lower: {lower_yellow}", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.putText(mask_display, f"Upper: {upper_yellow}", (10, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("黄色掩码", mask_display) cv2.waitKey(delay) # 裁剪底部区域重点关注近处的黄线 @@ -103,28 +79,26 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto if observe: debug("步骤1.5: 底部区域掩码", "处理") - cv2.imshow("底部区域掩码", bottom_roi) + bottom_roi_display = cv2.cvtColor(bottom_roi, cv2.COLOR_GRAY2BGR) + cv2.putText(bottom_roi_display, "Step 1.5: Bottom ROI", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(bottom_roi_display, f"ROI Height: {bottom_roi_height}px ({bottom_roi_height/height*100:.0f}%)", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("底部区域掩码", bottom_roi_display) cv2.waitKey(delay) - # 边缘检测 - 针对石板路调整参数 - if stone_path_mode: - edges = cv2.Canny(mask, 20, 100, apertureSize=3) # 进一步降低阈值以捕捉更弱的边缘 - else: - edges = cv2.Canny(mask, 50, 150, apertureSize=3) + # INFO 边缘检测 + edges = cv2.Canny(mask, 50, 150, apertureSize=3) if observe: debug("步骤2: 边缘检测", "处理") - cv2.imshow("边缘检测", edges) + edges_display = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) + cv2.putText(edges_display, "Step 2: Edge Detection (Canny)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(edges_display, "Thresholds: (50, 150)", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("边缘检测", edges_display) cv2.waitKey(delay) - # 霍夫变换检测直线 - 根据是否为石板路调整参数 - if stone_path_mode: - # 石板路上的线段可能更短更断续,使用更宽松的参数 - lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=15, - minLineLength=width*0.02, maxLineGap=60) - else: - lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=25, - minLineLength=width*0.05, maxLineGap=40) + # INFO 霍夫变换检测直线 + lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=25, + minLineLength=width*min_line_length, maxLineGap=max_line_gap) if lines is None or len(lines) == 0: error("未检测到直线", "失败") @@ -133,6 +107,8 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto if observe: debug(f"步骤3: 检测到 {len(lines)} 条直线", "处理") lines_img = img.copy() + cv2.putText(lines_img, "Step 3: Hough Lines", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) + cv2.putText(lines_img, f"Th:25, MinLen:{width*0.05:.1f}, MaxGap:{max_line_gap}", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1) for line in lines: x1, y1, x2, y2 = line[0] cv2.line(lines_img, (x1, y1), (x2, y2), (0, 255, 0), 2) @@ -154,11 +130,8 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto else: slope = (y2 - y1) / (x2 - x1) - # 根据是否为石板路调整斜率阈值 - min_slope_threshold = 0.4 if stone_path_mode else 0.75 - # 筛选接近垂直的线 (斜率较大),但允许更多倾斜度 - if abs(slope) > min_slope_threshold: + if max_slope_threshold > abs(slope) > min_slope_threshold: line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2) # 计算线的中点x坐标 mid_x = (x1 + x2) / 2 @@ -167,30 +140,15 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto # 保存线段、其坐标、斜率和长度 vertical_lines.append((line[0], mid_x, mid_y, slope, line_length)) + # vertical_lines = _merge_collinear_lines_iterative(vertical_lines, + # min_initial_len=5.0, + # max_angle_diff_deg=10.0, + # max_ep_gap_abs=max_line_gap / 2.0, + # max_ep_gap_factor=0.25, + # max_p_dist_abs=max_line_gap / 4.0, + # max_p_dist_factor=0.1) + if len(vertical_lines) < 2: - # 石板路模式下,尝试放宽斜率条件重新筛选线段 - if stone_path_mode: - vertical_lines = [] - for line in lines: - x1, y1, x2, y2 = line[0] - - # 仍然优先选择图像底部的线 - if y1 < height * 0.6 and y2 < height * 0.6: - continue # 忽略上部分的线 - - # 计算斜率 (避免除零错误) - if abs(x2 - x1) < 5: # 几乎垂直的线 - slope = 100 - else: - slope = (y2 - y1) / (x2 - x1) - - # 使用更宽松的斜率阈值 - if abs(slope) > 0.2: # 进一步放宽斜率阈值 - line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2) - mid_x = (x1 + x2) / 2 - mid_y = (y1 + y2) / 2 - vertical_lines.append((line[0], mid_x, mid_y, slope, line_length)) - if len(vertical_lines) < 2: error("未检测到足够的垂直线", "失败") return None, None, None @@ -198,6 +156,8 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto if observe: debug(f"步骤4: 找到 {len(vertical_lines)} 条垂直线", "处理") v_lines_img = img.copy() + cv2.putText(v_lines_img, "Step 4: Vertical Lines Filtered", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) + cv2.putText(v_lines_img, f"Min Slope Abs: {min_slope_threshold:.2f}", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1) for line_info in vertical_lines: line, _, _, slope, _ = line_info x1, y1, x2, y2 = line @@ -211,76 +171,6 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto # 优先选择更接近图像底部的线 - 根据y坐标均值排序 vertical_lines.sort(key=lambda x: x[2], reverse=True) # 按mid_y从大到小排序 - # 石板路模式下,可能需要处理断续的线段或合并相近的线段 - if stone_path_mode and len(vertical_lines) >= 3: - # 尝试合并相近的线段 - merged_lines = [] - processed = [False] * len(vertical_lines) - - for i in range(len(vertical_lines)): - if processed[i]: - continue - - current_line = vertical_lines[i] - _, current_mid_x, current_mid_y, current_slope, current_length = current_line - - # 查找相近的线段 - similar_lines = [current_line] - processed[i] = True - - for j in range(i+1, len(vertical_lines)): - if processed[j]: - continue - - candidate_line = vertical_lines[j] - _, candidate_mid_x, candidate_mid_y, candidate_slope, candidate_length = candidate_line - - # 如果x坐标接近且斜率相似,认为是同一条线的不同部分 - x_diff = abs(current_mid_x - candidate_mid_x) - slope_diff = abs(current_slope - candidate_slope) - y_diff = abs(current_mid_y - candidate_mid_y) - - # 放宽相似线段的判断条件 - if ((x_diff < width * 0.08 and slope_diff < 0.4) or # 更宽松的x差异和斜率差异 - (x_diff < width * 0.05 and y_diff < height * 0.2)): # 或者x和y都比较接近 - similar_lines.append(candidate_line) - processed[j] = True - - # 如果找到多条相近的线,合并它们 - if len(similar_lines) > 1: - # 按线长度加权合并 - total_weight = sum(line[4] for line in similar_lines) - merged_x1 = sum(line[0][0] * line[4] for line in similar_lines) / total_weight - merged_y1 = sum(line[0][1] * line[4] for line in similar_lines) / total_weight - merged_x2 = sum(line[0][2] * line[4] for line in similar_lines) / total_weight - merged_y2 = sum(line[0][3] * line[4] for line in similar_lines) / total_weight - - merged_line = (np.array([int(merged_x1), int(merged_y1), - int(merged_x2), int(merged_y2)]), - (merged_x1 + merged_x2) / 2, - (merged_y1 + merged_y2) / 2, - (merged_y2 - merged_y1) / (merged_x2 - merged_x1 + 1e-6), - np.sqrt((merged_x2-merged_x1)**2 + (merged_y2-merged_y1)**2)) - - merged_lines.append(merged_line) - else: - merged_lines.append(current_line) - - vertical_lines = merged_lines - - if observe: - debug(f"步骤4.5: 合并后找到 {len(vertical_lines)} 条垂直线", "处理") - merged_img = img.copy() - for line_info in vertical_lines: - line, _, _, slope, _ = line_info - x1, y1, x2, y2 = line - cv2.line(merged_img, (int(x1), int(y1)), (int(x2), int(y2)), (255, 0, 255), 2) - # 显示斜率 - cv2.putText(merged_img, f"{slope:.2f}", (int((x1+x2)//2), int((y1+y2)//2)), - cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) - cv2.imshow("合并后的垂直线", merged_img) - cv2.waitKey(delay) - # 按x坐标将线分为左右两组 left_lines = [line for line in vertical_lines if line[1] < center_x] right_lines = [line for line in vertical_lines if line[1] > center_x] @@ -301,10 +191,40 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto if observe: debug(f"左侧候选线数量: {len(left_lines)}, 右侧候选线数量: {len(right_lines)}", "线候选") + # 创建左右线可视化图像 + left_right_img = img.copy() + cv2.putText(left_right_img, "Left and Right Candidate Lines", (10, 20), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) + + # 绘制左侧候选线(蓝色) + for line_info in left_lines: + line = line_info[0] + x1, y1, x2, y2 = line + cv2.line(left_right_img, (x1, y1), (x2, y2), (255, 0, 0), 2) + # 显示斜率 + mid_x = (x1 + x2) // 2 + mid_y = (y1 + y2) // 2 + cv2.putText(left_right_img, f"L:{line_info[3]:.2f}", (mid_x, mid_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) + + # 绘制右侧候选线(红色) + for line_info in right_lines: + line = line_info[0] + x1, y1, x2, y2 = line + cv2.line(left_right_img, (x1, y1), (x2, y2), (0, 0, 255), 2) + # 显示斜率 + mid_x = (x1 + x2) // 2 + mid_y = (y1 + y2) // 2 + cv2.putText(left_right_img, f"R:{line_info[3]:.2f}", (mid_x, mid_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) + + cv2.imshow("左右候选线", left_right_img) + cv2.waitKey(delay) + # 优化说明:在默认模式下,评分函数和线对选择都优先考虑更靠近图像中心的线段 # 这有助于减少对图像边缘可能出现的干扰线的选择,提高轨道线检测的准确性 - # 改进的评分函数 - 同时考虑斜率、位置、长度和在图像中的位置 + # INFO 改进的评分函数 - 同时考虑斜率、位置、长度和在图像中的位置 def score_line(line_info, is_left): _, mid_x, mid_y, slope, length = line_info line_points = line_info[0] # 获取线段的端点坐标 @@ -325,14 +245,8 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto length_score = min(1.0, length_ratio * 1.2) # 适当提高长线段的权重 # 位置评分 - 线段位于预期位置得分高 - # 根据是否为石板路模式调整预期位置 center_x = width / 2 - if stone_path_mode: - # 石板路上的轨道宽度可能不同 - expected_track_width = width * 0.5 # 石板路轨道宽度估计 - else: - # 普通轨道的期望位置 - 默认模式下更靠近中心 - expected_track_width = width * 0.4 # 普通轨道宽度估计,更窄以接近中心 + expected_track_width = width * 0.4 # 普通轨道宽度估计,更窄以接近中心 # 计算预期的线位置(基于图像中心和轨道宽度) expected_x = center_x - expected_track_width * 0.5 if is_left else center_x + expected_track_width * 0.5 @@ -391,27 +305,16 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto bottom_reach_score = 1.0 if reaches_bottom else 0.5 # 综合评分 - 调整权重 - if stone_path_mode: - # 石板路模式下更关注位置和底部接近程度 - final_score = ( - y_score * 0.25 + # 底部接近度 - length_score * 0.15 + # 线段长度 - x_score * 0.15 + # 中点位置 - bottom_x_score * 0.2 + # 底部点位置 - slope_score * 0.15 + # 斜率合适性 - bottom_reach_score * 0.1 # 是否到达底部 - ) - else: - # 普通轨道模式下更关注中心接近性 - final_score = ( - y_score * 0.15 + # 底部接近度 - length_score * 0.15 + # 线段长度 - x_score * 0.15 + # 中点位置 - center_proximity_score * 0.2 + # 与中心的接近度 (新增) - bottom_x_score * 0.15 + # 底部点位置 - slope_score * 0.1 + # 斜率合适性 - bottom_reach_score * 0.1 # 是否到达底部 - ) + # 普通轨道模式下更关注中心接近性 + final_score = ( + y_score * 0.15 + # 底部接近度 + length_score * 0.05 + # 线段长度 + x_score * 0.15 + # 中点位置 + center_proximity_score * 0.3 + # 与中心的接近度 (新增) + bottom_x_score * 0.15 + # 底部点位置 + slope_score * 0.1 + # 斜率合适性 + bottom_reach_score * 0.1 # 是否到达底部 + ) return final_score @@ -465,12 +368,8 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto width_score = 0.0 else: # 轨道宽度应该在合理范围内 - 调整范围更加精确 - if stone_path_mode: - expected_width = width * 0.5 # 石板路可能更宽一些 - allowed_deviation = width * 0.3 # 允许的偏差范围 - else: - expected_width = width * 0.4 # 普通轨道相对窄一些,更靠近中心 - allowed_deviation = width * 0.2 # 允许的偏差范围,更精确 + expected_width = width * 0.4 # 普通轨道相对窄一些,更靠近中心 + allowed_deviation = width * 0.2 # 允许的偏差范围,更精确 width_diff = abs(track_width - expected_width) width_score = max(0, 1.0 - width_diff / allowed_deviation) @@ -509,25 +408,22 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto # 综合评分 - 调整权重 # 更重视平行性和底部宽度 - if stone_path_mode: - pair_score = (left_score + right_score) * 0.3 + parallel_score * 0.25 + width_score * 0.2 + symmetry_score * 0.1 + bottom_width_score * 0.15 - else: - # 默认模式下,增加对中心接近性的权重 - # 计算左右线到中心的距离 - left_to_center = abs(left_x - center_x) - right_to_center = abs(right_x - center_x) - - # 标准化距离(与图像宽度相关) - left_center_ratio = left_to_center / (width * 0.5) - right_center_ratio = right_to_center / (width * 0.5) - - # 接近度得分 - 越接近中心分数越高 - left_center_score = max(0, 1.0 - left_center_ratio) - right_center_score = max(0, 1.0 - right_center_ratio) - center_proximity_score = (left_center_score + right_center_score) / 2 - - # 给予中心接近性更高的权重 - pair_score = (left_score + right_score) * 0.25 + parallel_score * 0.2 + width_score * 0.15 + symmetry_score * 0.1 + bottom_width_score * 0.1 + center_proximity_score * 0.2 + # 默认模式下,增加对中心接近性的权重 + # 计算左右线到中心的距离 + left_to_center = abs(left_x - center_x) + right_to_center = abs(right_x - center_x) + + # 标准化距离(与图像宽度相关) + left_center_ratio = left_to_center / (width * 0.5) + right_center_ratio = right_to_center / (width * 0.5) + + # 接近度得分 - 越接近中心分数越高 + left_center_score = max(0, 1.0 - left_center_ratio) + right_center_score = max(0, 1.0 - right_center_ratio) + center_proximity_score = (left_center_score + right_center_score) / 2 + + # 给予中心接近性更高的权重 + pair_score = (left_score + right_score) * 0.25 + parallel_score * 0.2 + width_score * 0.15 + symmetry_score * 0.1 + bottom_width_score * 0.1 + center_proximity_score * 0.2 if pair_score > best_pair_score: best_pair_score = pair_score @@ -575,6 +471,26 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto right_x1, right_x2 = right_x2, right_x1 right_y1, right_y2 = right_y2, right_y1 + + # 尝试延长线段到图像底部,处理被石板路部分遮挡的情况 + left_extended_y2 = height + if abs(left_x2 - left_x1) < 5: # 几乎垂直 + left_extended_x2 = left_x2 + else: + left_slope = (left_y2 - left_y1) / (left_x2 - left_x1) + left_extended_x2 = left_x1 + (left_extended_y2 - left_y1) / left_slope + + right_extended_y2 = height + if abs(right_x2 - right_x1) < 5: # 几乎垂直 + right_extended_x2 = right_x2 + else: + right_slope = (right_y2 - right_y1) / (right_x2 - right_x1) + right_extended_x2 = right_x1 + (right_extended_y2 - right_y1) / right_slope + + # 更新线段端点为延长后的坐标 + left_x2, left_y2 = int(left_extended_x2), left_extended_y2 + right_x2, right_y2 = int(right_extended_x2), right_extended_y2 + # 尝试延长线段到图像底部,处理被石板路部分遮挡的情况 left_extended_y2 = height if abs(left_x2 - left_x1) < 5: # 几乎垂直 @@ -893,11 +809,16 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto # 显示偏差信息 cv2.putText(result_img, f"Deviation: {deviation:.1f}px", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + cv2.putText(result_img, "Final Result", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) + if 'best_pair_score' in locals() and best_pair_score != -1: + cv2.putText(result_img, f"Pair Score: {best_pair_score:.2f}", (10, 85), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) + current_y_offset = 105 + else: + current_y_offset = 85 - # 显示是否为石板路模式 - if stone_path_mode: - cv2.putText(result_img, "Stone Path Mode", (10, 60), - cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2) + cv2.putText(result_img, f"L-Slope: {left_line[3]:.2f}, R-Slope: {right_line[3]:.2f}", (10, current_y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) + current_y_offset += 20 + cv2.putText(result_img, f"Track Width: {right_line[1] - left_line[1]:.1f}px", (10, current_y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) if observe: cv2.imshow("轨迹线检测结果", result_img) @@ -929,7 +850,6 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto "right_track_mid_x": float(right_line[1]), "track_width": float(right_line[1] - left_line[1]), "center_slope": float(center_slope), - "stone_path_mode": stone_path_mode } info(f"双轨迹线检测结果: {log_info}", "日志") @@ -952,7 +872,6 @@ def detect_dual_track_lines(image, observe=False, delay=1000, save_log=True, sto "slope": float(center_slope), "is_vertical": abs(center_slope) > 5.0, # 判断是否接近垂直 "track_width": float(right_line[1] - left_line[1]), # 两轨迹线之间的距离 - "stone_path_mode": stone_path_mode # 记录是否使用了石板路模式 } return center_info, left_track_info, right_track_info @@ -1013,7 +932,11 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ if observe: debug("步骤1: 创建黄色掩码", "处理") - cv2.imshow("黄色掩码", combined_mask) + mask_display = cv2.cvtColor(combined_mask, cv2.COLOR_GRAY2BGR) + cv2.putText(mask_display, "Step 1: Yellow Mask (Center Based)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(mask_display, f"Lower: {lower_yellow} + Darker Var.", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.putText(mask_display, f"Upper: {upper_yellow} + Darker Var.", (10, 55), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("黄色掩码", mask_display) cv2.waitKey(delay) # 裁剪底部区域重点关注近处的黄线 @@ -1022,7 +945,10 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ if observe: debug("步骤1.5: 底部区域掩码", "处理") - cv2.imshow("底部区域掩码", bottom_roi) + bottom_roi_display = cv2.cvtColor(bottom_roi, cv2.COLOR_GRAY2BGR) + cv2.putText(bottom_roi_display, "Step 1.5: Bottom ROI (Center Based)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(bottom_roi_display, f"ROI Height: {bottom_roi_height}px ({bottom_roi_height/height*100:.0f}%)", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("底部区域掩码", bottom_roi_display) cv2.waitKey(delay) # 边缘检测 @@ -1030,7 +956,10 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ if observe: debug("步骤2: 边缘检测", "处理") - cv2.imshow("边缘检测", edges) + edges_display = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR) + cv2.putText(edges_display, "Step 2: Edge Detection (Canny - Center Based)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) + cv2.putText(edges_display, "Thresholds: (50, 150)", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 255, 0), 1) + cv2.imshow("边缘检测", edges_display) cv2.waitKey(delay) # 霍夫变换检测直线 @@ -1038,18 +967,9 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ minLineLength=width*0.05, maxLineGap=40) if lines is None or len(lines) == 0: - error("未检测到直线", "失败") + error("未检测到直线 (或合并后无直线 - Center Based)", "失败") return None, None, None - - if observe: - debug(f"步骤3: 检测到 {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) - + # 筛选近似垂直的线 vertical_lines = [] for line in lines: @@ -1065,7 +985,7 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ else: slope = (y2 - y1) / (x2 - x1) - # 筛选接近垂直的线 (斜率较大) + # 筛选接近垂直的线 (斜率较大),但允许更多倾斜度 if abs(slope) > 0.5: # 降低斜率阈值以捕获更多候选线 line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2) # 计算线的中点x坐标 @@ -1081,18 +1001,41 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ if observe: debug(f"步骤4: 找到 {len(vertical_lines)} 条垂直线", "处理") - v_lines_img = img.copy() + v_lines_img_display = img.copy() + cv2.putText(v_lines_img_display, "Step 4: Vertical Lines Filtered (Center Based)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) + cv2.putText(v_lines_img_display, "Min Slope Abs: 0.50", (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255), 1) # Slope threshold is 0.5 here for line_info in vertical_lines: line, _, _, slope, _ = line_info x1, y1, x2, y2 = line - cv2.line(v_lines_img, (x1, y1), (x2, y2), (0, 255, 255), 2) + cv2.line(v_lines_img_display, (x1, y1), (x2, y2), (0, 255, 255), 2) # 显示斜率 - cv2.putText(v_lines_img, f"{slope:.2f}", ((x1+x2)//2, (y1+y2)//2), + cv2.putText(v_lines_img_display, f"{slope:.2f}", ((x1+x2)//2, (y1+y2)//2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) - cv2.imshow("垂直线", v_lines_img) + cv2.imshow("垂直线", v_lines_img_display) cv2.waitKey(delay) - # 评分函数 - 用于找到最可能的中心线 + debug(f"步骤2.5 (Center Based): 初始检测到 {len(vertical_lines)} 条垂直线,尝试合并", "处理") + + # 合并参数设置 (可以根据需要调整,这里使用与 detect_dual_track_lines 类似的设置) + # 注意:这里的 max_line_gap 是 HoughLinesP 本身的参数,不是函数参数 + # 如果需要独立于 detect_dual_track_lines 中的 max_line_gap,需要单独定义或传递 + current_max_line_gap = 40 # 来自 HoughLinesP + min_len_for_merge_cb = 5.0 + angle_thresh_deg_cb = 10.0 + ep_gap_abs_cb = current_max_line_gap / 2.0 + ep_gap_factor_cb = 0.25 + p_dist_abs_cb = current_max_line_gap / 4.0 + p_dist_factor_cb = 0.1 + + # vertical_lines = _merge_collinear_lines_iterative(vertical_lines, + # min_initial_len=min_len_for_merge_cb, + # max_angle_diff_deg=angle_thresh_deg_cb, + # max_ep_gap_abs=ep_gap_abs_cb, + # max_ep_gap_factor=ep_gap_factor_cb, + # max_p_dist_abs=p_dist_abs_cb, + # max_p_dist_factor=p_dist_factor_cb) + + # INFO 评分函数 - 用于找到最可能的中心线 def score_center_line(line_info): _, mid_x, mid_y, slope, length = line_info @@ -1129,6 +1072,20 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ # 找到可能的中心线 center_candidates = sorted(vertical_lines, key=score_center_line, reverse=True) + + if observe: + debug(f"步骤3.5: 找到 {len(center_candidates)} 条可能的中心线", "处理") + center_candidates_img_display = img.copy() + cv2.putText(center_candidates_img_display, "Step 3: Center Candidates (Center Based)", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) + for line_info in center_candidates: + line, _, _, slope, _ = line_info + x1, y1, x2, y2 = line + cv2.line(center_candidates_img_display, (x1, y1), (x2, y2), (0, 255, 255), 2) + # 显示斜率 + cv2.putText(center_candidates_img_display, f"{slope:.2f}", ((x1+x2)//2, (y1+y2)//2), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) + cv2.imshow("可能的中心线", center_candidates_img_display) + cv2.waitKey(delay) # 如果有足够的候选线,取前3个进行评估 if len(center_candidates) >= 3: @@ -1345,7 +1302,7 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ bottom_center_x = max(0, min(width - 1, bottom_center_x)) deviation = bottom_center_x - center_x - # 创建结果图像 + # INFO 创建结果图像 result_img = None if observe or save_log: result_img = img.copy() @@ -1368,6 +1325,18 @@ def detect_center_based_dual_track_lines(image, observe=False, delay=1000, save_ # 显示偏差信息 cv2.putText(result_img, f"Deviation: {deviation:.1f}px", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) + cv2.putText(result_img, "Final Result (Center Based)", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) + if 'best_score' in locals() and best_score != -1: + cv2.putText(result_img, f"Pair Score: {best_score:.2f}", (10, 85), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) + current_y_offset = 105 + else: + current_y_offset = 85 + + cv2.putText(result_img, f"Center Slope: {center_slope:.2f}", (10, current_y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) + current_y_offset += 20 + cv2.putText(result_img, f"L-Slope: {left_line[3]:.2f}, R-Slope: {right_line[3]:.2f}", (10, current_y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) + current_y_offset += 20 + cv2.putText(result_img, f"Track Width: {right_line[1] - left_line[1]:.1f}px", (10, current_y_offset), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) if observe: cv2.imshow("改进的中心线检测结果", result_img) @@ -1446,7 +1415,7 @@ def auto_detect_dual_track_lines(image, observe=False, delay=1000, save_log=True result = detect_center_based_dual_track_lines(image, observe, delay, save_log) else: info("使用传统检测方法", "检测") - result = detect_dual_track_lines(image, observe, delay, save_log, stone_path_mode=False) + result = detect_dual_track_lines(image, observe, delay, save_log) # 检查结果是否成功 if result[0] is not None: