✨ 删除测试文件并更新箭头检测功能,增强可视化和调试信息输出。更新参数以支持观察模式和延迟展示,改进箭头方向检测算法。
							
								
								
									
										13
									
								
								res/arrows/test/arrow_detection_report.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,13 @@
 | 
			
		||||
箭头方向检测 - 测试报告
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
测试日期: 2025-05-13 23:48:36
 | 
			
		||||
测试图像总数: 8
 | 
			
		||||
 | 
			
		||||
总体准确率: 100.00%
 | 
			
		||||
各方向准确率:
 | 
			
		||||
  - left: 100.00%
 | 
			
		||||
  - right: 100.00%
 | 
			
		||||
 | 
			
		||||
平均处理时间: 5.30 毫秒
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 106 KiB  | 
							
								
								
									
										9
									
								
								res/arrows/test/arrow_detection_results.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,9 @@
 | 
			
		||||
图像文件,真实方向,检测方向,是否正确,处理时间(秒),结果文件
 | 
			
		||||
image-1.png,left,left,True,0.00851130485534668,left_image-1_result.jpg
 | 
			
		||||
image-3.png,left,left,True,0.007372140884399414,left_image-3_result.jpg
 | 
			
		||||
image-2.png,left,left,True,0.006041288375854492,left_image-2_result.jpg
 | 
			
		||||
image-5.png,left,left,True,0.002747058868408203,left_image-5_result.jpg
 | 
			
		||||
image-4.png,left,left,True,0.006627082824707031,left_image-4_result.jpg
 | 
			
		||||
image-1.png,right,right,True,0.003347158432006836,right_image-1_result.jpg
 | 
			
		||||
image-3.png,right,right,True,0.004812955856323242,right_image-3_result.jpg
 | 
			
		||||
image-2.png,right,right,True,0.002933979034423828,right_image-2_result.jpg
 | 
			
		||||
		
		
			
  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/arrow_detection_stats.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 18 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/left_image-1_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 102 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/left_image-2_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 102 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/left_image-3_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 106 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/left_image-4_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 105 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/left_image-5_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 106 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/right_image-1_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 104 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/right_image-2_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 99 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								res/arrows/test/right_image-3_result.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 104 KiB  | 
							
								
								
									
										197
									
								
								test/task-arrow/batch_test_arrow.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,197 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import cv2
 | 
			
		||||
import argparse
 | 
			
		||||
import time
 | 
			
		||||
from tqdm import tqdm
 | 
			
		||||
import pandas as pd
 | 
			
		||||
import matplotlib.pyplot as plt
 | 
			
		||||
import matplotlib as mpl
 | 
			
		||||
 | 
			
		||||
# 设置中文字体支持
 | 
			
		||||
plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei', 'sans-serif']
 | 
			
		||||
plt.rcParams['axes.unicode_minus'] = False
 | 
			
		||||
 | 
			
		||||
# 添加项目根目录到路径
 | 
			
		||||
current_dir = os.path.dirname(os.path.abspath(__file__))
 | 
			
		||||
project_root = os.path.dirname(os.path.dirname(current_dir))
 | 
			
		||||
sys.path.append(project_root)
 | 
			
		||||
 | 
			
		||||
from utils.decode_arrow import detect_arrow_direction, visualize_arrow_detection
 | 
			
		||||
 | 
			
		||||
def batch_test_arrows(data_dir="res/arrows", save_dir="res/arrows/test", show_results=False):
 | 
			
		||||
    """
 | 
			
		||||
    批量测试箭头方向检测算法
 | 
			
		||||
    
 | 
			
		||||
    参数:
 | 
			
		||||
        data_dir: 包含箭头图像的目录
 | 
			
		||||
        save_dir: 保存结果的目录
 | 
			
		||||
        show_results: 是否显示结果
 | 
			
		||||
    
 | 
			
		||||
    返回:
 | 
			
		||||
        results_df: 包含测试结果的DataFrame
 | 
			
		||||
    """
 | 
			
		||||
    # 确保保存目录存在
 | 
			
		||||
    os.makedirs(save_dir, exist_ok=True)
 | 
			
		||||
    
 | 
			
		||||
    # 保存结果的列表
 | 
			
		||||
    results = []
 | 
			
		||||
    
 | 
			
		||||
    # 处理左右箭头子目录
 | 
			
		||||
    for direction in ["left", "right"]:
 | 
			
		||||
        dir_path = os.path.join(data_dir, direction)
 | 
			
		||||
        if not os.path.exists(dir_path):
 | 
			
		||||
            print(f"警告: 目录 '{dir_path}' 不存在")
 | 
			
		||||
            continue
 | 
			
		||||
            
 | 
			
		||||
        # 获取该方向的所有图像文件
 | 
			
		||||
        image_files = [f for f in os.listdir(dir_path) if f.endswith(('.png', '.jpg', '.jpeg'))]
 | 
			
		||||
        
 | 
			
		||||
        print(f"处理 {direction} 方向的 {len(image_files)} 个图像...")
 | 
			
		||||
        
 | 
			
		||||
        # 处理每个图像
 | 
			
		||||
        for img_file in tqdm(image_files):
 | 
			
		||||
            img_path = os.path.join(dir_path, img_file)
 | 
			
		||||
            
 | 
			
		||||
            # 读取图像
 | 
			
		||||
            img = cv2.imread(img_path)
 | 
			
		||||
            if img is None:
 | 
			
		||||
                print(f"错误: 无法加载图像 '{img_path}'")
 | 
			
		||||
                continue
 | 
			
		||||
            
 | 
			
		||||
            # 开始计时
 | 
			
		||||
            start_time = time.time()
 | 
			
		||||
            
 | 
			
		||||
            # 检测箭头方向
 | 
			
		||||
            detected_direction = detect_arrow_direction(img)
 | 
			
		||||
            
 | 
			
		||||
            # 结束计时
 | 
			
		||||
            end_time = time.time()
 | 
			
		||||
            processing_time = end_time - start_time
 | 
			
		||||
            
 | 
			
		||||
            # 确定检测是否正确
 | 
			
		||||
            is_correct = detected_direction == direction
 | 
			
		||||
            
 | 
			
		||||
            # 保存可视化结果
 | 
			
		||||
            result_filename = f"{direction}_{img_file.split('.')[0]}_result.jpg"
 | 
			
		||||
            result_path = os.path.join(save_dir, result_filename)
 | 
			
		||||
            # visualize_arrow_detection(img, result_path)
 | 
			
		||||
            
 | 
			
		||||
            # 保存结果
 | 
			
		||||
            results.append({
 | 
			
		||||
                "图像文件": img_file,
 | 
			
		||||
                "真实方向": direction,
 | 
			
		||||
                "检测方向": detected_direction,
 | 
			
		||||
                "是否正确": is_correct,
 | 
			
		||||
                "处理时间(秒)": processing_time,
 | 
			
		||||
                "结果文件": result_filename
 | 
			
		||||
            })
 | 
			
		||||
    
 | 
			
		||||
    # 创建结果DataFrame
 | 
			
		||||
    results_df = pd.DataFrame(results)
 | 
			
		||||
    
 | 
			
		||||
    # 保存结果到CSV
 | 
			
		||||
    csv_path = os.path.join(save_dir, "arrow_detection_results.csv")
 | 
			
		||||
    results_df.to_csv(csv_path, index=False, encoding='utf-8-sig')
 | 
			
		||||
    
 | 
			
		||||
    # 生成统计报告
 | 
			
		||||
    generate_report(results_df, save_dir)
 | 
			
		||||
    
 | 
			
		||||
    return results_df
 | 
			
		||||
 | 
			
		||||
