K230庐山派,想将灰度识别矩形和识别色块放在一起运行(代码中task_flag == 2部分),但运行会死机,分开运行都没问题,有什么解决方法么:(

Viewed 69
`重现步骤`
<!-- 该问题的重现步骤是什么?请使用1、2、3描述 -->
# ============================================================
# MicroPython 灰度图矩形检测测试代码(使用 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类库
import math
from machine import UART
from machine import FPIOA


fpioa = FPIOA()
fpioa.set_function(11, FPIOA.UART2_TXD)
fpioa.set_function(12, FPIOA.UART2_RXD)
fpioa.set_function(52, FPIOA.GPIO52)
fpioa.set_function(36, FPIOA.GPIO36)

uart = UART(UART.UART2, baudrate=38400, bits=UART.EIGHTBITS, parity=UART.PARITY_NONE, stop=UART.STOPBITS_ONE)

# -------------------------------
# 图像尺寸设置 / Image resolution
# -------------------------------
image_shape = [320, 320]  # 高 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)

# -------------------------------
# 初始化摄像头(灰度图模式) / Initialize camera (grayscale 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.GRAYSCALE)  # 灰度图格式 / Grayscale 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.06      # 多边形拟合精度比例(越小拟合越精确)/ Polygon approximation accuracy
area_min_ratio     = 0.01     # 最小面积比例(相对于图像总面积)/ Min area ratio
max_angle_cos      = 0.3       # 最大角度余弦(越小越接近矩形)/ Max cosine of angle between edges
gaussian_blur_size = 5         # 高斯模糊核尺寸(奇数)/ Gaussian blur kernel size


threshold = [180, 255]   # 二值化阈值范围(亮区域)/ Threshold range for binarization
min_area = 1            # 最小目标面积 / Minimum area to keep
kernel_size = 1          # 腐蚀核大小(可用于降噪)/ Erosion kernel size
clock = time.clock()     # 帧率计时器


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)


# 在文件顶部添加数学计算函数
def calculate_ellipse_points(center_x, center_y, radius_cm, rect_corners, num_points=8):
    """
    根据矩形透视变形判断是画正圆还是椭圆
    center_x, center_y: 圆心坐标
    radius_cm: 实际半径(cm)
    rect_corners: 矩形的四个角点 [(x1,y1), (x2,y2), (x3,y3), (x4,y4)]
    num_points: 点数
    """
    # 估算像素到厘米的转换比例(以矩形长边为基准)
    d1 = math.sqrt((rect_corners[0][0]-rect_corners[2][0])**2 +
                   (rect_corners[0][1]-rect_corners[2][1])**2)
    d2 = math.sqrt((rect_corners[1][0]-rect_corners[3][0])**2 +
                   (rect_corners[1][1]-rect_corners[3][1])**2)
    diag_avg = (d1 + d2) / 2

    # A4纸对角线长度 ≈ 36.4 cm
    a4_diag_cm = math.sqrt(17.4**2 + 26**2)
    cm_to_pixel = diag_avg / a4_diag_cm
    radius_px = radius_cm * cm_to_pixel

    # 计算矩形长宽比
    width = math.sqrt((rect_corners[0][0]-rect_corners[1][0])**2 +
                      (rect_corners[0][1]-rect_corners[1][1])**2)
    height = math.sqrt((rect_corners[1][0]-rect_corners[2][0])**2 +
                       (rect_corners[1][1]-rect_corners[2][1])**2)

    long_edge = max(width, height)
    short_edge = min(width, height)
    aspect = long_edge / short_edge

    # 如果长宽比接近1(正视),画正圆;否则画椭圆
    if aspect < 1.6:  # 阈值可调
        # 正圆
        points = []
        for i in range(num_points):
            theta = 2 * math.pi * i / num_points
            x = int(center_x + radius_px * math.cos(theta))
            y = int(center_y + radius_px * math.sin(theta))
            points.append((x, y))
    else:
        # 椭圆
        dx = rect_corners[1][0] - rect_corners[0][0]
        dy = rect_corners[1][1] - rect_corners[0][1]
        angle = math.atan2(dy, dx)

        # 用矩形边长估算椭圆长短轴
        a = radius_px * (long_edge / short_edge)
        b = radius_px * (short_edge / long_edge)

        points = []
        for i in range(num_points):
            theta = 2 * math.pi * i / num_points
            x = a * math.cos(theta)
            y = b * math.sin(theta)

            x_rot = x * math.cos(angle) - y * math.sin(angle)
            y_rot = x * math.sin(angle) + y * math.cos(angle)

            points.append((int(center_x + x_rot), int(center_y + y_rot)))

        #print("aspect ratio:", aspect)

    return points




