针对您的需求,核心是实现双重识别:对红色物体始终用绿色方框标注对所有检测到的圆形始终用蓝色圆框(及圆心)标注。这两个检测过程是独立的,颜色检测只关注红色,形状检测只关注圆形。以下是完整实现方案。

首先,核心功能对比与实现策略总结如下表所示:

功能模块目标物体检测方法识别框识别框颜色技术要点
颜色检测红色物体find_blobs, LAB色彩空间外接矩形 (矩形框)绿色 (0, 255, 0)使用LAB阈值分割红色区域,对任何红色色块都绘制矩形框
形状检测圆形物体find_circles,霍夫圆变换圆形轮廓 + 圆心十字蓝色 (0, 0, 255)在全图检测边缘圆形,不依赖颜色,所有检测到的圆形都绘制蓝色圆框

以下是完整的OpenMV MicroPython代码实现:

# 文件:main_red_square_circle_blue.py
# 功能:独立检测红色物体(绿色方框)与圆形物体(蓝色圆框),STA静态IP,WiFi图传
import sensor, image, time, network, uhttpd
import math

# -------------------- 1. 摄像头初始化 --------------------
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.VGA)  # 640x480 分辨率
sensor.skip_frames(time=2000)     # 等待感光元件稳定
sensor.set_auto_gain(False)       # 关闭自动增益
sensor.set_auto_whitebal(False)   # 关闭自动白平衡
clock = time.clock()

# -------------------- 2. 颜色与形状检测阈值定义 --------------------
# 红色的LAB颜色阈值(L, A, B 最小值, L, A, B 最大值),需要根据实际环境校准
# LAB色彩空间在特定光照下对红色识别更稳定 
red_lab_threshold = [(20, 70, 40, 80, 10, 60)]

# 圆形检测的霍夫变换阈值,控制检测灵敏度,值越低越敏感,但也越容易误检 
circle_detection_threshold = 2500

# 色块检测的面积和像素数阈值,过滤噪声
BLOB_MIN_PIXELS = 100
BLOB_MIN_AREA = 100

# -------------------- 3. WiFi网络配置 (STA模式 + 静态IP) --------------------
WIFI_SSID = "Your_Network_SSID"      # 替换为您的WiFi名称
WIFI_PASSWORD = "Your_WiFi_Password" # 替换为您的WiFi密码
STATIC_IP = "192.168.1.250"
SUBNET_MASK = "255.255.255.0"
GATEWAY = "192.168.1.1"
DNS_SERVER = "8.8.8.8"

print("正在初始化网络并连接...")
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# 配置静态IP地址 
wlan.ifconfig((STATIC_IP, SUBNET_MASK, GATEWAY, DNS_SERVER))
wlan.connect(WIFI_SSID, WIFI_PASSWORD)

# 等待连接,最多10秒
connect_timeout = 10
while connect_timeout > 0:
    if wlan.isconnected():
        break
    connect_timeout -= 1
    print('等待网络连接...', connect_timeout)
    time.sleep(1)

if wlan.isconnected():
    print('网络连接成功!')
    print('设备IP地址:', wlan.ifconfig()[0])
else:
    print('网络连接失败,请检查配置。')
    raise RuntimeError('WiFi连接失败')