def generate_report(results_df, save_dir):
 | 
			
		||||
    """生成统计报告和可视化"""
 | 
			
		||||
    # 计算总体准确率
 | 
			
		||||
    accuracy = results_df["是否正确"].mean() * 100
 | 
			
		||||
    
 | 
			
		||||
    # 按箭头方向分组计算准确率
 | 
			
		||||
    direction_accuracy = results_df.groupby("真实方向")["是否正确"].mean() * 100
 | 
			
		||||
    
 | 
			
		||||
    # 计算平均处理时间
 | 
			
		||||
    avg_time = results_df["处理时间(秒)"].mean() * 1000  # 转换为毫秒
 | 
			
		||||
    
 | 
			
		||||
    # 创建报告文件
 | 
			
		||||
    report_path = os.path.join(save_dir, "arrow_detection_report.txt")
 | 
			
		||||
    
 | 
			
		||||
    with open(report_path, "w", encoding="utf-8") as f:
 | 
			
		||||
        f.write("箭头方向检测 - 测试报告\n")
 | 
			
		||||
        f.write("=======================\n\n")
 | 
			
		||||
        f.write(f"测试日期: {time.strftime('%Y-%m-%d %H:%M:%S')}\n")
 | 
			
		||||
        f.write(f"测试图像总数: {len(results_df)}\n\n")
 | 
			
		||||
        f.write(f"总体准确率: {accuracy:.2f}%\n")
 | 
			
		||||
        f.write("各方向准确率:\n")
 | 
			
		||||
        for direction, acc in direction_accuracy.items():
 | 
			
		||||
            f.write(f"  - {direction}: {acc:.2f}%\n")
 | 
			
		||||
        f.write(f"\n平均处理时间: {avg_time:.2f} 毫秒\n\n")
 | 
			
		||||
        
 | 
			
		||||
        # 错误案例分析
 | 
			
		||||
        if not results_df["是否正确"].all():
 | 
			
		||||
            f.write("错误检测案例:\n")
 | 
			
		||||
            error_cases = results_df[~results_df["是否正确"]]
 | 
			
		||||
            for _, row in error_cases.iterrows():
 | 
			
		||||
                f.write(f"  - 文件: {row['图像文件']}, 真实方向: {row['真实方向']}, 错误检测为: {row['检测方向']}\n")
 | 
			
		||||
    
 | 
			
		||||
    # 创建可视化图表
 | 
			
		||||
    plt.figure(figsize=(12, 6))
 | 
			
		||||
    
 | 
			
		||||
    # 准确率条形图
 | 
			
		||||
    plt.subplot(1, 2, 1)
 | 
			
		||||
    # 将中文索引转为英文避免字体问题
 | 
			
		||||
    direction_accuracy_en = direction_accuracy.copy()
 | 
			
		||||
    direction_accuracy_en.index = direction_accuracy.index.map(lambda x: "Left" if x == "left" else "Right")
 | 
			
		||||
    direction_accuracy_en.plot(kind='bar', color=['blue', 'green'])
 | 
			
		||||
    plt.title('各方向检测准确率')
 | 
			
		||||
    plt.ylabel('准确率 (%)')
 | 
			
		||||
    plt.ylim(0, 100)
 | 
			
		||||
    plt.grid(True, linestyle='--', alpha=0.7)
 | 
			
		||||
    
 | 
			
		||||
    # 处理时间箱线图
 | 
			
		||||
    plt.subplot(1, 2, 2)
 | 
			
		||||
    # 将中文列名改为英文再制图,避免字体问题
 | 
			
		||||
    temp_df = results_df.copy()
 | 
			
		||||
    temp_df.rename(columns={"处理时间(秒)": "processing_time", "真实方向": "direction"}, inplace=True)
 | 
			
		||||
    temp_df.boxplot(column=['processing_time'], by='direction')
 | 
			
		||||
    plt.title('处理时间分布')
 | 
			
		||||
    plt.ylabel('时间 (秒)')
 | 
			
		||||
    plt.suptitle('')
 | 
			
		||||
    
 | 
			
		||||
    # 保存图表
 | 
			
		||||
    plt.tight_layout()
 | 
			
		||||
    plt.savefig(os.path.join(save_dir, "arrow_detection_stats.png"))
 | 
			
		||||
    
 | 
			
		||||
    print(f"测试报告已保存到: {report_path}")
 | 
			
		||||
    print(f"统计图表已保存到: {os.path.join(save_dir, 'arrow_detection_stats.png')}")
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    # 创建参数解析器
 | 
			
		||||
    parser = argparse.ArgumentParser(description='箭头方向检测批量测试')
 | 
			
		||||
    parser.add_argument('--data-dir', default="res/arrows",
 | 
			
		||||
                       help='箭头图像数据目录 (默认: res/arrows)')
 | 
			
		||||
    parser.add_argument('--save-dir', default="res/arrows/test",
 | 
			
		||||
                       help='保存结果的目录 (默认: res/arrows/test)')
 | 
			
		||||
    parser.add_argument('--show', action='store_true',
 | 
			
		||||
                       help='显示结果图像')
 | 
			
		||||
    
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    
 | 
			
		||||
    # 运行批量测试
 | 
			
		||||
    results = batch_test_arrows(args.data_dir, args.save_dir, args.show)
 | 
			
		||||
    
 | 
			
		||||
    # 输出总体结果
 | 
			
		||||
    correct = results["是否正确"].sum()
 | 
			
		||||
    total = len(results)
 | 
			
		||||
    print(f"\n测试完成! 总共测试了 {total} 张图像,正确检测了 {correct} 张")
 | 
			
		||||
    print(f"总体准确率: {(correct/total*100):.2f}%")
 | 
			
		||||
    
 | 
			
		||||
    # 按真实方向打印准确率
 | 
			
		||||
    for direction in ["left", "right"]:
 | 
			
		||||
        dir_results = results[results["真实方向"] == direction]
 | 
			
		||||
        if len(dir_results) > 0:
 | 
			
		||||
            dir_correct = dir_results["是否正确"].sum()
 | 
			
		||||
            dir_total = len(dir_results)
 | 
			
		||||
            print(f"{direction} 方向准确率: {(dir_correct/dir_total*100):.2f}% ({dir_correct}/{dir_total})")
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main() 
 | 
			
		||||
