问题描述
帧率一般接近20,但是图像识别不稳定,识别很慢
硬件板卡
canMV-K230-LP4 V3.0
软件版本
CanMV_K230_LP4_V3.0_micropython_1.5_nncase_v2.110
其他信息
import time
import os
import sys
import math
from media.sensor import *
from media.display import *
sensor = None
1. 计算两条直线的角度差 (0~180度)
def angle_diff(a1, a2):
diff = abs(a1 - a2) % 180
return min(diff, 180 - diff)
2. 计算两条直线的几何交点
def get_line_intersection(line1, line2):
x1, y1, x2, y2 = line1.line()
x3, y3, x4, y4 = line2.line()
denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
if abs(denom) < 1e-5:
return None # 平行线无交点
px = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom
py = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom
return (int(px), int(py))
3. 检查交点有效性
def is_valid_point(pt, rect, padding=12):
if not pt:
return False
rx, ry, rw, rh = rect
x, y = pt
return (rx - padding <= x <= rx + rw + padding) and (ry - padding <= y <= ry + rh + padding)
4. 计算两点间距离(边长)
def point_dist(p1, p2):
return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
5. 计算直线中点
def get_line_midpoint(line):
x1, y1, x2, y2 = line.line()
return ((x1 + x2) / 2, (y1 + y2) / 2)
6. 从同一方向的线段中,挑选出距离最远的两条(即平行四边形相对的两条边)
def get_farthest_pair(lines_list):
if len(lines_list) < 2:
return None
max_d = -1
best_pair = None
for i in range(len(lines_list)):
for j in range(i + 1, len(lines_list)):
m1 = get_line_midpoint(lines_list[i])
m2 = get_line_midpoint(lines_list[j])
dist = math.sqrt((m1[0] - m2[0])**2 + (m1[1] - m2[1])**2)
if dist > max_d:
max_d = dist
best_pair = (lines_list[i], lines_list[j])
if max_d > 8: # 间距必须大于 8 像素
return best_pair
return None
try:
print("--- 启动高精度平行四边形识别程序 ---")
sensor = Sensor(width=320, height=320)
sensor.reset()
sensor.set_framesize(width=320, height=320)
sensor.set_pixformat(Sensor.RGB565)
Display.init(Display.LT9611, to_ide=True)
MediaManager.init()
sensor.run()
# 手机白屏黑图案专属灰度阈值
TARGET_THRESHOLD = [(0, 115)]
while True:
os.exitpoint()
img = sensor.snapshot(chn=CAM_CHN_ID_0)
gray = img.to_grayscale()
# 查找黑色色块 (兼容远距离小目标)
blobs = gray.find_blobs(TARGET_THRESHOLD, area_threshold=80, merge=True)
for blob in blobs:
img.draw_rectangle(blob.rect(), color=(255, 0, 0), thickness=2)
img.draw_cross(blob.cx(), blob.cy(), color=(255, 0, 0))
for blob in blobs:
area = blob.pixels()
w, h = blob.w(), blob.h()
perimeter = blob.perimeter()
if w * h == 0:
continue
extent = area / (w * h)
compactness = (perimeter * perimeter) / area if area > 0 else 0
# 1. 四边形轮廓初筛 (矩形/平行四边形填充率通常在 0.30~0.95,Compactness 在 14~45)
if (0.30 <= extent <= 0.95) and (14.0 <= compactness <= 45.0):
# 2. 在色块区域提取直线
raw_lines = gray.find_lines(roi=blob.rect(), threshold=300, x_stride=2, y_stride=2)
# 3. 将直线按角度归类为 2 个主要方向组 (方向1 与 方向2 夹角大于 20 度)
group1 = []
group2 = []
for l in raw_lines:
ang = l.theta()
if not group1:
group1.append(l)
elif all(angle_diff(ang, gl.theta()) < 20 for gl in group1):
group1.append(l)
elif not group2 and all(angle_diff(ang, gl.theta()) > 20 for gl in group1):
group2.append(l)
elif group2 and all(angle_diff(ang, gl.theta()) < 20 for gl in group2):
group2.append(l)
# 4. 从每个方向组中提取最外侧的两条对边线
pair1 = get_farthest_pair(group1)
pair2 = get_farthest_pair(group2)
if pair1 and pair2:
LA1, LA2 = pair1 # 方向 1 的两条对边
LB1, LB2 = pair2 # 方向 2 的两条对边
# 5. 两两求交,获得顺次连接的 4 个顶点
p1 = get_line_intersection(LA1, LB1)
p2 = get_line_intersection(LB1, LA2)
p3 = get_line_intersection(LA2, LB2)
p4 = get_line_intersection(LB2, LA1)
# 6. 校验 4 个交点是否有效
if (is_valid_point(p1, blob.rect()) and
is_valid_point(p2, blob.rect()) and
is_valid_point(p3, blob.rect()) and
is_valid_point(p4, blob.rect())):
# 计算 4 条边长
d12 = point_dist(p1, p2)
d23 = point_dist(p2, p3)
d34 = point_dist(p3, p4)
d41 = point_dist(p4, p1)
# 7. 平行四边形几何校验:对边长度必须近似相等 (误差 < 35%)
diff_opp1 = abs(d12 - d34) / max(d12, d34)
diff_opp2 = abs(d23 - d41) / max(d23, d41)
if diff_opp1 < 0.35 and diff_opp2 < 0.35 and min(d12, d23, d34, d41) > 5:
# --- 判定成功:开始绘制 ---
# A. 绘制 4 条绿线边框
img.draw_line(p1[0], p1[1], p2[0], p2[1], color=(0, 255, 0), thickness=2)
img.draw_line(p2[0], p2[1], p3[0], p3[1], color=(0, 255, 0), thickness=2)
img.draw_line(p3[0], p3[1], p4[0], p4[1], color=(0, 255, 0), thickness=2)
img.draw_line(p4[0], p4[1], p1[0], p1[1], color=(0, 255, 0), thickness=2)
# B. 绘制 4 个顶点红点
img.draw_circle(p1[0], p1[1], 3, color=(255, 0, 0), fill=True)
img.draw_circle(p2[0], p2[1], 3, color=(255, 0, 0), fill=True)
img.draw_circle(p3[0], p3[1], 3, color=(255, 0, 0), fill=True)
img.draw_circle(p4[0], p4[1], 3, color=(255, 0, 0), fill=True)
# C. 标注 4 条边的边长 (黄字)
m12 = ((p1[0] + p2[0]) // 2, (p1[1] + p2[1]) // 2)
m23 = ((p2[0] + p3[0]) // 2, (p2[1] + p3[1]) // 2)
m34 = ((p3[0] + p4[0]) // 2, (p3[1] + p4[1]) // 2)
m41 = ((p4[0] + p1[0]) // 2, (p4[1] + p1[1]) // 2)
img.draw_string(m12[0], m12[1], str(int(d12)), color=(255, 255, 0), scale=2)
img.draw_string(m23[0], m23[1], str(int(d23)), color=(255, 255, 0), scale=2)
img.draw_string(m34[0], m34[1], str(int(d34)), color=(255, 255, 0), scale=2)
img.draw_string(m41[0], m41[1], str(int(d41)), color=(255, 255, 0), scale=2)
# D. 精准计算中心坐标 (4 个顶点的中心)
cx = (p1[0] + p2[0] + p3[0] + p4[0]) // 4
cy = (p1[1] + p2[1] + p3[1] + p4[1]) // 4
# 中心标记:紫色十字 + 白点 + 坐标文本
img.draw_cross(cx, cy, color=(255, 0, 255), size=6, thickness=2)
img.draw_circle(cx, cy, 2, color=(255, 255, 255), fill=True)
img.draw_string(cx + 8, cy - 8, f"({cx},{cy})", color=(255, 255, 255), scale=1)
img.compressed_for_ide()
Display.show_image(img)
except Exception as e:
print("运行出错:", e)
finally:
if isinstance(sensor, Sensor):
sensor.stop()
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
MediaManager.deinit()
k230已经有cv加速的相关函数和固件了,怎么不试试,在传统识别上速度提升明显