庐山派K230识别矩形,想设置一个动态roi,但一直会爆内存,请帮我看一下 :(

Viewed 70

重现步骤

立创·庐山派-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()去掉就不会爆内存了

补充材料

1 Answers