# -------------------- 4. 核心检测与绘图函数 --------------------
def parallel_detection_and_annotation(img):
    """
    并行执行红色物体检测和圆形物体检测,并用指定颜色的框进行标注。
    参数:
        img: 从摄像头捕获的图像对象。
    """

    # **A. 检测所有红色色块 (用于绘制绿色方框)**
    # 使用find_blobs在LAB空间寻找红色区域 
    red_color_blobs = img.find_blobs(red_lab_threshold,
                                      pixels_threshold=BLOB_MIN_PIXELS,
                                      area_threshold=BLOB_MIN_AREA,
                                      merge=True,       # 合并相邻色块
                                      margin=10)        # 合并边界

    # **B. 在全图检测所有圆形 (不依赖颜色,用于绘制蓝色圆框)**
    # find_circles使用霍夫变换检测圆形边缘 
    detected_circles = img.find_circles(threshold=circle_detection_threshold,
                                         x_margin=10,
                                         y_margin=10,
                                         r_margin=10)

    # **C. 标注所有红色物体:用绿色方框和文字**
    for blob in red_color_blobs:
        # 获取色块的外接矩形坐标: (x, y, width, height)
        rect_x, rect_y, rect_w, rect_h = blob.rect()
        # 绘制绿色矩形框,线宽为2像素
        img.draw_rectangle(rect_x, rect_y, rect_w, rect_h,
                           color=(0, 255, 0),  # 绿色
                           thickness=2)
        # 在框的上方中央位置添加标签“Red”
        label_x = rect_x
        label_y = rect_y - 15  # 在矩形框上方显示文字
        if label_y < 0:
            label_y = rect_y + rect_h + 5  # 如果上方空间不够,显示在框下方
        img.draw_string(label_x, label_y, "Red", color=(0, 255, 0), scale=1.2)

    # **D. 标注所有检测到的圆形:用蓝色圆框和十字**
    for circle in detected_circles:
        circle_x = circle.x()
        circle_y = circle.y()
        circle_radius = circle.r()
        # 绘制蓝色圆形轮廓,线宽为2像素
        img.draw_circle(circle_x, circle_y, circle_radius,
                        color=(0, 0, 255),  # 蓝色
                        thickness=2)
        # 在圆心处绘制蓝色十字,便于定位
        img.draw_cross(circle_x, circle_y,
                       color=(0, 0, 255),  # 蓝色
                       size=10)
        # 在圆形右侧添加标签,显示半径
        label_text = "R:%d" % circle_radius
        img.draw_string(circle_x + circle_radius + 5, circle_y,
                        label_text, color=(0, 0, 255), scale=1.2)

    # **E. 在图像左上角显示实时统计信息**
    info_line_height = 15
    img.draw_string(5, 5, "Red Objects: %d" % len(red_color_blobs), color=(0, 255, 0))
    img.draw_string(5, 5 + info_line_height, "Circles: %d" % len(detected_circles), color=(0, 0, 255))

