问题描述
我想通过官方的矩形识别例程来实现稳定识别矩形,用于获得偏移量操作电机。我写了一个简单的动态roi变化,但是一旦运行时间稍微长一些或者标靶离远,就会出现反复丢失检测然后重新计算roi的情况,这时候就会爆内存。问题大概率出在else中频繁的roi修改。请问各位有任何关于追踪上一次识别位置的方法吗?
from machine import UART
from machine import FPIOA
import time
import _thread
import time, os, sys
from libs.PipeLine import PipeLine
from libs.YOLO import YOLO11
from libs.Utils import *
from media.sensor import *
from media.display import *
import os, sys, gc
import ulab.numpy as np
import image
import time
from machine import TOUCH
import utime
import machine
import time, utime
from machine import Pin, UART
import ustruct
import math
import time
import os
import sys
import gc
from media.sensor import *
from media.display import *
from media.media import *
from time import ticks_ms
sensor = None
# ----------------------------------------------------------
# 以下这三个是用于筛选矩形的计算函数
def calculate_area(corner):
"""计算四边形面积"""
# corner 是 (4, 2) 的坐标数组
area = 0.0
n = len(corner)
for i in range(n):
x1, y1 = corner[i]
x2, y2 = corner[(i + 1) % n]
area += (x1 * y2) - (x2 * y1)
return abs(area) / 2.0
def calculate_ratio(corner):
"""计算四边形长宽比"""
x_coords = [corner[0][0], corner[1][0], corner[2][0], corner[3][0]]
y_coords = [corner[0][1], corner[1][1], corner[2][1], corner[3][1]]
width = max(x_coords) - min(x_coords)
height = max(y_coords) - min(y_coords)
if height == 0:
return 0
return width / height
def calculate_center(corner):
x_coords = [corner[0][0], corner[1][0], corner[2][0], corner[3][0]]
y_coords = [corner[0][1], corner[1][1], corner[2][1], corner[3][1]]
cx = (min(x_coords) + max(x_coords)) / 2
cy = (min(y_coords) + max(y_coords)) / 2
return cx, cy
def distance(c1, c2):
return ((c1[0] - c2[0])**2 + (c1[1] - c2[1])**2)**0.5
# ------------------------------------------------------------------
# 以下是矩形检测的函数,动态roi用if else实现,当检测到时,roi以margin为距离套在
# 上一次检测到的矩形上
# 初始化全局变量:上次使用的ROI
# 初始化全局变量(调整适应400×240)
last_roi = [50, 20, 300, 180] # 初始ROI也要改小
last_threshold = 12000
first_detect = True
last_area = 8000 # 目标面积也变小了
def rect_detect():
global last_roi, first_detect, last_threshold, last_area, diff_x, diff_y
img = sensor.snapshot(chn=CAM_CHN_ID_0)
img_rect = img.binary([(50, 255)])
rects = img_rect.find_rects(roi=last_roi, threshold=last_threshold)
if rects is not None and len(rects) > 0:
valid_data = []
for rect in rects:
corner = rect.corners()
ratio = calculate_ratio(corner)
area = calculate_area(corner)
if 1.8 > ratio > 1.2 and area > 2000: # 面积下限降低
valid_data.append((rect, corner, area))
if len(valid_data) > 0:
min_diff = float('inf')
best_rect = None
best_corner = None
for rect, corner, area in valid_data:
diff = abs(area - last_area)
if diff < min_diff:
min_diff = diff
best_rect = rect
best_corner = corner
if best_rect is not None:
corner = best_corner
last_area = calculate_area(corner)
x_coords = [corner[0][0], corner[1][0], corner[2][0], corner[3][0]]
y_coords = [corner[0][1], corner[1][1], corner[2][1], corner[3][1]]
cx = int((min(x_coords) + max(x_coords)) / 2)
cy = int((min(y_coords) + max(y_coords)) / 2)
diff_x = cx - 200 # 中心点改成200,120
diff_y = 120 - cy
img.draw_circle(cx, cy, 10, color=(0, 255, 0), thickness=5)
print(last_roi)
if first_detect:
first_detect = False
margin = 25 # margin也适当减小
roi_x = min(x_coords) - margin
roi_y = min(y_coords) - margin
roi_w = (max(x_coords) - min(x_coords)) + 2 * margin
roi_h = (max(y_coords) - min(y_coords)) + 2 * margin
roi_x = max(0, roi_x)
roi_y = max(0, roi_y)
roi_w = max(80, min(400, roi_w)) # 最大宽度改成300
roi_h = max(60, min(240, roi_h)) # 最大高度改成180
roi_w = min(600 - roi_x, roi_w) # 边界检查改成400
roi_h = min(300 - roi_y, roi_h) # 边界检查改成240
last_roi = [roi_x, roi_y, roi_w, roi_h]
last_threshold = int(8000 * (roi_w * roi_h) / (200 * 150)) # 调整基准面积
last_threshold = max(5000, min(20000, last_threshold)) # 调整阈值范围
else:
last_roi[2] = min(600, int(last_roi[2] * 1.1))
last_roi[3] = min(300, int(last_roi[3] * 1.1))
last_roi[0] = max(0, (400 - last_roi[2]) // 2)
last_roi[1] = max(0, (240 - last_roi[3]) // 2)
else:
last_roi[2] = min(600, int(last_roi[2] * 1.1))
last_roi[3] = min(300, int(last_roi[3] * 1.1))
last_roi[0] = max(0, (400 - last_roi[2]) // 2)
last_roi[1] = max(0, (240 - last_roi[3]) // 2)
img.draw_circle(200, 120, 10, color=(245, 135, 235), thickness=3) # 中心点改成200,120
img.draw_string_advanced(300, 40, 30, "th:{}".format(last_threshold), color=(255, 0, 0))
img.draw_string_advanced(50, 40, 30, "fps: {}".format(clock.fps()), color=(255, 0, 0))
img.draw_rectangle(last_roi[0], last_roi[1], last_roi[2], last_roi[3], (255, 0, 0), 5, False)
Display.show_image(img)
# ------------------------------------------------------------------------
try:
gc.collect()
print("camera_test")
sensor = Sensor(width=1920,height=1080)
sensor.reset()
sensor.set_framesize(width=400,height=240)
sensor.set_pixformat(Sensor.RGB565)
Display.init(Display.ST7701, to_ide=True)
MediaManager.init() # 初始化媒体管理器
# 启动 sensor
sensor.run()
clock = time.clock()
while True:
clock.tick()
os.exitpoint()
rect_detect()
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()
'''
## 复现步骤
----------
执行函数
## 硬件板卡
----------
庐山派
## 软件版本
----------
CanMV_K230_LCKFB_micropython_v1.3-0-g8dd764f_nncase_v2.9.0
## 其他信息
----------
我尝试过降低摄像头分辨率到720p,限制sensor到30帧,都还是会出现这个问题:(