453 lines
18 KiB
Python
453 lines
18 KiB
Python
|
import cv2
|
|||
|
import numpy as np
|
|||
|
import os
|
|||
|
import datetime
|
|||
|
|
|||
|
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):
|
|||
|
"""
|
|||
|
检测左右两条平行的黄色轨道线,优化后能够处理石板路上的黄线
|
|||
|
|
|||
|
参数:
|
|||
|
image: 输入图像,可以是文件路径或者已加载的图像数组
|
|||
|
observe: 是否输出中间状态信息和可视化结果,默认为False
|
|||
|
delay: 展示每个步骤的等待时间(毫秒)
|
|||
|
save_log: 是否保存日志和图像
|
|||
|
stone_path_mode: 石板路模式,针对石板路上的黄线进行特殊处理
|
|||
|
|
|||
|
返回:
|
|||
|
tuple: (中心线信息, 左轨迹线信息, 右轨迹线信息)
|
|||
|
"""
|
|||
|
# 如果输入是字符串(文件路径),则加载图像
|
|||
|
if isinstance(image, str):
|
|||
|
img = cv2.imread(image)
|
|||
|
else:
|
|||
|
img = image.copy()
|
|||
|
|
|||
|
if img is None:
|
|||
|
error("无法加载图像", "失败")
|
|||
|
return None, None, None
|
|||
|
|
|||
|
# 获取图像尺寸
|
|||
|
height, width = img.shape[:2]
|
|||
|
|
|||
|
# 计算图像中间区域的范围
|
|||
|
center_x = width // 2
|
|||
|
|
|||
|
# 转换到HSV颜色空间以便更容易提取黄色
|
|||
|
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
|||
|
|
|||
|
# 根据是否为石板路模式选择不同的参数
|
|||
|
if stone_path_mode:
|
|||
|
# 石板路上的黄线通常对比度更低,需要更宽松的颜色范围
|
|||
|
lower_yellow = np.array([10, 60, 60]) # 更宽松的黄色下限
|
|||
|
upper_yellow = np.array([40, 255, 255]) # 更宽松的黄色上限
|
|||
|
else:
|
|||
|
# 标准黄色的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)
|
|||
|
|
|||
|
if observe:
|
|||
|
debug("步骤1: 创建黄色掩码", "处理")
|
|||
|
cv2.imshow("黄色掩码", mask)
|
|||
|
cv2.waitKey(delay)
|
|||
|
|
|||
|
# 裁剪底部区域重点关注近处的黄线
|
|||
|
bottom_roi_height = int(height * 0.4) # 关注图像底部40%区域
|
|||
|
bottom_roi = mask[height-bottom_roi_height:, :]
|
|||
|
|
|||
|
if observe:
|
|||
|
debug("步骤1.5: 底部区域掩码", "处理")
|
|||
|
cv2.imshow("底部区域掩码", bottom_roi)
|
|||
|
cv2.waitKey(delay)
|
|||
|
|
|||
|
# 边缘检测 - 针对石板路调整参数
|
|||
|
if stone_path_mode:
|
|||
|
edges = cv2.Canny(mask, 30, 120, apertureSize=3) # 降低阈值以捕捉更弱的边缘
|
|||
|
else:
|
|||
|
edges = cv2.Canny(mask, 50, 150, apertureSize=3)
|
|||
|
|
|||
|
if observe:
|
|||
|
debug("步骤2: 边缘检测", "处理")
|
|||
|
cv2.imshow("边缘检测", edges)
|
|||
|
cv2.waitKey(delay)
|
|||
|
|
|||
|
# 霍夫变换检测直线 - 根据是否为石板路调整参数
|
|||
|
if stone_path_mode:
|
|||
|
# 石板路上的线段可能更短更断续,使用更宽松的参数
|
|||
|
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=20,
|
|||
|
minLineLength=width*0.03, maxLineGap=50)
|
|||
|
else:
|
|||
|
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=25,
|
|||
|
minLineLength=width*0.05, maxLineGap=40)
|
|||
|
|
|||
|
if lines is None or len(lines) == 0:
|
|||
|
error("未检测到直线", "失败")
|
|||
|
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:
|
|||
|
x1, y1, x2, y2 = line[0]
|
|||
|
|
|||
|
# 优先选择图像底部的线
|
|||
|
if y1 < height * 0.5 and y2 < height * 0.5:
|
|||
|
continue # 忽略上半部分的线
|
|||
|
|
|||
|
# 计算斜率 (避免除零错误)
|
|||
|
if abs(x2 - x1) < 5: # 几乎垂直的线
|
|||
|
slope = 100 # 设置一个较大的值表示接近垂直
|
|||
|
else:
|
|||
|
slope = (y2 - y1) / (x2 - x1)
|
|||
|
|
|||
|
# 根据是否为石板路调整斜率阈值
|
|||
|
min_slope_threshold = 0.5 if stone_path_mode else 0.75
|
|||
|
|
|||
|
# 筛选接近垂直的线 (斜率较大),但允许更多倾斜度
|
|||
|
if abs(slope) > min_slope_threshold:
|
|||
|
line_length = np.sqrt((x2-x1)**2 + (y2-y1)**2)
|
|||
|
# 计算线的中点x坐标
|
|||
|
mid_x = (x1 + x2) / 2
|
|||
|
# 计算线的中点y坐标
|
|||
|
mid_y = (y1 + y2) / 2
|
|||
|
# 保存线段、其坐标、斜率和长度
|
|||
|
vertical_lines.append((line[0], mid_x, mid_y, slope, line_length))
|
|||
|
|
|||
|
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.3:
|
|||
|
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
|
|||
|
|
|||
|
if observe:
|
|||
|
debug(f"步骤4: 找到 {len(vertical_lines)} 条垂直线", "处理")
|
|||
|
v_lines_img = img.copy()
|
|||
|
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.putText(v_lines_img, 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.waitKey(delay)
|
|||
|
|
|||
|
# 优先选择更接近图像底部的线 - 根据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_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_slope, candidate_length = candidate_line
|
|||
|
|
|||
|
# 如果x坐标接近且斜率相似,认为是同一条线的不同部分
|
|||
|
x_diff = abs(current_mid_x - candidate_mid_x)
|
|||
|
slope_diff = abs(current_slope - candidate_slope)
|
|||
|
|
|||
|
if x_diff < width * 0.05 and slope_diff < 0.3:
|
|||
|
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]
|
|||
|
|
|||
|
# 如果任一侧没有检测到线,则放宽左右两侧线的分组条件
|
|||
|
if not left_lines or not right_lines:
|
|||
|
# 按x坐标排序所有垂直线
|
|||
|
vertical_lines.sort(key=lambda x: x[1])
|
|||
|
|
|||
|
# 如果有至少两条线,将最左侧的线作为左轨迹线,最右侧的线作为右轨迹线
|
|||
|
if len(vertical_lines) >= 2:
|
|||
|
left_lines = [vertical_lines[0]]
|
|||
|
right_lines = [vertical_lines[-1]]
|
|||
|
else:
|
|||
|
error("左侧或右侧未检测到轨迹线", "失败")
|
|||
|
return None, None, None
|
|||
|
|
|||
|
# 从左右两组中各选择一条最佳的线
|
|||
|
# 优先选择同时满足:1. 更靠近底部 2. 足够长 3. 更接近中心的线
|
|||
|
def score_line(line_info, is_left):
|
|||
|
_, mid_x, mid_y, slope, length = line_info
|
|||
|
# y越大(越靠近底部)分数越高
|
|||
|
y_score = mid_y / height
|
|||
|
# 线越长分数越高
|
|||
|
length_score = min(1.0, length / (height * 0.3))
|
|||
|
|
|||
|
# 石板路模式下,调整预期的线位置
|
|||
|
if stone_path_mode:
|
|||
|
# 使用更宽的轨道宽度估计
|
|||
|
expected_x = center_x * 0.25 if is_left else center_x * 1.75
|
|||
|
else:
|
|||
|
expected_x = center_x * 0.3 if is_left else center_x * 1.7
|
|||
|
|
|||
|
x_score = 1.0 - min(1.0, abs(mid_x - expected_x) / (center_x * 0.5))
|
|||
|
|
|||
|
# 综合评分,石板路模式下更重视线段长度
|
|||
|
if stone_path_mode:
|
|||
|
return y_score * 0.4 + length_score * 0.4 + x_score * 0.2
|
|||
|
else:
|
|||
|
return y_score * 0.5 + length_score * 0.3 + x_score * 0.2
|
|||
|
|
|||
|
# 对左右线组进行评分并排序
|
|||
|
left_lines = sorted(left_lines, key=lambda line: score_line(line, True), reverse=True)
|
|||
|
right_lines = sorted(right_lines, key=lambda line: score_line(line, False), reverse=True)
|
|||
|
|
|||
|
left_line = left_lines[0]
|
|||
|
right_line = right_lines[0]
|
|||
|
|
|||
|
# 获取两条线的坐标
|
|||
|
left_x1, left_y1, left_x2, left_y2 = left_line[0]
|
|||
|
right_x1, right_y1, right_x2, right_y2 = right_line[0]
|
|||
|
|
|||
|
# 确保线段的顺序是从上到下
|
|||
|
if left_y1 > left_y2:
|
|||
|
left_x1, left_x2 = left_x2, left_x1
|
|||
|
left_y1, left_y2 = left_y2, left_y1
|
|||
|
|
|||
|
if right_y1 > right_y2:
|
|||
|
right_x1, right_x2 = right_x2, right_x1
|
|||
|
right_y1, right_y2 = right_y2, right_y1
|
|||
|
|
|||
|
# 计算中心线
|
|||
|
center_line_x1 = (left_x1 + right_x1) // 2
|
|||
|
center_line_y1 = (left_y1 + right_y1) // 2
|
|||
|
center_line_x2 = (left_x2 + right_x2) // 2
|
|||
|
center_line_y2 = (left_y2 + right_y2) // 2
|
|||
|
|
|||
|
# 计算中心线的斜率
|
|||
|
if abs(center_line_x2 - center_line_x1) < 5:
|
|||
|
center_slope = 100 # 几乎垂直
|
|||
|
else:
|
|||
|
center_slope = (center_line_y2 - center_line_y1) / (center_line_x2 - center_line_x1)
|
|||
|
|
|||
|
# 计算中心线延伸到图像底部的点
|
|||
|
if abs(center_slope) < 0.01: # 几乎垂直
|
|||
|
bottom_x = center_line_x1
|
|||
|
else:
|
|||
|
bottom_x = int(center_line_x1 + (height - center_line_y1) / center_slope)
|
|||
|
center_point = (bottom_x, height)
|
|||
|
|
|||
|
# 计算中心线与图像中心线的偏差
|
|||
|
deviation = bottom_x - center_x
|
|||
|
|
|||
|
result_img = None
|
|||
|
if observe or save_log:
|
|||
|
result_img = img.copy()
|
|||
|
# 绘制左右轨迹线
|
|||
|
cv2.line(result_img, (int(left_x1), int(left_y1)), (int(left_x2), int(left_y2)), (255, 0, 0), 2)
|
|||
|
cv2.line(result_img, (int(right_x1), int(right_y1)), (int(right_x2), int(right_y2)), (0, 0, 255), 2)
|
|||
|
# 绘制中心线
|
|||
|
cv2.line(result_img, (center_line_x1, center_line_y1), (center_line_x2, center_line_y2), (0, 255, 0), 2)
|
|||
|
cv2.line(result_img, (center_line_x2, center_line_y2), center_point, (0, 255, 0), 2)
|
|||
|
# 绘制图像中心线
|
|||
|
cv2.line(result_img, (center_x, 0), (center_x, height), (0, 0, 255), 1)
|
|||
|
# 标记中心点
|
|||
|
cv2.circle(result_img, center_point, 10, (255, 0, 255), -1)
|
|||
|
|
|||
|
# 显示偏差信息
|
|||
|
cv2.putText(result_img, f"Deviation: {deviation}px", (10, 30),
|
|||
|
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
|||
|
|
|||
|
# 显示是否为石板路模式
|
|||
|
if stone_path_mode:
|
|||
|
cv2.putText(result_img, "Stone Path Mode", (10, 60),
|
|||
|
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
|
|||
|
|
|||
|
if observe:
|
|||
|
cv2.imshow("轨迹线检测结果", result_img)
|
|||
|
cv2.waitKey(delay)
|
|||
|
|
|||
|
# 保存日志图像
|
|||
|
if save_log and result_img is not None:
|
|||
|
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
|||
|
log_dir = "logs/image"
|
|||
|
os.makedirs(log_dir, exist_ok=True)
|
|||
|
img_path = os.path.join(log_dir, f"dual_track_{timestamp}.jpg")
|
|||
|
cv2.imwrite(img_path, result_img)
|
|||
|
info(f"保存双轨迹线检测结果图像到: {img_path}", "日志")
|
|||
|
|
|||
|
# 保存文本日志信息
|
|||
|
log_info = {
|
|||
|
"timestamp": timestamp,
|
|||
|
"center_point": center_point,
|
|||
|
"deviation": deviation,
|
|||
|
"left_track_mid_x": left_line[1],
|
|||
|
"right_track_mid_x": right_line[1],
|
|||
|
"track_width": right_line[1] - left_line[1],
|
|||
|
"center_slope": center_slope,
|
|||
|
"stone_path_mode": stone_path_mode
|
|||
|
}
|
|||
|
info(f"双轨迹线检测结果: {log_info}", "日志")
|
|||
|
|
|||
|
# 创建左右轨迹线和中心线信息
|
|||
|
left_track_info = {
|
|||
|
"line": left_line[0],
|
|||
|
"slope": left_line[3],
|
|||
|
"x_mid": left_line[1]
|
|||
|
}
|
|||
|
|
|||
|
right_track_info = {
|
|||
|
"line": right_line[0],
|
|||
|
"slope": right_line[3],
|
|||
|
"x_mid": right_line[1]
|
|||
|
}
|
|||
|
|
|||
|
center_info = {
|
|||
|
"point": center_point,
|
|||
|
"deviation": deviation,
|
|||
|
"slope": center_slope,
|
|||
|
"is_vertical": abs(center_slope) > 5.0, # 判断是否接近垂直
|
|||
|
"track_width": right_line[1] - left_line[1], # 两轨迹线之间的距离
|
|||
|
"stone_path_mode": stone_path_mode # 记录是否使用了石板路模式
|
|||
|
}
|
|||
|
|
|||
|
return center_info, left_track_info, right_track_info
|
|||
|
|
|||
|
def auto_detect_dual_track_lines(image, observe=False, delay=1000, save_log=True):
|
|||
|
"""
|
|||
|
自动检测双轨迹线,先尝试标准模式,如果失败则尝试石板路模式
|
|||
|
|
|||
|
参数:
|
|||
|
image: 输入图像,可以是文件路径或者已加载的图像数组
|
|||
|
observe: 是否输出中间状态信息和可视化结果,默认为False
|
|||
|
delay: 展示每个步骤的等待时间(毫秒)
|
|||
|
save_log: 是否保存日志和图像
|
|||
|
|
|||
|
返回:
|
|||
|
tuple: (中心线信息, 左轨迹线信息, 右轨迹线信息)
|
|||
|
"""
|
|||
|
# 先尝试标准模式
|
|||
|
result = detect_dual_track_lines(image, observe, delay, save_log, stone_path_mode=False)
|
|||
|
|
|||
|
# 如果标准模式失败,尝试石板路模式
|
|||
|
if result[0] is None:
|
|||
|
info("标准模式检测失败,尝试石板路模式", "自动检测")
|
|||
|
result = detect_dual_track_lines(image, observe, delay, save_log, stone_path_mode=True)
|
|||
|
|
|||
|
return result
|