@ -1,22 +1,31 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import cv2
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import cv2
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
# 添加父目录到路径,以便能够导入utils
 | 
			
		||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 | 
			
		||||
# 添加项目根目录到路径
 | 
			
		||||
current_dir = os.path.dirname(os.path.abspath(__file__))
 | 
			
		||||
project_root = os.path.dirname(os.path.dirname(current_dir))
 | 
			
		||||
sys.path.append(project_root)
 | 
			
		||||
 | 
			
		||||
from utils.decode_arrow import detect_arrow_direction, visualize_arrow_detection
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    # 检查命令行参数
 | 
			
		||||
    if len(sys.argv) < 2:
 | 
			
		||||
        print("使用方法: python test_arrow.py <图像路径>")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    # 创建参数解析器
 | 
			
		||||
    parser = argparse.ArgumentParser(description='箭头方向检测测试')
 | 
			
		||||
    parser.add_argument('--image', default="res/arrows/left/image-3.png", 
 | 
			
		||||
                        help='图像文件路径 (默认: image_20250511_121219.png)')
 | 
			
		||||
    parser.add_argument('--save', default="res/arrows/test/arrow_detection_result.jpg",
 | 
			
		||||
                        help='保存可视化结果的路径 (默认: res/arrows/test/arrow_detection_result.jpg)')
 | 
			
		||||
    parser.add_argument('--show', action='store_true',
 | 
			
		||||
                        help='显示可视化结果')
 | 
			
		||||
    
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    
 | 
			
		||||
    # 获取图像路径
 | 
			
		||||
    image_path = sys.argv[1]
 | 
			
		||||
    image_path = args.image
 | 
			
		||||
    
 | 
			
		||||
    # 检查文件是否存在
 | 
			
		||||
    if not os.path.exists(image_path):
 | 
			
		||||
