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

如何为OpenCV鼠标绘制的圆添加平均RGB值至文本文件?

解决OpenCV绘制圆后计算内部平均RGB的问题

首先得说,你现在修改的代码里用cv2.mean(circle_drawn)是不对的——circle_drawn只是在原图上画了圆的轮廓,整个图像的像素只有圆的边缘被改变了,圆外的像素还是原图内容,所以这个mean计算的是整个图像的RGB均值,完全不是圆内部区域的均值,这就是你结果异常的原因。

接下来分两种方法帮你实现需求,包括你问的“不用mask”的方案:


方法一:用Mask计算(推荐,高效又准确)

这是OpenCV里计算指定区域均值的标准做法,原理很简单:创建一个和原图尺寸一致的全黑蒙版,然后在蒙版上画一个和你绘制的圆完全重合的实心白圆,最后用这个蒙版过滤原图,只计算蒙版白色区域(也就是圆内部)的像素均值。

修改EVENT_LBUTTONUP事件里的代码如下:

elif event == cv2.EVENT_LBUTTONUP:
    drawing = False
    num += 1
    radius = int(math.hypot(x - x1, y - y1))
    z = (z + 1) % (len(colours) - 1)
    
    # 先在图像上绘制圆的轮廓
    cv2.circle(img, (x1,y1), radius, colours[z], 1)
    
    # 创建mask并绘制实心圆
    mask = np.zeros(img.shape[:2], dtype=np.uint8)
    cv2.circle(mask, (x1, y1), radius, 255, -1)  # -1表示填充实心圆
    
    # 计算圆内均值:注意OpenCV图像是BGR顺序,要转成RGB
    bgr_mean = cv2.mean(img, mask=mask)
    rgb_mean = (bgr_mean[2], bgr_mean[1], bgr_mean[0])  # BGR转RGB
    
    print("圆内RGB均值: ", rgb_mean)
    
    # 更新保存的内容,把RGB均值加进去
    circleProps += f"{num} {x1} {y1} {radius} {rgb_mean[0]:.2f} {rgb_mean[1]:.2f} {rgb_mean[2]:.2f}\n"
    
    # 以下是原有的绘制圆心、编号的代码,保持不变
    cv2.circle(img, (x1, y1), 1, (0, 255, 0), -1)
    font = cv2.FONT_HERSHEY_PLAIN
    cv2.putText(img, str(num), (x1 + radius, y1 + radius), font, 1, (200, 255, 155), 1, cv2.LINE_AA)
    img2 = img.copy()

这种方法效率极高,不管圆的大小,计算速度都很快,是最推荐的方案。


方法二:不用Mask的纯坐标计算(适合小半径场景)

如果你确实不想用mask,也可以通过遍历像素坐标来判断是否在圆内,再收集这些像素的RGB值计算均值。但要注意,这种方法对于大半径的圆会非常慢,因为要遍历大量像素。

修改后的代码片段:

elif event == cv2.EVENT_LBUTTONUP:
    drawing = False
    num += 1
    radius = int(math.hypot(x - x1, y - y1))
    z = (z + 1) % (len(colours) - 1)
    
    # 绘制圆轮廓
    cv2.circle(img, (x1,y1), radius, colours[z], 1)
    
    # 遍历圆的外接矩形区域,减少计算量(不用遍历整个图像)
    start_x = max(0, x1 - radius)
    end_x = min(img.shape[1], x1 + radius)
    start_y = max(0, y1 - radius)
    end_y = min(img.shape[0], y1 + radius)
    
    pixel_list = []
    for y in range(start_y, end_y):
        for x in range(start_x, end_x):
            # 用勾股定理判断点是否在圆内(避免开根号,提升速度)
            if (x - x1)**2 + (y - y1)**2 <= radius**2:
                # OpenCV是BGR,转成RGB存入列表
                b, g, r = img[y, x]
                pixel_list.append((r, g, b))
    
    # 计算均值
    if pixel_list:
        rgb_mean = np.mean(pixel_list, axis=0)
        print("圆内RGB均值: ", rgb_mean)
    else:
        rgb_mean = (0, 0, 0)
        print("Warning: 圆内无有效像素")
    
    # 更新保存内容
    circleProps += f"{num} {x1} {y1} {radius} {rgb_mean[0]:.2f} {rgb_mean[1]:.2f} {rgb_mean[2]:.2f}\n"
    
    # 原有绘制代码不变
    cv2.circle(img, (x1, y1), 1, (0, 255, 0), -1)
    font = cv2.FONT_HERSHEY_PLAIN
    cv2.putText(img, str(num), (x1 + radius, y1 + radius), font, 1, (200, 255, 155), 1, cv2.LINE_AA)
    img2 = img.copy()

这种方法不需要依赖mask,但性能上不如mask方案,只适合小半径的圆场景。


最后再提醒两点:

  1. 一定要注意OpenCV的图像通道顺序是BGR,不是常规的RGB,所以计算后要转换顺序才能得到正确的RGB值;
  2. 你原来的circleProps表头也要修改,比如改成Num | x1 | y1 | r | R | G | B \n,这样保存的txt文件格式才对应。

内容的提问来源于stack exchange,提问作者Abrar Sayeed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:43:56