# -------------------- 5. HTTP视频流处理函数 (MJPEG流) --------------------
def http_stream_handler(request, response):
    """
    处理HTTP请求,持续发送MJPEG视频流。
    浏览器刷新后会重新建立连接,实现持续访问 。
    """
    # 发送HTTP响应头,声明内容类型为MJPEG流
    response.send_response(200)
    response.send_header("Content-Type", "multipart/x-mixed-replace; boundary=openmv_frame")
    response.send_header("Cache-Control", "no-cache")
    response.send_header("Pragma", "no-cache")
    response.send_header("Access-Control-Allow-Origin", "*")  # 允许跨域
    response.end_headers()

    while True:
        # 计算帧率
        clock.tick()
        # 从摄像头捕获一帧图像
        frame = sensor.snapshot()

        # **在图像上执行并行检测和标注**
        parallel_detection_and_annotation(frame)

        # 在图像右上角显示当前帧率
        current_fps = clock.fps()
        fps_text = "FPS: {:.1f}".format(current_fps)
        frame.draw_string(frame.width() - 80, 5, fps_text, color=(255, 255, 255))

        # 将图像压缩为JPEG格式,准备通过网络发送
        # 压缩质量(35)在清晰度和传输速度间取得平衡 
        jpeg_buffer = frame.compressed(quality=35)

        # 按照MJPEG流格式发送一帧图像数据
        response.send_bytes(b"--openmv_frame\r
")
        response.send_bytes(b"Content-Type: image/jpeg\r
")
        response.send_bytes(b"Content-Length: " + str(len(jpeg_buffer)) + b"\r
\r
")
        response.send_bytes(jpeg_buffer)
        response.send_bytes(b"\r
")

# -------------------- 6. 启动HTTP服务器 --------------------
# 创建uHTTPd应用实例
app = uhttpd.App()
# 将根路径"/"的GET请求绑定到视频流处理函数
app.route("/", methods=["GET"], handler=http_stream_handler)

print("")
print("=" * 50)
print("系统启动完成!")
print("视频流服务器正在运行...")
print("请在浏览器中访问: http://" + STATIC_IP + "/")
print("")
print("识别规则说明:")
print("  1. 红色物体 -> 绿色矩形框")
print("  2. 圆形物体 -> 蓝色圆形框 + 蓝色十字中心")
print("=" * 50)

# 启动服务器,监听所有网络接口的80端口
app.run(host="0.0.0.0", port=80)

方案设计与实现详解

  1. 独立的并行检测架构

    • 代码中的 parallel_detection_and_annotation 函数是核心。它内部先后调用了 img.find_blobsimg.find_circles 这两个独立的视觉算法 。
    • find_blobs 基于颜色阈值(LAB空间)分割图像,返回所有符合红色阈值的连通区域(色块)。其检测结果 red_color_blobs 是一个包含多个 blob 对象的列表,每个 blob 对象都包含其外接矩形 (rect())、中心点等属性,用于绘制绿色方框
    • find_circles 基于霍夫圆变换,在图像的边缘中寻找圆形轮廓。其检测结果 detected_circles 是一个列表,包含每个检测到的圆的圆心坐标 (x, y) 和半径 r,用于绘制蓝色圆框和十字 。
    • 这两个过程在逻辑和数据处理上完全独立,符合“颜色和形状分开识别”的要求。
  2. 识别框的动态性与同步

    • 红色物体的绿色方框:方框由色块的外接矩形 (blob.rect()) 决定。当红色物体由远及近由小变大时,其在图像中的像素面积增大,find_blobs 检测到的色块外接矩形尺寸 (w, h) 也随之变大,因此绘制的绿色方框会自动跟随物体大小和位置变化,实现动态跟踪效果 。
    • 圆形物体的蓝色圆框:圆框的圆心 (x, y) 和半径 r 直接来自 find_circles 的检测结果。当圆形物体靠近摄像头时,其像素半径 r 增大,绘制的蓝色圆形轮廓的半径也同步增大。因此,蓝色圆框同样具备动态缩放和跟随的能力 。
  3. 应用场景与参数调优

    • 典型应用场景:此方案适用于需要同时监控红色物体和统计圆形物体的工业或教育场景。例如,在一个分拣流水线上,需要将所有红色的零件(无论形状)用绿色框标出以进行定位,同时需要将所有圆形的轴承(无论颜色)用蓝色框标出以进行计数和质量检查 。
    • 关键参数校准流程
      1. 红色阈值 (red_lab_threshold):这是最关键的一步。需要在OpenMV IDE中,使用“工具(Tools) -> 机器视觉(Machine Vision) -> 阈值编辑器(Threshold Editor)”,将真实红色物体置于实际光照下,用取色器获取其LAB值范围。可能需要使用双区间阈值来完整捕捉红色,因为红色在HSV/HSL色环上跨越0°和180° 。
      2. 圆形检测灵敏度 (circle_detection_threshold):该参数控制霍夫圆变换的投票阈值。如果很多圆形被漏检,可以尝试降低此值(如从2500改为2000);如果背景中的弧形或噪声被误检为圆形,则需要提高此值(如改为3000)。
      3. 性能优化:若处理帧率 (FPS) 过低或网络延迟高,可采取以下措施:
        • 降低图像分辨率:将 sensor.set_framesize(sensor.VGA) 改为 sensor.set_framesize(sensor.QVGA)
        • 降低JPEG压缩质量:将 frame.compressed(quality=35) 中的 35 降低到 20 左右,但会损失图像清晰度。
        • 调整检测区域:可以为 find_blobsfind_circles 设置 roi 参数,只检测图像中感兴趣的区域,减少计算量。
  4. 网络与图传的健壮性

    • 代码配置了静态IP (STATIC_IP),确保设备在局域网中的地址固定,方便通过浏览器稳定访问 。
    • 视频流采用 MJPEG (Motion JPEG) 格式。其工作原理是服务器通过一个持久的HTTP连接,持续发送一系列独立的JPEG图片帧。当用户在浏览器中刷新页面时,旧的HTTP连接被关闭,浏览器会立即发起一个新的HTTP请求,服务器随之建立一个新的流连接并开始发送数据。这个过程是HTTP协议自带的,因此浏览器刷新后能自动重新连接并继续观看视频流,无需任何额外的重连逻辑 。

参考来源

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