task_flag = 2
receivemess = None




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

    max_area = 0
    r = None
    blob_max_area = 0
    b = None

    if task_flag == 0:
        while receivemess == None:
            img = sensor.snapshot()   #####
            receivemess = uart.read()
            Display.show_image(img)
            time.sleep_ms(1)
#            uart.write(receivemess)
        if receivemess == b'\x31':
            task_flag=1
        elif receivemess == b'\x32':
            task_flag=2
        elif receivemess == b'\x33':
            task_flag=3
        elif receivemess == b'\x34':
            task_flag=4
        elif receivemess == b'\x35':
            task_flag=5
        elif receivemess == b'\x36':
            task_flag=6
        elif receivemess == b'\x37':
            task_flag=7
        elif receivemess == b'\x38':
            task_flag=8
        elif receivemess == b'\x39':
            task_flag=9
        elif receivemess == b'\x40':
            task_flag=10
        else :
            task_flag=0
            print(f"{receivemess}")
            receivemess = None

    elif task_flag == 1:
        # 拍摄一帧图像 / Capture a frame
        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.grayscale_find_rectangles_with_corners(
            image_shape, img_np,
            canny_thresh1, canny_thresh2,
            approx_epsilon,
            area_min_ratio,
            max_angle_cos,
            gaussian_blur_size
        )
        # 遍历检测到的矩形并绘制矩形框和角点
        for i in range(len(rects)):
            r_1 = rects[i]
            #img.draw_rectangle(r[0],r[1], r[2], r[3], color=(255, 255, 255), thickness=2)
            #img.draw_cross(r[4],r[5],color=(255,255,255),size=5,thickness=2)
            #img.draw_cross(r[6],r[7],color=(255,255,255),size=5,thickness=2)
            #img.draw_cross(r[8],r[9],color=(255,255,255),size=5,thickness=2)
            #img.draw_cross(r[10],r[11],color=(255,255,255),size=5,thickness=2)
            area = r_1[2] * r_1[3]
            if area > max_area:
                max_area = area
                r = r_1

        if r != None:
            # 提取角点(已按 cv_lite 返回顺序)
            pts = [
                (r[4], r[5]),   # 角点1
                (r[6], r[7]),   # 角点2
                (r[8], r[9]),   # 角点3
                (r[10], r[11])  # 角点4
            ]

            # 计算几何中心
            cx = sum(p[0] for p in pts) / 4.0
            cy = sum(p[1] for p in pts) / 4.0

            # 极角排序(顺时针)
            import math
            def angle_key(pt):
                return math.atan2(pt[1] - cy, pt[0] - cx)

            pts_sorted = sorted(pts, key=angle_key)

            # 提取排序后的角点
            p0, p1, p2, p3 = pts_sorted

            # 计算对角线交点
            ix, iy = intersection(p0, p2, p1, p3)

            #################圆形#################
            # 计算椭圆上的8个点
            ellipse_points = calculate_ellipse_points(ix, iy, 6, [p0, p1, p2, p3], num_points=20)

            # 绘制椭圆上的点
            for i, (px, py) in enumerate(ellipse_points):
                img.draw_circle(px, py, 3, color=(255, 0, 0), thickness=2)

                # 绘制连接线
                next_idx = (i + 1) % len(ellipse_points)
                img.draw_line(px, py, ellipse_points[next_idx][0], ellipse_points[next_idx][1],
                             color=(255, 0, 255), thickness=1)


            # 画边
            img.draw_line(*p0, *p1, color=(0,255,0), thickness=2)
            img.draw_line(*p1, *p2, color=(0,255,0), thickness=2)
            img.draw_line(*p2, *p3, color=(0,255,0), thickness=2)
            img.draw_line(*p3, *p0, color=(0,255,0), thickness=2)

            # 画对角线
            img.draw_line(*p0, *p2, color=(0,255,255), thickness=2)
            img.draw_line(*p1, *p3, color=(0,255,255), thickness=2)

            # 画交点
            img.draw_cross(ix, iy, size=10, thickness=2)

            center_points = [ix,iy]

            value_rect_1 = int((center_points[0]//100)%10 +(center_points[0]//10)%10 +center_points[0]%10 + (center_points[1]//100)%10 + (center_points[1]//10)%10 + center_points[1]%10)

            message_x = f'{center_points[0]:03d}'
            message_y = f'{center_points[1]:03d}'

            message_rect_1 = "{}{}{}\r\n".format(value_rect_1, message_x, message_y)

            # 发送椭圆点数据到UART
            # 格式:每个点"x,y"用逗号分隔,以"E"结尾
            ellipse_data = "E"
            for px, py in ellipse_points:
                ellipse_data += f"{px:03d},{py:03d},"
            ellipse_data = ellipse_data.rstrip(',') + "\r\n"
            #uart.write(ellipse_data)

            #uart.write(message_rect_1)
            #print(ellipse_data)
            #print(message_rect_1)

            # 画外接矩形(可选)
            #img.draw_rectangle(r[0], r[1], r[2], r[3], color=(1, 147, 230), thickness=3)

        # 显示图像 / Show image
        Display.show_image(img)

    elif task_flag == 2:

        img_np = img.to_numpy_ref()  # 获取图像数据引用 / Get ndarray reference


        # 执行灰度图二值连通域检测 / Perform blob detection on thresholded grayscale image
        blob = cv_lite.grayscale_find_blobs(
            image_shape, img_np,
            threshold[0], threshold[1],
            min_area, kernel_size
        )


        if len(blob) == 4:  # 只有一个 blob
            x, y, w, h = blob
            img.draw_rectangle(x, y, w, h, color=(0, 0, 0), thickness=2)
            bcx = blob[0] + blob[2]
            bcy = blob[1] + blob[3]
            print(blob)


            center_blob_points = [bcx,bcy]
            value_blob_1 = int((center_blob_points[0]//100)%10 +(center_blob_points[0]//10)%10 + center_blob_points[0]%10 + (center_blob_points[1]//100)%10 + (center_blob_points[1]//10)%10 + center_blob_points[1]%10)
            message_blob_x = f'{center_blob_points[0]:03d}'
            message_blob_y = f'{center_blob_points[1]:03d}'
            message_blob_1 = "{}{}{}b\r\n".format(value_blob_1, message_blob_x, message_blob_y)


        rects = cv_lite.grayscale_find_rectangles_with_corners(
            image_shape, img_np,
            canny_thresh1, canny_thresh2,
            approx_epsilon,
            area_min_ratio,
            max_angle_cos,
            gaussian_blur_size
        )

        # 遍历检测到的矩形并绘制矩形框和角点
        if rects:
            for r_1 in rects:
                area = r_1[2] * r_1[3]
                if area > max_area:
                    max_area = area
                    r = r_1

        if r != None:
            # 提取角点(已按 cv_lite 返回顺序)
            pts = [
                (r[4], r[5]),   # 角点1
                (r[6], r[7]),   # 角点2
                (r[8], r[9]),   # 角点3
                (r[10], r[11])  # 角点4
            ]

            # 计算几何中心
            cx = sum(p[0] for p in pts) / 4.0
            cy = sum(p[1] for p in pts) / 4.0

            # 极角排序(顺时针)
            import math
            def angle_key(pt):
                return math.atan2(pt[1] - cy, pt[0] - cx)

            pts_sorted = sorted(pts, key=angle_key)

            # 提取排序后的角点
            p0, p1, p2, p3 = pts_sorted

            # 计算对角线交点
            ix, iy = intersection(p0, p2, p1, p3)


            #################圆形#################
            # 计算椭圆上的8个点
            ellipse_points = calculate_ellipse_points(ix, iy, 6, [p0, p1, p2, p3], num_points=20)

            # 绘制椭圆上的点
            for i, (px, py) in enumerate(ellipse_points):
                img.draw_circle(px, py, 3, color=(255, 0, 0), thickness=2)

                # 绘制连接线
                next_idx = (i + 1) % len(ellipse_points)
                img.draw_line(px, py, ellipse_points[next_idx][0], ellipse_points[next_idx][1],
                             color=(255, 0, 255), thickness=1)

            # 画边
            img.draw_line(*p0, *p1, color=(0,255,0), thickness=2)
            img.draw_line(*p1, *p2, color=(0,255,0), thickness=2)
            img.draw_line(*p2, *p3, color=(0,255,0), thickness=2)
            img.draw_line(*p3, *p0, color=(0,255,0), thickness=2)

            # 画对角线
            img.draw_line(*p0, *p2, color=(0,255,255), thickness=2)
            img.draw_line(*p1, *p3, color=(0,255,255), thickness=2)

            # 画交点
            img.draw_cross(ix, iy, size=10, thickness=2)
            #img.draw_cross(bcx, bcy, size=10, thickness=2)

            center_points = [ix,iy]
            value_rect_1 = int((center_points[0]//100)%10 +(center_points[0]//10)%10 +center_points[0]%10 + (center_points[1]//100)%10 + (center_points[1]//10)%10 + center_points[1]%10)
            message_x = f'{center_points[0]:03d}'
            message_y = f'{center_points[1]:03d}'
            message_rect_1 = "{}{}{}a\r\n".format(value_rect_1, message_x, message_y)



#            uart.write(message_rect_1)
#            uart.write(message_blob_1)
            print(message_rect_1)
            #print(message_blob_1)

        Display.show_image(img)
    # 垃圾回收 & 输出帧率和检测矩形数量 / Garbage collect and print FPS & rectangles count
    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()





`期待结果和实际结果`
<!-- 你期待的结果是什么?实际看到的结果是什么? -->
能够在一个任务里同时进行

`软硬件版本信息`
<!-- 硬件版本信息?软件版本信息? -->


`错误日志`
<!-- 是否有任何错误信息或日志?请附上相关内容。 -->
find sensor gc2093_csi2, type 24, output 1920x1080@60
vb common pool count 4
sensor(0), mode 0, buffer_num 4, buffer_size 0

到这直接卡死

`尝试解决过程`
<!-- 你为解决这个问题尝试过哪些方法?请提供更多详细信息。 -->
分开运行都没问题

`补充材料`
<!-- 请提供其他相关信息(如代码片段、配置文件、截图等)。 -->
2 Answers
        rects = cv_lite.rgb888_find_rectangles_with_corners(
            image_shape, img_np_2,
            canny_thresh1, canny_thresh2,
            approx_epsilon,
            area_min_ratio,
            max_angle_cos,
            gaussian_blur_size
        )

你好,主要是因为这里把grayscale的图输入给rgb888的函数使用了,导致底层死掉了。

以及,这里没有必要把一个img生成2个img_np.

我改过来了,现在是能运行,但矩形和色块只能同时识别出来一个,代码我已经替换到问题里了

好像可以,我再试试

你好,请用代码块包住代码,现在的格式太乱了,稍后我再帮你看看

已经包好