@ -25,12 +34,31 @@ def main():
 | 
			
		||||
    
 | 
			
		||||
    print(f"正在处理图像: {image_path}")
 | 
			
		||||
    
 | 
			
		||||
    # 检测箭头方向
 | 
			
		||||
    direction = detect_arrow_direction(image_path)
 | 
			
		||||
    print(f"检测到的箭头方向: {direction}")
 | 
			
		||||
    # 加载图像
 | 
			
		||||
    img = cv2.imread(image_path)
 | 
			
		||||
    if img is None:
 | 
			
		||||
        print(f"错误: 无法加载图像 '{image_path}'")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    
 | 
			
		||||
    # 可视化检测过程
 | 
			
		||||
    visualize_arrow_detection(image_path)
 | 
			
		||||
    try:
 | 
			
		||||
        # 检测箭头方向
 | 
			
		||||
        direction = detect_arrow_direction(img, observe=True)
 | 
			
		||||
        print(f"检测到的箭头方向: {direction}")
 | 
			
		||||
        
 | 
			
		||||
        # 可视化检测过程并保存结果
 | 
			
		||||
        visualize_arrow_detection(img, args.save)
 | 
			
		||||
        
 | 
			
		||||
        print(f"可视化结果已保存到: {args.save}")
 | 
			
		||||
        
 | 
			
		||||
        # 如果需要显示结果,等待用户按键
 | 
			
		||||
        print("按任意键退出...")
 | 
			
		||||
        cv2.waitKey(0)
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        print(f"发生错误: {e}")
 | 
			
		||||
    finally:
 | 
			
		||||
        cv2.destroyAllWindows()
 | 
			
		||||
    
 | 
			
		||||
    return direction
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main() 
 | 
			
		||||
    main()
 | 
			
		||||
@ -1,57 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
# 添加父目录到路径,以便能够导入utils
 | 
			
		||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 | 
			
		||||
 | 
			
		||||
from utils.decode_arrow import detect_arrow_direction, visualize_arrow_detection
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    # 创建参数解析器
 | 
			
		||||
    parser = argparse.ArgumentParser(description='测试箭头方向检测')
 | 
			
		||||
    parser.add_argument('image_path', help='图像文件路径')
 | 
			
		||||
    parser.add_argument('--save', help='保存可视化结果的路径', default=None)
 | 
			
		||||
    parser.add_argument('--show', help='显示可视化结果', action='store_true')
 | 
			
		||||
    parser.add_argument('--debug', help='输出详细的调试信息', action='store_true')
 | 
			
		||||
    
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    
 | 
			
		||||
    # 检查文件是否存在
 | 
			
		||||
    if not os.path.exists(args.image_path):
 | 
			
		||||
        print(f"错误: 文件 '{args.image_path}' 不存在")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    
 | 
			
		||||
    print(f"正在处理图像: {args.image_path}")
 | 
			
		||||
    
 | 
			
		||||
    # 加载图像
 | 
			
		||||
    img = cv2.imread(args.image_path)
 | 
			
		||||
    if img is None:
 | 
			
		||||
        print(f"错误: 无法加载图像 '{args.image_path}'")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    
 | 
			
		||||
    # 如果需要,显示原始图像
 | 
			
		||||
    if args.debug:
 | 
			
		||||
        cv2.imshow('Original Image', img)
 | 
			
		||||
        cv2.waitKey(0)
 | 
			
		||||
    
 | 
			
		||||
    # 检测箭头方向
 | 
			
		||||
    direction = detect_arrow_direction(img)
 | 
			
		||||
    print(f"检测到的箭头方向: {direction}")
 | 
			
		||||
    
 | 
			
		||||
    # 如果需要,显示可视化结果
 | 
			
		||||
    if args.show or args.save:
 | 
			
		||||
        visualize_arrow_detection(img, args.save)
 | 
			
		||||
    
 | 
			
		||||
    # 如果不需要显示可视化结果但需要保存
 | 
			
		||||
    if args.save and not args.show:
 | 
			
		||||
        print(f"可视化结果已保存到: {args.save}")
 | 
			
		||||
    
 | 
			
		||||
    return direction
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main() 
 | 
			
		||||
@ -1,61 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import cv2
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
# 添加项目根目录到路径
 | 
			
		||||
current_dir = os.path.dirname(os.path.abspath(__file__))
 | 
			
		||||
project_root = os.path.dirname(os.path.dirname(current_dir))
 | 
			
		||||
sys.path.append(project_root)
 | 
			
		||||
 | 
			
		||||
from utils.decode_arrow import detect_arrow_direction, visualize_arrow_detection
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    # 创建参数解析器
 | 
			
		||||
    parser = argparse.ArgumentParser(description='箭头方向检测测试')
 | 
			
		||||
    parser.add_argument('--image', default="res/arrows/left/image-2.png", 
 | 
			
		||||
                        help='图像文件路径 (默认: image_20250511_121219.png)')
 | 
			
		||||
    parser.add_argument('--save', default="res/arrows/test/arrow_detection_result.jpg",
 | 
			
		||||
                        help='保存可视化结果的路径 (默认: res/arrows/test/arrow_detection_result.jpg)')
 | 
			
		||||
    parser.add_argument('--show', action='store_true',
 | 
			
		||||
                        help='显示可视化结果')
 | 
			
		||||
    
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
    
 | 
			
		||||
    # 获取图像路径
 | 
			
		||||
    image_path = args.image
 | 
			
		||||
    
 | 
			
		||||
    # 检查文件是否存在
 | 
			
		||||
    if not os.path.exists(image_path):
 | 
			
		||||
        print(f"错误: 文件 '{image_path}' 不存在")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    
 | 
			
		||||
    print(f"正在处理图像: {image_path}")
 | 
			
		||||
    
 | 
			
		||||
    # 加载图像
 | 
			
		||||
    img = cv2.imread(image_path)
 | 
			
		||||
    if img is None:
 | 
			
		||||
        print(f"错误: 无法加载图像 '{image_path}'")
 | 
			
		||||
        sys.exit(1)
 | 
			
		||||
    
 | 
			
		||||
    # 检测箭头方向
 | 
			
		||||
    direction = detect_arrow_direction(img)
 | 
			
		||||
    print(f"检测到的箭头方向: {direction}")
 | 
			
		||||
    
 | 
			
		||||
    # 可视化检测过程并保存结果
 | 
			
		||||
    visualize_arrow_detection(img, args.save)
 | 
			
		||||
    
 | 
			
		||||
    print(f"可视化结果已保存到: {args.save}")
 | 
			
		||||
    
 | 
			
		||||
    # 如果需要显示结果,等待用户按键
 | 
			
		||||
    if args.show:
 | 
			
		||||
        print("按任意键退出...")
 | 
			
		||||
        cv2.waitKey(0)
 | 
			
		||||
        cv2.destroyAllWindows()
 | 
			
		||||
    
 | 
			
		||||
    return direction
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
@ -1,12 +1,14 @@
 | 
			
		||||
