泛洪算法填充后无法识别到目标颜色区域

Viewed 48

重现步骤
复制代码运行
使用电赛c题要求的基础目标物测试

期待结果和实际结果
希望锁定泛洪填充为绿色的区域,但锁定到了a4纸边缘的黑框线内侧

软硬件版本信息
硬件为:立创k230庐山派
固件为:0.4.0
ide:CanMV IDE K230 4.0.7-0

错误日志
无报错,但不符合预期

尝试解决过程

补充材料
代码如下:

import time
import os
import sys
from media.sensor import *
from media.display import *
from media.media import *
from time import ticks_ms

sensor = None

# 自定义函数:计算矩形中心点
def mid_point_rect(x0, y0, wid, heigh):
    x_mid = x0 + wid // 2
    y_mid = y0 + heigh // 2
    return (x_mid, y_mid)

# 阈值设置 - 修复HSV阈值格式
bin_threshold = (0, 75)  # 灰度二值化阈值(用于A4纸边缘检测)
green_rgb = (0, 255, 0)  # 泛洪填充的绿色RGB值
# 修正HSV阈值格式
green_hsv_min = (35, 77, 40)    # HSV最小值
green_hsv_max = (85, 255, 255)  # HSV最大值

try:
    # 初始化摄像头
    sensor = Sensor(width=480, height=320)
    sensor.reset()
    sensor.set_framesize(width=480, height=320)
    sensor.set_pixformat(Sensor.RGB565)
    
    # 初始化显示
    Display.init(Display.LT9611, to_ide=True)
    MediaManager.init()
    sensor.run()
    clock = time.clock()

    while True:
        clock.tick()
        os.exitpoint()
        
        # 获取原始RGB565图像
        rgb_img = sensor.snapshot(chn=CAM_CHN_ID_0)
        
        # 创建灰度图用于边缘检测
        gray_img = rgb_img.to_grayscale(copy=True)
        gray_img = gray_img.binary([bin_threshold])

        # 查找A4纸矩形
        rects = gray_img.find_rects(threshold=3000)
        max_area = 0
        max_corners = None
        max_rect = None
        
        if rects:
            for rect in rects:
                corners = rect.corners()
                # 确保角点坐标是整数
                corners = [(int(c[0]), int(c[1])) for c in corners]
                width = abs(corners[1][0] - corners[0][0])
                height = abs(corners[3][1] - corners[0][1])
                area = width * height
                
                if area > max_area and width > 100 and height > 100:
                    max_area = area
                    max_corners = corners
                    max_rect = rect

            if max_corners and max_rect:
                # 绘制A4纸边框(红色)
                for i in range(4):
                    x1, y1 = max_corners[i]
                    x2, y2 = max_corners[(i+1)%4]
                    # 确保坐标是整数
                    rgb_img.draw_line(int(x1), int(y1), int(x2), int(y2), color=(255, 0, 0), thickness=2)
                
                # 获取A4纸区域信息
                x, y, w, h = max_rect.rect()
                
                # 计算A4纸中心区域
                inner_x = x + int(w * 0.2)
                inner_y = y + int(h * 0.2)
                inner_w = int(w * 0.6)
                inner_h = int(h * 0.6)
                
                # 泛洪填充(绿色)
                seed_point = mid_point_rect(inner_x, inner_y, inner_w, inner_h)
                # 确保种子点是整数坐标
                seed_x, seed_y = int(seed_point[0]), int(seed_point[1])
                rgb_img.flood_fill(seed_x, seed_y, seed_threshold=0.1, color=green_rgb)
                
                # 检索填充的绿色区域 - 使用修正的HSV阈值格式
                green_blobs = rgb_img.find_blobs(
                    [green_hsv_min, green_hsv_max],  # 修正:使用两个独立元组
                    invert=False,
                    roi=(int(x), int(y), int(w), int(h)),  # 确保ROI参数是整数
                    x_stride=1,
                    y_stride=1,
                    pixels_threshold=1000,
                    area_threshold=1000,
                    merge=True,
                    margin=False
                )
                
                # 绘制绿色区域边框(绿色)
                if green_blobs:
                    largest_green = max(green_blobs, key=lambda b: b.area())
                    
                    # 绘制边框时确保所有坐标都是整数
                    rgb_img.draw_rectangle(
                        int(largest_green.x()), int(largest_green.y()),
                        int(largest_green.w()), int(largest_green.h()),
                        color=(0, 0, 255), thickness=2, fill=False
                    )
                    
                    # 显示绿色区域信息
                    info = f"Green: {largest_green.w()}x{largest_green.h()}"
                    rgb_img.draw_string_advanced(
                        int(x) + 10, int(y) - 30, 16,
                        info, color=(0, 255, 0)
                    )
                    print(f"绿色区域尺寸: {largest_green.w()}x{largest_green.h()}")
        
        # 显示帧率
        rgb_img.draw_string_advanced(10, 10, 20, f"fps: {int(clock.fps())}", color=(255, 0, 0))
        rgb_img.compressed_for_ide()
        Display.show_image(rgb_img)

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()

