mi-task/utils/decode_arrow.py
Havoc cfcdf24a4c feat(task_5): 添加箭头方向检测与运动控制
- 初始化箭头检测器并获取图像
- 根据检测到的箭头方向调整运动方向
- 更新运动参数,包括速度和步态
- 添加资源清理逻辑以确保检测器正常关闭
2025-05-13 09:44:34 +08:00

181 lines
5.6 KiB
Python

import cv2
import numpy as np
def detect_arrow_direction(image):
"""
从图像中提取绿色箭头并判断其指向方向(左或右)
参数:
image: 输入图像,可以是文件路径或者已加载的图像数组
返回:
direction: 字符串,"left"表示左箭头,"right"表示右箭头,"unknown"表示无法确定
"""
# 如果输入是字符串(文件路径),则加载图像
if isinstance(image, str):
img = cv2.imread(image)
else:
img = image.copy()
if img is None:
print("无法加载图像")
return "unknown"
# 转换到HSV颜色空间以便更容易提取绿色
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 绿色的HSV范围
# 调整这些值以匹配图像中绿色的具体色调··
lower_green = np.array([40, 50, 50])
upper_green = np.array([80, 255, 255])
# 创建绿色的掩码
mask = cv2.inRange(hsv, lower_green, upper_green)
# 应用掩码,只保留绿色部分
green_only = cv2.bitwise_and(img, img, mask=mask)
# 将掩码转为灰度图
gray = mask.copy()
# 查找轮廓
contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 如果没有找到轮廓,返回未知
if not contours:
return "unknown"
# 找到最大的轮廓(假设是箭头)
max_contour = max(contours, key=cv2.contourArea)
# 获取轮廓的最小外接矩形
x, y, w, h = cv2.boundingRect(max_contour)
# 计算轮廓的矩,用于确定箭头方向
M = cv2.moments(max_contour)
# 避免除以零
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
else:
cx, cy = x + w//2, y + h//2
# 将图像分为左右两部分
left_region = gray[y:y+h, x:cx]
right_region = gray[y:y+h, cx:x+w]
# 计算每个区域中白色像素的数量(箭头部分)
left_pixels = cv2.countNonZero(left_region)
right_pixels = cv2.countNonZero(right_region)
# 计算每个区域中白色像素的密度
left_density = left_pixels / (left_region.size + 1e-10)
right_density = right_pixels / (right_region.size + 1e-10)
# 根据左右区域的像素密度确定箭头方向
# 如果箭头指向右侧,右侧区域的箭头头部应该有更多的像素密度
# 如果箭头指向左侧,左侧区域的箭头头部应该有更多的像素密度
if right_density > left_density:
return "right"
else:
return "left"
def visualize_arrow_detection(image, save_path=None):
"""
可视化箭头检测过程,显示中间结果
参数:
image: 输入图像,可以是文件路径或者已加载的图像数组
save_path: 保存结果图像的路径(可选)
"""
# 如果输入是字符串(文件路径),则加载图像
if isinstance(image, str):
img = cv2.imread(image)
else:
img = image.copy()
if img is None:
print("无法加载图像")
return
# 转换到HSV颜色空间
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 绿色的HSV范围
lower_green = np.array([40, 50, 50])
upper_green = np.array([80, 255, 255])
# 创建绿色的掩码
mask = cv2.inRange(hsv, lower_green, upper_green)
# 应用掩码,只保留绿色部分
green_only = cv2.bitwise_and(img, img, mask=mask)
# 查找轮廓
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 创建输出图像
output = img.copy()
# 如果找到轮廓,绘制最大轮廓
if contours:
max_contour = max(contours, key=cv2.contourArea)
cv2.drawContours(output, [max_contour], -1, (0, 0, 255), 2)
# 获取轮廓的最小外接矩形
x, y, w, h = cv2.boundingRect(max_contour)
cv2.rectangle(output, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 计算轮廓的矩
M = cv2.moments(max_contour)
# 避免除以零
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
# 绘制中心点
cv2.circle(output, (cx, cy), 5, (255, 0, 0), -1)
# 绘制分割线
cv2.line(output, (cx, y), (cx, y + h), (0, 255, 255), 2)
# 获取箭头方向
direction = detect_arrow_direction(img)
# 在图像上添加方向文本
cv2.putText(output, f"Direction: {direction}", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 如果提供了保存路径,保存结果图像
if save_path:
cv2.imwrite(save_path, output)
# 创建一个包含所有图像的窗口
result = np.hstack((img, green_only, output))
# 调整大小以便查看
scale_percent = 50 # 缩放到原来的50%
width = int(result.shape[1] * scale_percent / 100)
height = int(result.shape[0] * scale_percent / 100)
dim = (width, height)
resized = cv2.resize(result, dim, interpolation=cv2.INTER_AREA)
# 显示结果
cv2.imshow('Arrow Detection Process', resized)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 用法示例
if __name__ == "__main__":
# 替换为实际图像路径
image_path = "path/to/arrow/image.png"
# 检测箭头方向
direction = detect_arrow_direction(image_path)
print(f"检测到的箭头方向: {direction}")
# 可视化检测过程
visualize_arrow_detection(image_path)