如何为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方案,只适合小半径的圆场景。
最后再提醒两点:
- 一定要注意OpenCV的图像通道顺序是BGR,不是常规的RGB,所以计算后要转换顺序才能得到正确的RGB值;
- 你原来的
circleProps表头也要修改,比如改成Num | x1 | y1 | r | R | G | B \n,这样保存的txt文件格式才对应。
内容的提问来源于stack exchange,提问作者Abrar Sayeed
相关产品推荐
相关产品推荐