显示结果:image.png

2 Answers
# ============================================================
# MicroPython RGB888矩形检测测试代码(使用 cv_lite 扩展模块),带角点
# Grayscale Rectangle Detection Test using cv_lite extension
# ============================================================

import time, os, sys, gc
from machine import Pin
from media.sensor import *     # 摄像头接口 / Camera interface
from media.display import *    # 显示接口 / Display interface
from media.media import *      # 媒体资源管理器 / Media manager
import _thread
import cv_lite                 # cv_lite扩展模块 / cv_lite extension (C bindings)
import ulab.numpy as np        # MicroPython NumPy类库

# -------------------------------
# 图像尺寸设置 / Image resolution
# -------------------------------
image_shape = [480, 640]  # 高 x 宽 / Height x Width

def calculate_crop(sensor_width, sensor_height, target_width, target_height):
    """
    Calculate center crop rectangle from sensor resolution to match target resolution
    with preserved aspect ratio.

    Returns:
        (crop_x, crop_y, crop_width, crop_height)
    """
    scale = min(sensor_width // target_width, sensor_height // target_height)
    crop_width = int(target_width * scale)
    crop_height = int(target_height * scale)
    crop_x = (sensor_width - crop_width) // 2
    crop_y = (sensor_height - crop_height) // 2
    return (crop_x, crop_y, crop_width, crop_height)

# -------------------------------
# 初始化摄像头(RGB888模式) / Initialize camera (rgb888 mode)
# -------------------------------
sensor = Sensor(id=2, fps = 90)
sensor.reset()
sensor_width = sensor.width(None)
sensor_height = sensor.height(None)
sensor.set_framesize(width=image_shape[1], height=image_shape[0], crop = calculate_crop(sensor_width,sensor_height,image_shape[1],image_shape[0]))
sensor.set_pixformat(Sensor.RGB888)  # RGB888格式 / rgb888 format

# -------------------------------
# 初始化显示器(IDE虚拟输出) / Initialize display (IDE virtual output)
# -------------------------------
Display.init(Display.VIRT, width=image_shape[1], height=image_shape[0],
             to_ide=True, quality=50)

# -------------------------------
# 初始化媒体系统 / Initialize media system
# -------------------------------
MediaManager.init()
sensor.run()

# -------------------------------
# 可选增益设置(亮度/对比度调节)/ Optional sensor gain setting
# -------------------------------
gain = k_sensor_gain()
gain.gain[0] = 20
sensor.again(gain)

# -------------------------------
# 启动帧率计时 / Start FPS timer
# -------------------------------
clock = time.clock()

# -------------------------------
# 矩形检测可调参数 / Adjustable rectangle detection parameters
# -------------------------------
canny_thresh1      = 50        # Canny 边缘检测低阈值 / Canny low threshold
canny_thresh2      = 150       # Canny 边缘检测高阈值 / Canny high threshold
approx_epsilon     = 0.04      # 多边形拟合精度比例(越小拟合越精确)/ Polygon approximation accuracy
area_min_ratio     = 0.001     # 最小面积比例(相对于图像总面积)/ Min area ratio
max_angle_cos      = 0.3       # 最大角度余弦(越小越接近矩形)/ Max cosine of angle between edges
gaussian_blur_size = 5         # 高斯模糊核尺寸(奇数)/ Gaussian blur kernel size

# 阈值设置 - 修复HSV阈值格式
bin_threshold = (0, 75)  # 灰度二值化阈值(用于A4纸边缘检测)
green_rgb = (0, 255, 0)  # 泛洪填充的绿色RGB值
# 修正HSV阈值格式
green_lab_min = (0, -128, 0)
green_lab_max = (100, 0, 127)

def mid_point_rect(x0, y0, wid, heigh):
    x_mid = x0 + wid // 2
    y_mid = y0 + heigh // 2
    return (x_mid, y_mid)

# -------------------------------
# 主循环 / Main loop
# -------------------------------
while True:
    clock.tick()

    img565 = None  # 用于存储RGB565格式图像

    # 拍摄一帧图像 / Capture a frame
    img = sensor.snapshot()
    img_np = img.to_numpy_ref()

    # 调用底层矩形检测函数
    # 返回格式:[[x0, y0, w0, h0, c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, c4,x, c4.y], [x1, y1, w1, h1,c1.x, c1.y, c2.x, c2.y, c3.x, c3.y, c4,x, c4.y], ...]
    rects = cv_lite.rgb888_find_rectangles_with_corners(
        image_shape, img_np,
        canny_thresh1, canny_thresh2,
        approx_epsilon,
        area_min_ratio,
        max_angle_cos,
        gaussian_blur_size
    )

    rect_cnt = len(rects)
    if rect_cnt:
        img565 = img.to_rgb565()

        for i in range(rect_cnt):
            r = rects[i]
        
            # 获取A4纸区域信息
            x, y, w, h = r[0], r[1], r[2], r[3]

            # 计算中心区域
            inner_x = x + int(w * 0.2)
            inner_y = y + int(h * 0.2)
            inner_w = int(w * 0.6)
            inner_h = int(h * 0.6)

            seed_x, seed_y = mid_point_rect(inner_x, inner_y, inner_w, inner_h)
            img565.flood_fill(int(seed_x), int(seed_y), seed_threshold=0.1, floating_thresholds=0.05,
                        color=green_rgb, invert=False, clear_background=False)
        
            # HSV 范围检测
            green_blobs = img565.find_blobs(
                [(0, 80, -128, 90, -128, 29)], # green
                invert=True,
                roi=(int(x), int(y), int(w), int(h)),
                x_stride=1,
                y_stride=1,
                pixels_threshold=1000,
                area_threshold=1000,
                merge=True,
                margin=False
            )

            print(f"检测到 {len(green_blobs)} 个绿色区域")

            # 绘制绿色区域边框
            if green_blobs:
                largest_green = max(green_blobs, key=lambda b: b.area())

                img565.draw_rectangle(
                    int(largest_green.x()), int(largest_green.y()),
                    int(largest_green.w()), int(largest_green.h()),
                    color=(0, 0, 255), thickness=2, fill=False
                )

                info = f"Green: {largest_green.w()}x{largest_green.h()}"
                img565.draw_string_advanced(
                    int(x) + 10, int(y) - 30, 16,
                    info, color=(0, 255, 0)
                )
                print(f"绿色区域尺寸: {largest_green.w()}x{largest_green.h()}")

            # Draw all detected rectangles and corners for visual feedback
            img565.draw_rectangle(r[0], r[1], r[2], r[3], color=(255, 255, 255), thickness=2)
            for j in range(4):
                img565.draw_cross(r[4 + 2 * j], r[5 + 2 * j], color=(255, 255, 255), size=5, thickness=2)
            img565.draw_cross(seed_x, seed_y, color=(255, 0, 0), size=5, thickness=2)

    # 显示图像 / Show image
    if img565 is not None:
        # 如果有检测到矩形,则显示RGB565格式图像
        Display.show_image(img565)
        img565.__del__()  # 释放RGB565图像内存
    else:
        Display.show_image(img)

    # 垃圾回收 & 输出帧率/ Garbage collect and print FPS 
    gc.collect()
    print("fps:", clock.fps())

# -------------------------------
# 程序退出与资源释放 / Cleanup on exit
# -------------------------------
sensor.stop()
Display.deinit()
os.exitpoint(os.EXITPOINT_ENABLE_SLEEP)
time.sleep_ms(100)
MediaManager.deinit()

你好,可以试试这个代码。需要更新到最新得daily build.

谢谢佬!!!

你好,请下载https://kendryte-download.canaan-creative.com/developer/releases/canmv_k230_micropython/daily_build/ 最新的固件,使用这个demo ,https://github.com/kendryte/canmv_k230/blob/canmv_k230/resources/examples/23-CV_Lite/rgb888_pnp_distance_from_corners_and_find_target.py