
什么是 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
图像采集 → 双算法检测 → 几何验证 → 等边分类 → 去重排序 → 可视化输出
- 双算法融合架构
python
def find_triangles_optimized(img):
triangles1 = find_triangles_from_contours(img) # 轮廓检测
triangles2 = find_triangles_from_blobs(img) # 区域检测
双重检测策略:
轮廓检测:基于形状边界的精确几何检测
Blob检测:基于区域特征的快速区域检测
优势互补:提高不同场景下的检测成功率
核心技术组件详解
- 几何验证系统
等边三角形验证算法
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°(避免过于尖锐)
面积计算:使用向量叉积法精确计算
- 双检测算法实现
轮廓检测方法
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角点中选择最佳三点组合
质量评分:基于面积选择最优三角形
- 数学计算核心
距离计算
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
基于向量叉积的三角形面积公式
准确且计算高效
性能优化策略
- 多级过滤机制
text
原始候选 → 几何验证 → 等边分类 → 中心点去重 → 面积排序 → 数量限制 - 智能参数配置
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
- 图像采集 → 2. 双算法并行检测 → 3. 几何验证 →
- 等边分类 → 5. 去重排序 → 6. 可视化渲染 → 7. 结果显示
实验串口返回情况

实验场景图




8931

被折叠的 条评论
为什么被折叠?



