【花雕动手做】CanMV K230 AI 视觉识别模块之优化的三角形检测算法

在这里插入图片描述

什么是 CanMV K230?
CanMV K230是一款高性价比的RISC-V边缘AI平台,凭借低功耗、强视觉处理能力和开放的开发生态,成为嵌入式AI开发的理想选择,尤其适合需要快速部署视觉与AI功能的创客、中小企业及教育场景。CanMV 是一套 AI 视觉开发平台,K230 是其核心芯片。该模块结合了图像采集、AI推理、边缘计算等能力,适合嵌入式视觉应用开发。

CanMV:类似 OpenMV 的图像处理框架,支持 Python 编程,简化视觉识别开发流程。
K230 芯片:嘉楠科技推出的 AIoT SoC,采用 RISC-V 架构,内置第三代 KPU(AI加速单元),算力高达 6 TOPS,性能是 K210 的 13.7 倍。

在这里插入图片描述
在这里插入图片描述
知识点
三角形检测是计算机视觉中基于多边形拟合的经典任务,核心是从图像中识别满足 “三边闭合、内角和 180°” 几何特征的区域,通过 “轮廓提取 + 多边形逼近 + 几何验证” 实现,适配零件检测、路标识别等场景。

1、核心原理
三角形的核心特征是 “边数为 3 且闭合”,检测逻辑与矩形检测同源,关键步骤:
图像预处理:降噪、边缘检测(如 Canny),突出目标轮廓。
轮廓提取:找到图像中的连续像素区域(前景目标)。
多边形逼近:用approxPolyDP算法将轮廓简化为多边形,保留核心形状。
几何验证:筛选边数 = 3 的多边形,再验证三边长度匹配、内角和接近 180°,排除非三角形(如不规则三边形)。

2、主流算法(按场景适配)

在这里插入图片描述

3、实操示例(OpenCV 轮廓逼近实现)
适配 K230 摄像头实时采集,代码简洁可直接移植:
python
import cv2
import numpy as np

def is_triangle(approx):
“”“验证多边形是否为三角形:边数3+内角和接近180°”“”
if len(approx) != 3:
return False

# 计算三边向量
vec1 = approx[1][0] - approx[0][0]
vec2 = approx[2][0] - approx[1][0]
vec3 = approx[0][0] - approx[2][0]

# 计算三个内角(余弦定理)
def angle(vec_a, vec_b):
    dot = np.dot(vec_a, vec_b)
    norm_a = np.linalg.norm(vec_a)
    norm_b = np.linalg.norm(vec_b)
    if norm_a == 0 or norm_b == 0:
        return 0
    cos_ang = max(-1.0, min(1.0, dot/(norm_a*norm_b)))
    return np.degrees(np.arccos(cos_ang))

ang1 = angle(vec1, -vec3)  # 第一个内角
ang2 = angle(vec2, -vec1)  # 第二个内角
ang3 = angle(vec3, -vec2)  # 第三个内角
total_ang = ang1 + ang2 + ang3

# 内角和在170°~190°之间(允许轻微偏差)
return 170 < total_ang < 190

初始化K230摄像头

cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

if not cap.isOpened():
print(“摄像头打开失败”)
exit()

while True:
ret, frame = cap.read()
if not ret:
break
img_copy = frame.copy()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

# 预处理:降噪+边缘检测
blur = cv2.GaussianBlur(gray, (5, 5), 0)
canny = cv2.Canny(blur, 50, 150)

