重现步骤
立创·庐山派-K230-CanMV开发板资料与相关扩展板软硬件资料官网全部开源
开发板官网:www.lckfb.com
技术支持常驻论坛,任何技术问题欢迎随时交流学习
立创论坛:www.jlc-bbs.com/lckfb
关注bilibili账号:【立创开发板】,掌握我们的最新动态!
不靠卖板赚钱,以培养中国工程师为己任
import time, os, sys
from machine import UART
from machine import FPIOA
from media.sensor import *
from media.display import *
from media.media import *
import utime
from machine import Pin
import math
picture_width = 400
picture_height = 240
sensor_id = 2
sensor = None
显示模式选择:可以是 "VIRT"、"LCD" 或 "HDMI"
DISPLAY_MODE = "LCD"
根据模式设置显示宽高
if DISPLAY_MODE == "VIRT":
# 虚拟显示器模式
DISPLAY_WIDTH = ALIGN_UP(1920, 16)
DISPLAY_HEIGHT = 1080
elif DISPLAY_MODE == "LCD":
# 3.1寸屏幕模式
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 480
elif DISPLAY_MODE == "HDMI":
# HDMI扩展板模式
DISPLAY_WIDTH = 1920
DISPLAY_HEIGHT = 1080
else:
raise ValueError("未知的 DISPLAY_MODE,请选择 'VIRT', 'LCD' 或 'HDMI'")
try:
# 构造一个具有默认配置的摄像头对象
sensor = Sensor(id=sensor_id)
# 重置摄像头sensor
sensor.reset()
# 无需进行镜像翻转
# 设置水平镜像
# sensor.set_hmirror(False)
# 设置垂直翻转
# sensor.set_vflip(False)
# 设置通道0的输出尺寸为1920x1080
sensor.set_framesize(width=picture_width, height=picture_height, chn=CAM_CHN_ID_0)
# 设置通道0的输出像素格式为RGB565
sensor.set_pixformat(Sensor.RGB565, chn=CAM_CHN_ID_0)
# 根据模式初始化显示器
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)
elif DISPLAY_MODE == "HDMI":
Display.init(Display.LT9611, width=DISPLAY_WIDTH, height=DISPLAY_HEIGHT, to_ide=True)
# 初始化媒体管理器
MediaManager.init()
# 启动传感器
sensor.run()
clock = utime.clock()
ROI_point = (0,0,picture_width,picture_height)
def intersection(p1, p2, p3, p4):
"""
计算线段 (p1-p2) 与 (p3-p4) 的交点
返回 (ix, iy),若平行则返回 None
"""
x1, y1 = p1
x2, y2 = p2
x3, y3 = p3
x4, y4 = p4
denom = (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)
if abs(denom) < 1e-6: # 平行
return None
t = ((x1 - x3)*(y3 - y4) - (y1 - y3)*(x3 - x4)) / denom
ix = int(x1 + t*(x2 - x1))
iy = int(y1 + t*(y2 - y1))
return (ix, iy)
while True:
os.exitpoint()
clock.tick()
max_area = 0
find_r = []
# 捕获通道0的图像
img = sensor.snapshot(chn=CAM_CHN_ID_0)
img_gray = img.to_grayscale() #转灰度
# 查找线段并绘制
rects = img_gray.find_rects(roi=ROI_point,threshold=5000)
#for r in rects:
# img.draw_rectangle(r.rect(), color=(0, 0, 255), thickness=3)
kgbs = [r for r in rects if 2.0 > float(r.w() / r.h()) > 1.0]
if kgbs:
#for r in kgbs:
# img.draw_rectangle(r.rect(), color=(0, 255, 0), thickness=3)
lixiangs = []
for r in kgbs:
w = max(r.w(), 1)
h = max(r.h(), 1)
x = max(r.x(), 0)
y = max(r.y(), 0)
#img.draw_rectangle(r.rect(), color=(1, 147, 230), thickness=3)
#print(r.rect())
center_x = int(x + w / 2)
center_y = int(y + h / 2)
area = w * h
top_roi = (max(x, 0), max(y, 0), w//5, 10)
top_stati = img.get_statistics(roi=top_roi).mean()
left_roi = (max(x, 0), max(y, 0), 10, h//5)
left_stati = img.get_statistics(roi=left_roi).mean()
center_roi = (max(center_x - 2, 0),
max(center_y - 2, 0),
min(4, picture_width - center_x + 2),
min(4, picture_height - center_y + 2))
center_stati = img.get_statistics(roi=center_roi).mean()
#img.draw_rectangle(top_roi, color=(255, 0, 0), thickness=2)
#img.draw_rectangle(left_roi, color=(255, 0, 0), thickness=2)
#img.draw_rectangle(center_roi, color=(255, 0, 0), thickness=2)
if top_stati < 200:
if left_stati < 200:
if center_stati > 10:
if area > max_area:
find_r = r
max_area = area
else:
ROI_point = (0,0,picture_width,picture_height)
if find_r:
corner = find_r.corners() # 获取矩形的四个顶点
# 假设 pts 是 4 个 (x, y) 元组/列表
pts = list(corner) # 先复制一份,避免改动原数据
# 1. 计算几何中心
cx = sum(p[0] for p in pts) / 4.0
cy = sum(p[1] for p in pts) / 4.0
# 2. 计算极角并按角度升序排序(顺时针)
def angle_key(pt):
return math.atan2(pt[1] - cy, pt[0] - cx)
# 3. 排序(角度小的排在前面)
pts_sorted = sorted(pts, key=angle_key)
# 现在 pts_sorted 就是 左上 -> 右上 -> 右下 -> 左下 的顺序
# 如果想把结果再写回 corner,可以:
#print(pts_sorted)
p0 = pts_sorted[0] # 左上角
p1 = pts_sorted[1] # 右上角
p2 = pts_sorted[2] # 右下角
p3 = pts_sorted[3] # 左下角
ix, iy = intersection(p0, p2, p1, p3)
# 画四条边
img.draw_line(p0[0], p0[1], p1[0], p1[1], color=(0,255,0), thickness=4)
img.draw_line(p1[0], p1[1], p2[0], p2[1], color=(0,255,0), thickness=4)
img.draw_line(p2[0], p2[1], p3[0], p3[1], color=(0,255,0), thickness=4)
img.draw_line(p3[0], p3[1], p0[0], p0[1], color=(0,255,0), thickness=4)
# 画对角线
img.draw_line(p0[0], p0[1], p2[0], p2[1], color=(0,255,255), thickness=4)
img.draw_line(p1[0], p1[1], p3[0], p3[1], color=(0,255,255), thickness=4)
img.draw_cross(ix, iy, size=10, thickness=3)
img.draw_rectangle(find_r.rect(), color=(1, 147, 230), thickness=3)
ROI_point = find_r.rect()
#print(f"Rect {rect}") # 打印线段信息
# 显示捕获的图像,中心对齐,居中显示
img.draw_string_advanced(50, 50, 80, "fps: {}".format(clock.fps()), color=(255, 0, 0))
#img.compressed_for_ide()
Display.show_image(img, x=int((DISPLAY_WIDTH - picture_width) / 2), y=int((DISPLAY_HEIGHT - picture_height) / 2))
except KeyboardInterrupt as e:
print("用户停止: ", e)
except BaseException as e:
print(f"异常: {e}")
finally:
# 停止传感器运行
if isinstance(sensor, Sensor):
sensor.stop()
# 反初始化显示模块
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
# 释放媒体缓冲区
MediaManager.deinit()
期待结果和实际结果
可以实现动态ROI来提高帧数
软硬件版本信息
错误日志
MPY: soft reboot
MicroPython v1.2 on 2024-11-28; k230_canmv_lckfb with K230
find sensor gc2093_csi2, type 24, output 1920x1080@60
buffer pool : 4
sensor(0), mode 0, buffer_num 4, buffer_size 0
异常: Out of fast frame buffer stack memory
MPY: soft reboot
MicroPython v1.2 on 2024-11-28; k230_canmv_lckfb with K230
尝试解决过程
将ROI_point = find_r.rect()去掉就不会爆内存了
补充材料