import cv2
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
def detect_arrow_direction(image):
 | 
			
		||||
def detect_arrow_direction(image, observe=False, delay=500):
 | 
			
		||||
    """
 | 
			
		||||
    从图像中提取绿色箭头并判断其指向方向(左或右)
 | 
			
		||||
    
 | 
			
		||||
    参数:
 | 
			
		||||
        image: 输入图像,可以是文件路径或者已加载的图像数组
 | 
			
		||||
        observe: 是否输出中间状态信息和可视化结果,默认为False
 | 
			
		||||
        delay: 展示每个步骤的等待时间(毫秒),默认为500ms
 | 
			
		||||
        
 | 
			
		||||
    返回:
 | 
			
		||||
        direction: 字符串,"left"表示左箭头,"right"表示右箭头,"unknown"表示无法确定
 | 
			
		||||
@ -21,9 +23,19 @@ def detect_arrow_direction(image):
 | 
			
		||||
        print("无法加载图像")
 | 
			
		||||
        return "unknown"
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤1: 原始图像已加载")
 | 
			
		||||
        cv2.imshow("原始图像", img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 转换到HSV颜色空间以便更容易提取绿色
 | 
			
		||||
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤2: 转换到HSV颜色空间")
 | 
			
		||||
        cv2.imshow("HSV图像", hsv)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 绿色的HSV范围
 | 
			
		||||
    # 调整这些值以匹配图像中绿色的具体色调··
 | 
			
		||||
    lower_green = np.array([40, 50, 50])
 | 
			
		||||
@ -32,9 +44,19 @@ def detect_arrow_direction(image):
 | 
			
		||||
    # 创建绿色的掩码
 | 
			
		||||
    mask = cv2.inRange(hsv, lower_green, upper_green)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤3: 创建绿色掩码")
 | 
			
		||||
        cv2.imshow("绿色掩码", mask)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 应用掩码,只保留绿色部分
 | 
			
		||||
    green_only = cv2.bitwise_and(img, img, mask=mask)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤4: 提取绿色部分")
 | 
			
		||||
        cv2.imshow("只保留绿色", green_only)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 将掩码转为灰度图
 | 
			
		||||
    gray = mask.copy()
 | 
			
		||||
    
 | 
			
		||||
@ -43,13 +65,91 @@ def detect_arrow_direction(image):
 | 
			
		||||
    
 | 
			
		||||
    # 如果没有找到轮廓,返回未知
 | 
			
		||||
    if not contours:
 | 
			
		||||
        if observe:
 | 
			
		||||
            print("未找到轮廓")
 | 
			
		||||
        return "unknown"
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"步骤5: 找到 {len(contours)} 个轮廓")
 | 
			
		||||
        contour_img = img.copy()
 | 
			
		||||
        cv2.drawContours(contour_img, contours, -1, (0, 255, 0), 2)
 | 
			
		||||
        cv2.imshow("所有轮廓", contour_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 找到最大的轮廓(假设是箭头)
 | 
			
		||||
    max_contour = max(contours, key=cv2.contourArea)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤6: 提取最大轮廓")
 | 
			
		||||
        max_contour_img = img.copy()
 | 
			
		||||
        cv2.drawContours(max_contour_img, [max_contour], -1, (0, 0, 255), 2)
 | 
			
		||||
        cv2.imshow("最大轮廓", max_contour_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 使用多边形近似轮廓
 | 
			
		||||
    epsilon = 0.02 * cv2.arcLength(max_contour, True)
 | 
			
		||||
    approx = cv2.approxPolyDP(max_contour, epsilon, True)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"步骤7: 多边形近似,顶点数: {len(approx)}")
 | 
			
		||||
        approx_img = img.copy()
 | 
			
		||||
        cv2.drawContours(approx_img, [approx], -1, (255, 0, 0), 2)
 | 
			
		||||
        cv2.imshow("多边形近似", approx_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 计算凸包
 | 
			
		||||
    hull = cv2.convexHull(max_contour)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤8: 计算凸包")
 | 
			
		||||
        hull_img = img.copy()
 | 
			
		||||
        cv2.drawContours(hull_img, [hull], -1, (0, 255, 0), 2)
 | 
			
		||||
        cv2.imshow("凸包", hull_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 计算凸缺陷
 | 
			
		||||
    if len(max_contour) > 3:
 | 
			
		||||
        defects = cv2.convexityDefects(max_contour, cv2.convexHull(max_contour, returnPoints=False))
 | 
			
		||||
    else:
 | 
			
		||||
        if observe:
 | 
			
		||||
            print("轮廓点太少,无法准确判断")
 | 
			
		||||
        return "unknown"  # 轮廓点太少,无法准确判断
 | 
			
		||||
    
 | 
			
		||||
    if defects is None:
 | 
			
		||||
        if observe:
 | 
			
		||||
            print("未找到凸缺陷")
 | 
			
		||||
        return "unknown"
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"步骤9: 计算凸缺陷,找到 {defects.shape[0]} 个缺陷点")
 | 
			
		||||
        defect_img = img.copy()
 | 
			
		||||
        for i in range(defects.shape[0]):
 | 
			
		||||
            s, e, f, d = defects[i, 0]
 | 
			
		||||
            start = tuple(max_contour[s][0])
 | 
			
		||||
            end = tuple(max_contour[e][0])
 | 
			
		||||
            far = tuple(max_contour[f][0])
 | 
			
		||||
            cv2.circle(defect_img, far, 5, (0, 0, 255), -1)
 | 
			
		||||
        cv2.imshow("凸缺陷", defect_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
        
 | 
			
		||||
    # 获取轮廓的最小外接矩形
 | 
			
		||||
    x, y, w, h = cv2.boundingRect(max_contour)
 | 
			
		||||
    rect = cv2.minAreaRect(max_contour)
 | 
			
		||||
    box = cv2.boxPoints(rect)
 | 
			
		||||
    box = np.int0(box)
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("步骤10: 获取最小外接矩形")
 | 
			
		||||
        rect_img = img.copy()
 | 
			
		||||
        cv2.drawContours(rect_img, [box], 0, (255, 0, 0), 2)
 | 
			
		||||
        cv2.imshow("最小外接矩形", rect_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 获取中心点和角度
 | 
			
		||||
    center = rect[0]
 | 
			
		||||
    angle = rect[2]
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"矩形中心: {center}, 角度: {angle}")
 | 
			
		||||
    
 | 
			
		||||
    # 计算轮廓的矩,用于确定箭头方向
 | 
			
		||||
    M = cv2.moments(max_contour)
 | 
			
		||||
@ -59,35 +159,159 @@ def detect_arrow_direction(image):
 | 
			
		||||
        cx = int(M["m10"] / M["m00"])
 | 
			
		||||
        cy = int(M["m01"] / M["m00"])
 | 
			
		||||
    else:
 | 
			
		||||
        cx, cy = x + w//2, y + h//2
 | 
			
		||||
        cx, cy = int(center[0]), int(center[1])
 | 
			
		||||
    
 | 
			
		||||
    # 将图像分为左右两部分
 | 
			
		||||
    left_region = gray[y:y+h, x:cx]
 | 
			
		||||
    right_region = gray[y:y+h, cx:x+w]
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"步骤11: 计算质心 - 坐标: ({cx}, {cy})")
 | 
			
		||||
        center_img = img.copy()
 | 
			
		||||
        cv2.circle(center_img, (cx, cy), 5, (255, 0, 0), -1)
 | 
			
		||||
        cv2.imshow("质心", center_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 计算每个区域中白色像素的数量(箭头部分)
 | 
			
		||||
    left_pixels = cv2.countNonZero(left_region)
 | 
			
		||||
    right_pixels = cv2.countNonZero(right_region)
 | 
			
		||||
    # 改进的箭头尖端检测算法
 | 
			
		||||
    # 1. 找到所有凸缺陷点
 | 
			
		||||
    defect_points = []
 | 
			
		||||
    for i in range(defects.shape[0]):
 | 
			
		||||
        s, e, f, d = defects[i, 0]
 | 
			
		||||
        start = tuple(max_contour[s][0])
 | 
			
		||||
        end = tuple(max_contour[e][0])
 | 
			
		||||
        far = tuple(max_contour[f][0])
 | 
			
		||||
        
 | 
			
		||||
        # 计算缺陷点到中心的距离
 | 
			
		||||
        dist = np.sqrt((far[0] - cx) ** 2 + (far[1] - cy) ** 2)
 | 
			
		||||
        
 | 
			
		||||
        if observe:
 | 
			
		||||
            print(f"缺陷点 {i}: 位置 {far}, 到中心距离: {dist:.2f}")
 | 
			
		||||
        
 | 
			
		||||
        # 记录凸缺陷点及其距离
 | 
			
		||||
        defect_points.append({
 | 
			
		||||
            'point': far,
 | 
			
		||||
            'distance': dist,
 | 
			
		||||
            'start': start,
 | 
			
		||||
            'end': end
 | 
			
		||||
        })
 | 
			
		||||
    
 | 
			
		||||
    # 计算每个区域中白色像素的密度
 | 
			
		||||
    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"
 | 
			
		||||
    # 没有缺陷点,使用矩形判断
 | 
			
		||||
    if not defect_points:
 | 
			
		||||
        # 判断逻辑将在后面处理
 | 
			
		||||
        arrow_tip = None
 | 
			
		||||
    else:
 | 
			
		||||
        return "left"
 | 
			
		||||
        # 2. 按距离对缺陷点排序
 | 
			
		||||
        defect_points.sort(key=lambda x: x['distance'], reverse=True)
 | 
			
		||||
        
 | 
			
		||||
        # 3. 获取最远的几个缺陷点(可能的尖端候选)
 | 
			
		||||
        top_n = min(3, len(defect_points))
 | 
			
		||||
        candidates = defect_points[:top_n]
 | 
			
		||||
        
 | 
			
		||||
        # 4. 分析这些点的位置分布
 | 
			
		||||
        left_candidates = [p for p in candidates if p['point'][0] < cx]
 | 
			
		||||
        right_candidates = [p for p in candidates if p['point'][0] >= cx]
 | 
			
		||||
        
 | 
			
		||||
        # 5. 根据候选点的分布判断箭头朝向
 | 
			
		||||
        if len(left_candidates) > len(right_candidates):
 | 
			
		||||
            # 左侧候选点更多,箭头可能指向左边
 | 
			
		||||
            arrow_tip = max(left_candidates, key=lambda x: x['distance'])['point']
 | 
			
		||||
            arrow_direction = "left"
 | 
			
		||||
        elif len(right_candidates) > len(left_candidates):
 | 
			
		||||
            # 右侧候选点更多,箭头可能指向右边
 | 
			
		||||
            arrow_tip = max(right_candidates, key=lambda x: x['distance'])['point']
 | 
			
		||||
            arrow_direction = "right"
 | 
			
		||||
        else:
 | 
			
		||||
            # 候选点分布均衡,使用最远的点
 | 
			
		||||
            arrow_tip = candidates[0]['point']
 | 
			
		||||
            # 根据最远点的位置判断
 | 
			
		||||
            if arrow_tip[0] < cx:
 | 
			
		||||
                arrow_direction = "left"
 | 
			
		||||
            else:
 | 
			
		||||
                arrow_direction = "right"
 | 
			
		||||
    
 | 
			
		||||
    if observe and arrow_tip:
 | 
			
		||||
        print(f"步骤12: 找到可能的箭头尖端 - 位置: {arrow_tip}")
 | 
			
		||||
        tip_img = img.copy()
 | 
			
		||||
        cv2.circle(tip_img, arrow_tip, 8, (0, 255, 255), -1)
 | 
			
		||||
        cv2.line(tip_img, (cx, cy), arrow_tip, (255, 0, 255), 2)
 | 
			
		||||
        cv2.imshow("箭头尖端", tip_img)
 | 
			
		||||
        cv2.waitKey(delay)
 | 
			
		||||
    
 | 
			
		||||
    # 使用多种特征综合判断箭头方向
 | 
			
		||||
    if arrow_tip is None:
 | 
			
		||||
        # 如果没有找到明显的箭头尖端,使用最小外接矩形来判断
 | 
			
		||||
        width = rect[1][0]
 | 
			
		||||
        height = rect[1][1]
 | 
			
		||||
        
 | 
			
		||||
        if observe:
 | 
			
		||||
            print(f"未找到明显尖端,使用矩形判断 - 宽: {width}, 高: {height}")
 | 
			
		||||
        
 | 
			
		||||
        # 矩形的方向向量
 | 
			
		||||
        if width > height:  # 水平箭头
 | 
			
		||||
            # 考虑角度的定义
 | 
			
		||||
            if angle > 45:
 | 
			
		||||
                arrow_direction = "left"
 | 
			
		||||
            else:
 | 
			
		||||
                arrow_direction = "right"
 | 
			
		||||
        else:  # 垂直箭头,不在我们的考虑范围内
 | 
			
		||||
            if observe:
 | 
			
		||||
                print("垂直箭头,不在考虑范围")
 | 
			
		||||
            return "unknown"
 | 
			
		||||
    else:
 | 
			
		||||
        # 已经在上面的代码中确定了方向
 | 
			
		||||
        pass
 | 
			
		||||
    
 | 
			
		||||
    # 附加检查:计算轮廓边界上的点,确认箭头的形状特征
 | 
			
		||||
    x, y, w, h = cv2.boundingRect(max_contour)
 | 
			
		||||
    aspect_ratio = float(w) / h
 | 
			
		||||
    
 | 
			
		||||
    # 计算轮廓周长和面积
 | 
			
		||||
    perimeter = cv2.arcLength(max_contour, True)
 | 
			
		||||
    area = cv2.contourArea(max_contour)
 | 
			
		||||
    
 | 
			
		||||
    # 计算轮廓的形状复杂度
 | 
			
		||||
    complexity = perimeter / (4 * np.sqrt(area))
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"轮廓分析 - 宽高比: {aspect_ratio:.2f}, 复杂度: {complexity:.2f}")
 | 
			
		||||
    
 | 
			
		||||
    # 箭头形状特征检查
 | 
			
		||||
    # 一般来说,箭头的复杂度会在一定范围内
 | 
			
		||||
    if 1.1 < complexity < 3.0:
 | 
			
		||||
        # 根据形状特征进一步确认方向判断
 | 
			
		||||
        # 使用质心位置相对于轮廓边界的偏移
 | 
			
		||||
        relative_cx = (cx - x) / w
 | 
			
		||||
        
 | 
			
		||||
        if observe:
 | 
			
		||||
            print(f"质心相对位置: {relative_cx:.2f}")
 | 
			
		||||
        
 | 
			
		||||
        # 如果质心偏向左侧,箭头可能指向右侧
 | 
			
		||||
        # 如果质心偏向右侧,箭头可能指向左侧
 | 
			
		||||
        # 这是一个启发式规则,可能需要根据具体箭头形状调整
 | 
			
		||||
        if relative_cx < 0.4:
 | 
			
		||||
            # 质心在左侧,可能是右箭头
 | 
			
		||||
            if arrow_direction == "left":
 | 
			
		||||
                # 当前方法判断为左,但质心位置特征表明可能是右
 | 
			
		||||
                # 增加额外的检查
 | 
			
		||||
                if aspect_ratio > 1.5:  # 宽大于高
 | 
			
		||||
                    arrow_direction = "right"
 | 
			
		||||
        elif relative_cx > 0.6:
 | 
			
		||||
            # 质心在右侧,可能是左箭头
 | 
			
		||||
            if arrow_direction == "right":
 | 
			
		||||
                # 当前方法判断为右,但质心位置特征表明可能是左
 | 
			
		||||
                if aspect_ratio > 1.5:  # 宽大于高
 | 
			
		||||
                    arrow_direction = "left"
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print(f"基于综合特征判断: {arrow_direction}箭头")
 | 
			
		||||
    
 | 
			
		||||
    return arrow_direction
 | 
			
		||||
 | 
			
		||||
def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
def visualize_arrow_detection(image, save_path=None, observe=False, delay=500):
 | 
			
		||||
    """
 | 
			
		||||
    可视化箭头检测过程,显示中间结果
 | 
			
		||||
    
 | 
			
		||||
    参数:
 | 
			
		||||
        image: 输入图像,可以是文件路径或者已加载的图像数组
 | 
			
		||||
        save_path: 保存结果图像的路径(可选)
 | 
			
		||||
        observe: 是否输出中间状态信息和可视化结果,默认为False
 | 
			
		||||
        delay: 展示每个步骤的等待时间(毫秒),默认为500ms
 | 
			
		||||
    """
 | 
			
		||||
    # 如果输入是字符串(文件路径),则加载图像
 | 
			
		||||
    if isinstance(image, str):
 | 
			
		||||
@ -99,6 +323,9 @@ def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
        print("无法加载图像")
 | 
			
		||||
        return
 | 
			
		||||
    
 | 
			
		||||
    if observe:
 | 
			
		||||
        print("\n开始可视化箭头检测过程")
 | 
			
		||||
    
 | 
			
		||||
    # 转换到HSV颜色空间
 | 
			
		||||
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
 | 
			
		||||
    
 | 
			
		||||
@ -124,8 +351,10 @@ def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
        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)
 | 
			
		||||
        rect = cv2.minAreaRect(max_contour)
 | 
			
		||||
        box = cv2.boxPoints(rect)
 | 
			
		||||
        box = np.int0(box)
 | 
			
		||||
        cv2.drawContours(output, [box], 0, (255, 0, 0), 2)
 | 
			
		||||
        
 | 
			
		||||
        # 计算轮廓的矩
 | 
			
		||||
        M = cv2.moments(max_contour)
 | 
			
		||||
@ -137,12 +366,24 @@ def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
            
 | 
			
		||||
            # 绘制中心点
 | 
			
		||||
            cv2.circle(output, (cx, cy), 5, (255, 0, 0), -1)
 | 
			
		||||
            
 | 
			
		||||
            # 绘制分割线
 | 
			
		||||
            cv2.line(output, (cx, y), (cx, y + h), (0, 255, 255), 2)
 | 
			
		||||
        
 | 
			
		||||
        # 绘制凸包
 | 
			
		||||
        hull = cv2.convexHull(max_contour)
 | 
			
		||||
        cv2.drawContours(output, [hull], 0, (0, 255, 0), 2)
 | 
			
		||||
        
 | 
			
		||||
        # 绘制凸缺陷
 | 
			
		||||
        if len(max_contour) > 3:
 | 
			
		||||
            defects = cv2.convexityDefects(max_contour, cv2.convexHull(max_contour, returnPoints=False))
 | 
			
		||||
            if defects is not None:
 | 
			
		||||
                for i in range(defects.shape[0]):
 | 
			
		||||
                    s, e, f, d = defects[i, 0]
 | 
			
		||||
                    start = tuple(max_contour[s][0])
 | 
			
		||||
                    end = tuple(max_contour[e][0])
 | 
			
		||||
                    far = tuple(max_contour[f][0])
 | 
			
		||||
                    cv2.circle(output, far, 5, (0, 0, 255), -1)  # 在凸缺陷点绘制红色圆点
 | 
			
		||||
    
 | 
			
		||||
    # 获取箭头方向
 | 
			
		||||
    direction = detect_arrow_direction(img)
 | 
			
		||||
    direction = detect_arrow_direction(img, observe=observe, delay=delay)
 | 
			
		||||
    
 | 
			
		||||
    # 在图像上添加方向文本
 | 
			
		||||
    cv2.putText(output, f"Direction: {direction}", (10, 30), 
 | 
			
		||||
@ -151,6 +392,8 @@ def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
    # 如果提供了保存路径,保存结果图像
 | 
			
		||||
    if save_path:
 | 
			
		||||
        cv2.imwrite(save_path, output)
 | 
			
		||||
        if observe:
 | 
			
		||||
            print(f"结果已保存到: {save_path}")
 | 
			
		||||
    
 | 
			
		||||
    # 创建一个包含所有图像的窗口
 | 
			
		||||
    result = np.hstack((img, green_only, output))
 | 
			
		||||
@ -163,18 +406,18 @@ def visualize_arrow_detection(image, save_path=None):
 | 
			
		||||
    resized = cv2.resize(result, dim, interpolation=cv2.INTER_AREA)
 | 
			
		||||
    
 | 
			
		||||
    # 显示结果
 | 
			
		||||
    # cv2.imshow('Arrow Detection Process', resized)
 | 
			
		||||
    # cv2.waitKey(0)
 | 
			
		||||
    # cv2.destroyAllWindows()
 | 
			
		||||
    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)
 | 
			
		||||
    # 检测箭头方向,使用较长的延迟时间(1500毫秒)
 | 
			
		||||
    direction = detect_arrow_direction(image_path, observe=True, delay=1500)
 | 
			
		||||
    print(f"检测到的箭头方向: {direction}")
 | 
			
		||||
    
 | 
			
		||||
    # 可视化检测过程
 | 
			
		||||
    visualize_arrow_detection(image_path)
 | 
			
		||||
    # 可视化检测过程,使用较长的延迟时间
 | 
			
		||||
    visualize_arrow_detection(image_path, observe=True, delay=1500)
 | 
			
		||||
 | 
			
		||||