# 提取轮廓(只保留外部轮廓)
contours, _ = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 筛选三角形轮廓
for cnt in contours:
    # 过滤小面积噪声
    if cv2.contourArea(cnt) < 500:
        continue
    # 多边形逼近(epsilon控制精度)
    epsilon = 0.03 * cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, epsilon, True)
    # 验证是否为三角形
    if is_triangle(approx):
        # 绘制三角形(绿色边框+蓝色顶点)
        cv2.drawContours(img_copy, [approx], -1, (0, 255, 0), 2)
        for (x, y) in approx[:, 0]:
            cv2.circle(img_copy, (x, y), 4, (255, 0, 0), -1)
        # 标注内角和
        cv2.putText(img_copy, f"Ang: {ang1+ang2+ang3:.1f}", (approx[0][0][0], approx[0][0][1]-10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)

cv2.imshow("Triangle Detection", img_copy)
if cv2.waitKey(1) == ord('q'):
    break

cap.release()
cv2.destroyAllWindows()

4、关键优化技巧(提升准确率)
预处理强化:
复杂背景用阈值分割(如二值化、自适应阈值),分离前景三角形。
用形态学操作(膨胀 + 腐蚀)修复断裂轮廓,增强边缘连续性。
参数调优:
轮廓逼近:epsilon设为轮廓长度的 0.02~0.04 倍,避免将三角形逼近为四边形。
面积阈值:根据目标大小调整(640x480 图像设为 500~2000 像素),过滤小噪声。
内角验证:放宽内角和范围至 170°~190°,适配轻微变形的三角形。
后处理去重:合并重叠或嵌套的三角形检测结果,保留面积最大的有效轮廓。

5、K230 平台适配:
用 NPU 加速 Canny 边缘检测和轮廓提取,CPU 专注多边形逼近和几何验证,单帧延迟 < 80ms。
针对 MIPI 摄像头采集的图像,通过 ISP 调整白平衡,避免因光照导致的轮廓模糊。

6、典型应用场景
工业质检:检测三角形状的零件(如三角支架、齿轮齿形)是否合格。
智能交通:识别三角形交通标志(如警告标志),辅助自动驾驶决策。
机器人视觉:定位三角形目标(如积木、零件),规划抓取路径。
文档识别:提取图纸中的三角形图形,实现工程图纸结构化分析。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

【花雕动手做】CanMV K230 AI 视觉识别模块之优化的三角形检测算法
项目测试实验代码

#【花雕动手做】CanMV K230 AI 视觉识别模块之检测三角形

# 优化的三角形检测算法 / Optimized Triangle Detection Algorithm
# 专门针对黑色实心三角形在白色背景上的检测 / Specifically for black solid triangles on white background

import time, os, sys, math
from media.sensor import *
from media.display import *
from media.media import *

# 图像分辨率设置 / Image resolution settings
PICTURE_WIDTH = 640  # 降低分辨率提高帧率 / Lower resolution for better FPS
PICTURE_HEIGHT = 480

# 摄像头配置 / Camera configuration
sensor = None

# 显示模式选择 / Display mode selection
DISPLAY_MODE = "LCD"

# 绘制控制参数 / Drawing control parameters
DRAW_GENERAL_TRIANGLES = False  # 是否绘制普通三角形(绿色)/ Whether to draw general triangles (green)

# 根据显示模式设置分辨率 / Set resolution based on display mode
if DISPLAY_MODE == "VIRT":
    DISPLAY_WIDTH = ALIGN_UP(1920, 16)
    DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
    DISPLAY_WIDTH = 640
    DISPLAY_HEIGHT = 480
else:
    raise ValueError("Unknown DISPLAY_MODE, please select 'VIRT', 'LCD'")

# 创建时钟对象用于FPS计算 / Create clock object for FPS calculation
clock = time.clock()

def distance(p1, p2):
    """计算两点间距离 / Calculate distance between two points"""
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

def calculate_angle(p1, p2, p3):
    """计算三点构成的角度 / Calculate angle formed by three points"""
    try:
        # 向量 p2->p1 和 p2->p3 / Vectors p2->p1 and p2->p3
        v1 = (p1[0] - p2[0], p1[1] - p2[1])
        v2 = (p3[0] - p2[0], p3[1] - p2[1])

        # 计算向量长度 / Calculate vector lengths
        len1 = math.sqrt(v1[0]**2 + v1[1]**2)
        len2 = math.sqrt(v2[0]**2 + v2[1]**2)

        if len1 == 0 or len2 == 0:
            return 0

        # 计算夹角余弦值 / Calculate cosine of the angle
        cos_angle = (v1[0]*v2[0] + v1[1]*v2[1]) / (len1 * len2)
        cos_angle = max(-1, min(1, cos_angle))  # 限制在[-1,1]范围内 / Clamp to [-1,1] range

        # 转换为角度 / Convert to degrees
        angle = math.acos(cos_angle) * 180 / math.pi
        return angle
    except:
        return 0

def is_equilateral_triangle(corners, side_tolerance=0.2, angle_tolerance=20):
    """
    判断三个角点是否构成等边三角形 / Check if three corners form an equilateral triangle

    参数 / Parameters:
        corners: 三个角点的坐标列表 / List of three corner coordinates
        side_tolerance: 边长相对误差容忍度 / Side length relative tolerance (0.15 = 15%)
        angle_tolerance: 角度误差容忍度 / Angle tolerance in degrees

    返回 / Returns:
        bool: 是否为等边三角形 / Whether it's an equilateral triangle
    """
    if len(corners) != 3:
        return False

    # 计算三边长度 / Calculate three side lengths
    side1 = distance(corners[0], corners[1])
    side2 = distance(corners[1], corners[2])
    side3 = distance(corners[2], corners[0])

    # 检查边长是否过小 / Check if sides are too small
    if side1 < 10 or side2 < 10 or side3 < 10:
        return False

    # 方法1: 检查三边长度是否相等(允许相对误差)/ Method 1: Check if three sides are equal (with relative tolerance)
    avg_side = (side1 + side2 + side3) / 3
    side1_diff = abs(side1 - avg_side) / avg_side
    side2_diff = abs(side2 - avg_side) / avg_side
    side3_diff = abs(side3 - avg_side) / avg_side

    sides_equal = (side1_diff <= side_tolerance and
                   side2_diff <= side_tolerance and
                   side3_diff <= side_tolerance)

    # 方法2: 检查三个内角是否都接近60度 / Method 2: Check if three angles are close to 60 degrees
    angle1 = calculate_angle(corners[0], corners[1], corners[2])
    angle2 = calculate_angle(corners[1], corners[2], corners[0])
    angle3 = calculate_angle(corners[2], corners[0], corners[1])

    angles_equal = (abs(angle1 - 60) <= angle_tolerance and
                    abs(angle2 - 60) <= angle_tolerance and
                    abs(angle3 - 60) <= angle_tolerance)

    # 两种方法都满足才认为是等边三角形 / Both methods must be satisfied
    return sides_equal and angles_equal

def is_valid_triangle(corners, min_area=100, max_area=10000, angle_tolerance=20):
    """
    判断三个角点是否构成有效三角形 / Check if three corners form a valid triangle

    参数 / Parameters:
        corners: 三个角点的坐标列表 / List of three corner coordinates
        min_area: 最小面积阈值 / Minimum area threshold
        max_area: 最大面积阈值 / Maximum area threshold
        angle_tolerance: 角度容忍度 / Angle tolerance

    返回 / Returns:
        bool: 是否为有效三角形 / Whether it's a valid triangle
    """
    if len(corners) != 3:
        return False

    # 计算三边长度 / Calculate three side lengths
    side1 = distance(corners[0], corners[1])
    side2 = distance(corners[1], corners[2])
    side3 = distance(corners[2], corners[0])

    # 计算面积 / Calculate area using cross product
    area = abs((corners[1][0] - corners[0][0]) * (corners[2][1] - corners[0][1]) -
               (corners[2][0] - corners[0][0]) * (corners[1][1] - corners[0][1])) / 2

    # 计算三个内角 / Calculate three interior angles
    angle1 = calculate_angle(corners[0], corners[1], corners[2])
    angle2 = calculate_angle(corners[1], corners[2], corners[0])
    angle3 = calculate_angle(corners[2], corners[0], corners[1])

    # 检查角度是否合理(三角形内角和应该接近180度)/ Check if angles are reasonable
    angle_sum = angle1 + angle2 + angle3
    if abs(angle_sum - 180) > 30:  # 允许一定误差 / Allow some error
        return False

    # 检查是否有过小的角度 / Check for too small angles
    if angle1 < 20 or angle2 < 20 or angle3 < 20:
        return False

    return True

def find_triangles_from_contours(img):
    """
    使用轮廓检测寻找三角形 / Find triangles using contour detection

    参数 / Parameters:
        img: 输入图像 / Input image

    返回 / Returns:
        list: 检测到的三角形列表 / List of detected triangles
    """
    triangles = []

    try:
        # 转换为灰度图像进行边缘检测 / Convert to grayscale for edge detection
        img_gray = img.to_grayscale()

        # 使用自适应阈值进行二值化 / Use adaptive threshold for binarization
        # 针对黑色三角形,使用反向阈值 / For black triangles, use inverted threshold
        img_binary = img_gray.binary([(0, 100)], invert=True)  # 检测黑色区域 / Detect black regions

        # 寻找矩形作为候选区域 / Find rectangles as candidate regions
        rects = img_binary.find_rects(threshold=1000, roi=None)

        for rect in rects:
            corners = rect.corners()
            if corners is not None and len(corners) >= 3:
                # 尝试所有可能的三点组合 / Try all possible three-point combinations
                for i in range(len(corners)):
                    for j in range(i+1, len(corners)):
                        for k in range(j+1, len(corners)):
                            triangle_corners = [corners[i], corners[j], corners[k]]
                            if is_valid_triangle(triangle_corners):
                                center = ((triangle_corners[0][0] + triangle_corners[1][0] + triangle_corners[2][0]) // 3,
                                         (triangle_corners[0][1] + triangle_corners[1][1] + triangle_corners[2][1]) // 3)
                                area = abs((triangle_corners[1][0] - triangle_corners[0][0]) *
                                          (triangle_corners[2][1] - triangle_corners[0][1]) -
                                          (triangle_corners[2][0] - triangle_corners[0][0]) *
                                          (triangle_corners[1][1] - triangle_corners[0][1])) / 2

                                # 检查是否为等边三角形 / Check if it's an equilateral triangle
                                is_equilateral = is_equilateral_triangle(triangle_corners)

                                triangles.append({
                                    'corners': triangle_corners,
                                    'center': center,
                                    'area': area,
                                    'is_equilateral': is_equilateral,
                                    'type': 'equilateral' if is_equilateral else 'general'
                                })
                                break
    except Exception as e:
        pass

    return triangles

def find_triangles_from_blobs(img):
    """
    使用blob检测寻找三角形 / Find triangles using blob detection

    参数 / Parameters:
        img: 输入图像 / Input image

    返回 / Returns:
        list: 检测到的三角形列表 / List of detected triangles
    """
    triangles = []

    try:
        # 检测黑色blob / Detect black blobs
        blobs = img.find_blobs([(0, 50, -128, 127, -128, 127)],
                              pixels_threshold=200,
                              area_threshold=500,
                              merge=True)

        for blob in blobs:
            # 获取blob的边界框 / Get blob bounding box
            x, y, w, h = blob.rect()

            # 检查长宽比是否合理 / Check if aspect ratio is reasonable
            aspect_ratio = max(w, h) / min(w, h)
            if aspect_ratio > 3:  # 过于细长的形状可能不是三角形 / Too elongated shape may not be triangle
                continue

            # 使用blob的角点信息 / Use blob corner information
            if hasattr(blob, 'corners') and callable(blob.corners):
                corners = blob.corners()
                if corners is not None and len(corners) >= 3:
                    # 选择最合适的三个角点 / Select the most suitable three corners
                    best_triangle = None
                    best_score = 0

                    for i in range(len(corners)):
                        for j in range(i+1, len(corners)):
                            for k in range(j+1, len(corners)):
                                triangle_corners = [corners[i], corners[j], corners[k]]
                                if is_valid_triangle(triangle_corners):
                                    # 计算三角形质量分数 / Calculate triangle quality score
                                    area = abs((triangle_corners[1][0] - triangle_corners[0][0]) *
                                             (triangle_corners[2][1] - triangle_corners[0][1]) -
                                             (triangle_corners[2][0] - triangle_corners[0][0]) *
                                             (triangle_corners[1][1] - triangle_corners[0][1])) / 2

                                    # 分数基于面积和形状规整度 / Score based on area and shape regularity
                                    score = area
                                    if score > best_score:
                                        best_score = score
                                        best_triangle = triangle_corners

                    if best_triangle:
                        center = ((best_triangle[0][0] + best_triangle[1][0] + best_triangle[2][0]) // 3,
                                 (best_triangle[0][1] + best_triangle[1][1] + best_triangle[2][1]) // 3)

                        # 检查是否为等边三角形 / Check if it's an equilateral triangle
                        is_equilateral = is_equilateral_triangle(best_triangle)

                        triangles.append({
                            'corners': best_triangle,
                            'center': center,
                            'area': best_score,
                            'is_equilateral': is_equilateral,
                            'type': 'equilateral' if is_equilateral else 'general'
                        })
    except Exception as e:
        print(f"Error in blob detection: {e}")

    return triangles

def find_triangles_optimized(img):
    """
    优化的三角形检测主函数 / Optimized main triangle detection function

    参数 / Parameters:
        img: 输入图像 / Input image

    返回 / Returns:
        list: 检测到的三角形列表 / List of detected triangles
    """
    all_triangles = []

    # 方法1: 轮廓检测 / Method 1: Contour detection
    triangles1 = find_triangles_from_contours(img)
    all_triangles.extend(triangles1)

    # 方法2: Blob检测 / Method 2: Blob detection
    triangles2 = find_triangles_from_blobs(img)
    all_triangles.extend(triangles2)

    # 去重和筛选 / Remove duplicates and filter
    unique_triangles = []
    for triangle in all_triangles:
        is_duplicate = False
        for existing in unique_triangles:
            # 检查中心点距离 / Check center point distance
            center_dist = distance(triangle['center'], existing['center'])
            if center_dist < 20:  # 如果中心点很近,认为是重复的 / If centers are close, consider duplicate
                is_duplicate = True
                break

        if not is_duplicate:
            unique_triangles.append(triangle)

    # 按面积排序,优先返回较大的三角形 / Sort by area, prioritize larger triangles
    unique_triangles.sort(key=lambda x: x['area'], reverse=True)

    return unique_triangles[:5]  # 最多返回5个三角形 / Return at most 5 triangles

def process_triangles(img, triangles):
    """处理检测到的三角形 / Process detected triangles"""
    print("【三角形检测结果 / Triangle Detection Results】")
    equilateral_count = 0
    general_count = 0

    for i, triangle in enumerate(triangles):
        corners = triangle['corners']
        center = triangle['center']
        area = triangle['area']
        is_equilateral = triangle.get('is_equilateral', False)
        triangle_type = triangle.get('type', 'general')

        # 统计三角形类型 / Count triangle types
        if is_equilateral:
            equilateral_count += 1
        else:
            general_count += 1

        # 根据三角形类型和控制参数决定是否绘制 / Draw based on triangle type and control parameters
        should_draw = False
        if is_equilateral:
            should_draw = True
            line_color = (255, 255, 0)  # 黄色表示等边三角形 / Yellow for equilateral triangles
            corner_color = (255, 165, 0)  # 橙色角点 / Orange corner points
            center_color = (255, 0, 255)  # 紫色中心点 / Purple center point
            label = "EQUI"
        elif DRAW_GENERAL_TRIANGLES:
            should_draw = True
            line_color = (0, 255, 0)  # 绿色表示普通三角形 / Green for general triangles
            corner_color = (255, 0, 0)  # 红色角点 / Red corner points
            center_color = (0, 0, 255)  # 蓝色中心点 / Blue center point
            label = "GEN"

        if should_draw:
            # 绘制三角形边框 / Draw triangle outline
            for j in range(3):
                start = corners[j]
                end = corners[(j + 1) % 3]
                img.draw_line(start[0], start[1], end[0], end[1], color=line_color, thickness=2)

            # 绘制角点 / Draw corner points
            for corner in corners:
                img.draw_circle(corner[0], corner[1], 4, color=corner_color, thickness=2)

            # 绘制中心点 / Draw center point
            img.draw_circle(center[0], center[1], 3, color=center_color, thickness=2)

            # 在三角形旁边显示类型标签 / Display type label next to triangle
            img.draw_string_advanced(center[0] + 10, center[1] - 10, 12, label, color=line_color, scale=1)

        # 计算边长 / Calculate side lengths
        side1 = distance(corners[0], corners[1])
        side2 = distance(corners[1], corners[2])
        side3 = distance(corners[2], corners[0])

        # 计算三个内角用于验证 / Calculate three angles for verification
        angle1 = calculate_angle(corners[0], corners[1], corners[2])
        angle2 = calculate_angle(corners[1], corners[2], corners[0])
        angle3 = calculate_angle(corners[2], corners[0], corners[1])

        print(f"Triangle {i+1} ({triangle_type.upper()}): Center({center[0]}, {center[1]}), Area: {area:.1f}")
        print(f"  Corners: {corners}")
        print(f"  Side lengths: {side1:.1f}, {side2:.1f}, {side3:.1f}")
        if is_equilateral:
            print(f"  Angles: {angle1:.1f}°, {angle2:.1f}°, {angle3:.1f}°")
            print(f"  ★ EQUILATERAL TRIANGLE DETECTED! ★")

    print(f"Total triangles found: {len(triangles)} (Equilateral: {equilateral_count}, General: {general_count})")
    print("【==============================】")

try:
    # 初始化摄像头 / Initialize camera
    sensor = Sensor()
    sensor.reset()

    # 设置图像分辨率和格式 / Set image resolution and format
    sensor.set_framesize(width=PICTURE_WIDTH, height=PICTURE_HEIGHT, chn=CAM_CHN_ID_0)
    sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)

    # 初始化显示器 / Initialize display
    if DISPLAY_MODE == "VIRT":
        Display.init(Display.VIRT, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, fps=60)
    elif DISPLAY_MODE == "LCD":
        Display.init(Display.ST7701, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)

    # 初始化媒体管理器 / Initialize media manager
    MediaManager.init()
    sensor.run()

    # 计算显示偏移量以居中显示 / Calculate display offsets for center alignment
    x_offset = (DISPLAY_WIDTH - PICTURE_WIDTH) // 2
    y_offset = (DISPLAY_HEIGHT - PICTURE_HEIGHT) // 2

    print("三角形检测已启动,请将黑色三角形放在白色背景前...")
    print("Triangle detection started, please place black triangles on white background...")

    while True:
        os.exitpoint()
        clock.tick()  # 开始计时 / Start timing

        # 捕获图像 / Capture image
        img = sensor.snapshot(chn=CAM_CHN_ID_0)

        # 寻找三角形 / Find triangles
        triangles = find_triangles_optimized(img)

        # 处理检测到的三角形 / Process detected triangles
        equilateral_count = 0
        general_count = 0
        if len(triangles) > 0:
            process_triangles(img, triangles)
            # 统计等边三角形数量 / Count equilateral triangles
            for triangle in triangles:
                if triangle.get('is_equilateral', False):
                    equilateral_count += 1
                else:
                    general_count += 1

        # 显示FPS / Display FPS
        fps = clock.fps()
        print(f"FPS: {fps:.1f}")

        # 在图像上显示信息 / Display information on image
        img.draw_string_advanced(10, 10, 15, f"FPS: {fps:.1f}", color=(255, 255, 255), scale=2)
        img.draw_string_advanced(10, 30, 15, f"Total: {len(triangles)}", color=(255, 255, 255), scale=2)
        if equilateral_count > 0:
            img.draw_string_advanced(10, 50, 15, f"Equilateral: {equilateral_count}", color=(255, 255, 0), scale=2)
        if general_count > 0 and DRAW_GENERAL_TRIANGLES:
            img.draw_string_advanced(10, 70, 15, f"General: {general_count}", color=(0, 255, 0), scale=2)

        # 居中显示图像 / Display image centered
        Display.show_image(img, x=x_offset, y=y_offset)

except KeyboardInterrupt as e:
    print("User Stop: ", e)
except BaseException as e:
    print(f"Exception: {e}")
finally:
    # 清理资源 / Cleanup resources
    if isinstance(sensor, Sensor):
        sensor.stop()
    Display.deinit()
    os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
    time.sleep_ms(100)
    MediaManager.deinit()

代码解读:
程序总体功能
这是一个基于CanMV K230的高级实时三角形检测与分类系统,专门针对黑色实心三角形在白色背景上的检测,能够区分等边三角形和普通三角形。

系统架构设计
核心处理流程
text
图像采集 → 双算法检测 → 几何验证 → 等边分类 → 去重排序 → 可视化输出

  1. 双算法融合架构
    python
def find_triangles_optimized(img):
    triangles1 = find_triangles_from_contours(img)  # 轮廓检测
    triangles2 = find_triangles_from_blobs(img)     # 区域检测

双重检测策略:
轮廓检测:基于形状边界的精确几何检测
Blob检测:基于区域特征的快速区域检测
优势互补:提高不同场景下的检测成功率

核心技术组件详解

  1. 几何验证系统
    等边三角形验证算法
    python
def is_equilateral_triangle(corners, side_tolerance=0.2, angle_tolerance=20):

双重验证机制:
边长验证:三边长度相对误差 ≤ 20%
python

side1_diff = abs(side1 - avg_side) / avg_side ≤ 0.2

角度验证:三个内角接近60° ± 20°

python

abs(angle1 - 60)20

必须同时满足:确保几何特征的严格性

三角形有效性检查
python

def is_valid_triangle(corners):

有效性标准:
角度和验证:180° ± 30°(三角形基本定理)
最小角度限制:每个角 ≥ 20°(避免过于尖锐)
面积计算:使用向量叉积法精确计算

  1. 双检测算法实现
    轮廓检测方法
    python
def find_triangles_from_contours(img):

处理流程:
灰度转换:img.to_grayscale()
二值化:反向阈值 (0, 100), invert=True 检测黑色区域
矩形检测:find_rects(threshold=1000) 获取候选区域
角点组合:从矩形角点中尝试所有三点组合
几何验证:对每个组合进行三角形验证

Blob检测方法
python

def find_triangles_from_blobs(img):

处理流程:
颜色空间检测:在LAB颜色空间中检测黑色区域
区域过滤:基于像素数、面积、长宽比过滤
角点分析:从blob角点中选择最佳三点组合
质量评分:基于面积选择最优三角形

  1. 数学计算核心
    距离计算
    python
def distance(p1, p2):
    return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)

欧几里得距离公式
用于计算三角形边长

角度计算
python

def calculate_angle(p1, p2, p3):

向量几何方法:
向量构造:v1 = p1→p2, v2 = p3→p2
点积计算:v1·v2 = |v1||v2|cosθ
角度求解:θ = arccos((v1·v2)/(|v1||v2|))

面积计算
python

area = abs((x2-x1)*(y3-y1) - (x3-x1)*(y2-y1)) / 2

基于向量叉积的三角形面积公式
准确且计算高效

性能优化策略

  1. 多级过滤机制
    text
    原始候选 → 几何验证 → 等边分类 → 中心点去重 → 面积排序 → 数量限制
  2. 智能参数配置
    python
# 检测参数
side_tolerance=0.2      # 20%边长误差容忍度
angle_tolerance=20      # 20°角度误差容忍度
pixels_threshold=200    # Blob最小像素数
area_threshold=500      # 最小区域面积

# 显示控制
DRAW_GENERAL_TRIANGLES = False  # 只显示等边三角形,减少视觉干扰
3. 结果优化处理
python
# 去重:基于中心点距离
center_dist = distance(triangle['center'], existing['center']) < 20

# 排序:按面积降序
unique_triangles.sort(key=lambda x: x['area'], reverse=True)

# 限制:最多返回5个
return unique_triangles[:5]

可视化系统设计
颜色编码体系
python

# 等边三角形视觉元素
line_color = (255, 255, 0)      # 黄色边框 - 突出显示
corner_color = (255, 165, 0)    # 橙色角点 - 关键特征
center_color = (255, 0, 255)    # 紫色中心 - 重心位置
label = "EQUI"                  # 类型标识

# 普通三角形视觉元素(可选显示)
line_color = (0, 255, 0)        # 绿色边框
corner_color = (255, 0, 0)      # 红色角点  
center_color = (0, 0, 255)      # 蓝色中心

信息显示层级
python

# 实时性能监控
img.draw_string_advanced(10, 10, 15, f"FPS: {fps:.1f}", color=(255,255,255))

# 检测结果统计
img.draw_string_advanced(10, 30, 15, f"Total: {len(triangles)}", color=(255,255,255))

# 等边三角形计数(突出显示)
img.draw_string_advanced(10, 50, 15, f"Equilateral: {equilateral_count}", color=(255,255,0))

控制台详细输出
text
【三角形检测结果】
Triangle 1 (EQUI): Center(320, 240), Area: 1250.5
Corners: [(300,200), (340,200), (320,280)]
Side lengths: 40.0, 44.7, 44.7
Angles: 60.5°, 59.8°, 59.7°
★ EQUILATERAL TRIANGLE DETECTED! ★

算法工作流程
实时处理流水线
text

  1. 图像采集 → 2. 双算法并行检测 → 3. 几何验证 →
  2. 等边分类 → 5. 去重排序 → 6. 可视化渲染 → 7. 结果显示

实验串口返回情况

在这里插入图片描述

实验场景图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

驴友花雕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值