You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在OpenCV中限制Roboflow模型仅在用户自定义区域推理

解决方案:在OAK设备端实现ROI区域的硬件级裁剪推理

核心思路是利用OAK设备的硬件加速图像裁剪功能,在图像送入模型推理前就只截取用户指定的矩形区域,避免模型处理整帧画面,从根源上提升效率。以下是具体实现步骤:

1. 基础准备:获取用户绘制的ROI坐标

通过OpenCV鼠标回调获取用户绘制的矩形坐标(x1, y1为左上角,x2, y2为右下角),确保坐标符合相机输出尺寸范围,同时统一坐标顺序(保证x1 < x2、y1 < y2)。

2. 构建支持ROI裁剪的DepthAI Pipeline

OAK的DepthAI框架提供ImageManip节点,可在硬件层完成图像裁剪与缩放,无需CPU介入。结合roboflowoak库,我们可以自定义Pipeline实现ROI推理:

import depthai as dai
import cv2
from roboflowoak import RoboflowOak

# 初始化ROI(可通过鼠标回调动态更新)
roi_x1, roi_y1 = 150, 150
roi_x2, roi_y2 = 450, 450
roi_w = roi_x2 - roi_x1
roi_h = roi_y2 - roi_y1

# 创建DepthAI Pipeline
pipeline = dai.Pipeline()

# 配置相机输入
cam_rgb = pipeline.create(dai.node.ColorCamera)
cam_rgb.setPreviewSize(640, 480)  # 匹配模型输入尺寸或相机原生尺寸
cam_rgb.setInterleaved(False)

# 添加硬件裁剪节点
manip = pipeline.create(dai.node.ImageManip)
# 设置裁剪区域(参数为相对比例:x_start, y_start, width_ratio, height_ratio)
manip.initialConfig.setCropRect(roi_x1/640, roi_y1/480, roi_w/640, roi_h/480)
# 将裁剪后的图像缩放到模型要求的输入尺寸(例如640x640)
manip.initialConfig.setResize(640, 640)
cam_rgb.preview.link(manip.inputImage)

# 初始化RoboflowOak,传入自定义Pipeline
rf = RoboflowOak(
    model="your-billiards-model-id",
    confidence=0.5,
    overlap=0.5,
    version="your-model-version",
    api_key="your-roboflow-api-key",
    pipeline=pipeline
)

3. 动态更新ROI(可选)

如果需要用户随时调整ROI,可在鼠标回调中动态发送新的裁剪配置到ImageManip节点:

def mouse_callback(event, x, y, flags, param):
    global roi_x1, roi_y1, roi_x2, roi_y2, drawing
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        roi_x1, roi_y1 = x, y
    elif event == cv2.EVENT_MOUSEMOVE and drawing:
        roi_x2, roi_y2 = x, y
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        # 修正坐标顺序
        roi_x1, roi_x2 = min(roi_x1, roi_x2), max(roi_x1, roi_x2)
        roi_y1, roi_y2 = min(roi_y1, roi_y2), max(roi_y1, roi_y2)
        roi_w = roi_x2 - roi_x1
        roi_h = roi_y2 - roi_y1
        # 发送新的裁剪配置
        config = dai.ImageManipConfig()
        config.setCropRect(roi_x1/640, roi_y1/480, roi_w/640, roi_h/480)
        config.setResize(640, 640)
        manip.inputConfig.send(config)

# 绑定鼠标回调
cv2.namedWindow("Billiards Detection")
cv2.setMouseCallback("Billiards Detection", mouse_callback)

4. 推理结果映射回原帧

由于模型是在裁剪后的图像上推理,检测框坐标需要映射回原帧的全局坐标:

drawing = False
while True:
    result, _, raw_frame, _ = rf.detect()
    
    # 绘制用户指定的ROI
    cv2.rectangle(raw_frame, (roi_x1, roi_y1), (roi_x2, roi_y2), (0, 0, 255), 2)
    
    # 映射检测框坐标并绘制
    for pred in result.get("predictions", []):
        # 裁剪后的图像上的坐标转换为原帧坐标
        pred_x = pred["x"] * (roi_w / 640) + roi_x1
        pred_y = pred["y"] * (roi_h / 640) + roi_y1
        pred_w = pred["width"] * (roi_w / 640)
        pred_h = pred["height"] * (roi_h / 640)
        
        # 计算检测框的左上角和右下角
        top_left = (int(pred_x - pred_w/2), int(pred_y - pred_h/2))
        bottom_right = (int(pred_x + pred_w/2), int(pred_y + pred_h/2))
        cv2.rectangle(raw_frame, top_left, bottom_right, (0, 255, 0), 2)
        cv2.putText(raw_frame, pred["class"], top_left, cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2)
    
    cv2.imshow("Billiards Detection", raw_frame)
    if cv2.waitKey(1) == ord('q'):
        break

cv2.destroyAllWindows()

关键优势对比

  • 原方案:模型处理整帧→CPU过滤结果,浪费VPU算力,大帧幅下延迟高
  • 优化方案:硬件裁剪ROI→模型仅处理目标区域,算力利用率提升,延迟显著降低

注意事项

  • 确保ImageManip的缩放尺寸与模型输入尺寸一致,避免推理错误
  • 动态更新ROI时,需保证坐标在相机输出尺寸范围内,防止裁剪参数越界
  • 坐标映射时要考虑裁剪区域与原帧的比例关系,避免检测框偏移

内容的提问来源于stack exchange,提问作者Ben gann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 05:33:14