如何用Python为图像单一绿色区域绘制矩形轮廓并裁剪?
问题描述
我尝试为图像中的亮绿色区域绘制矩形轮廓,但目前仅能绘制出最大矩形,无法针对性地识别单一颜色区域进行绘制。期望得到亮绿色区域的矩形裁剪图。我的代码如下:
import cv2 import numpy as np median = cv2.imread("try.png", 0) image_gray = median image_gray = np.where(image_gray > 30, 255, image_gray) image_gray = np.where(image_gray <= 30, 0, image_gray) image_gray = cv2.adaptiveThreshold(image_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 115, 1) _, contours, _ = cv2.findContours(image_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) rect_cnts = [] for cnt in contours: peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.04 * peri, True) (x, y, w, h) = cv2.boundingRect(cnt) ar = w / float(h) if len(approx) == 4: # shape filtering condition rect_cnts.append(cnt) max_area = 0 football_square = None for cnt in rect_cnts: (x, y, w, h) = cv2.boundingRect(cnt) if max_area < w*h: max_area = w*h football_square = cnt # Draw the result image = cv2.cvtColor(image_gray, cv2.COLOR_GRAY2RGB) cv2.drawContours(image, [football_square], -1, (0, 0,255), 5) cv2.imshow("Result Preview", image) cv2.waitKey()
解决方案
嗨,这个问题的核心是你当前的代码完全在灰度空间处理,根本没用到颜色信息来锁定亮绿色区域——这就是为什么只会找到画面里的最大矩形,而非你要的绿色区域。咱们换个思路,先通过颜色分割把亮绿色区域单独提取出来,再针对性找轮廓和矩形,具体操作如下:
关键思路拆解
- 切换到HSV颜色空间做颜色分割
RGB空间对光照变化太敏感,HSV空间更适合精准筛选特定颜色。我们可以先定义亮绿色的HSV范围,生成掩码把绿色区域单独抠出来。 - 用形态学操作优化掩码
初始提取的掩码可能有小噪点,用「开运算」(腐蚀+膨胀)可以去掉这些干扰,让轮廓更清晰。 - 筛选矩形轮廓并处理
复用你原来的矩形筛选逻辑,但这次是基于绿色掩码的轮廓,所以只会针对绿色区域工作。
修改后的完整代码
import cv2 import numpy as np # 读取原始彩色图像(别再读成灰度图了!) image = cv2.imread("try.png") # 转换到HSV颜色空间,方便颜色分割 hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 定义亮绿色的HSV范围(可以根据你的实际图像调整数值) lower_green = np.array([40, 40, 40]) upper_green = np.array([80, 255, 255]) # 生成绿色区域的掩码:只保留绿色部分 mask = cv2.inRange(hsv, lower_green, upper_green) # 形态学开运算:去除小噪点,让轮廓更规整 kernel = np.ones((5,5), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 寻找轮廓:只找最外层轮廓,减少干扰 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选符合条件的绿色矩形轮廓 green_rects = [] for cnt in contours: # 计算轮廓周长,用于多边形逼近 peri = cv2.arcLength(cnt, True) # 多边形逼近,把轮廓简化成近似形状 approx = cv2.approxPolyDP(cnt, 0.04 * peri, True) # 获取轮廓的边界矩形 x, y, w, h = cv2.boundingRect(cnt) # 计算宽高比,过滤掉形状不符合的区域(比如细长条) ar = w / float(h) # 筛选条件:是矩形(4个顶点)、面积足够大、宽高比接近屏幕的比例 if len(approx) == 4 and w*h > 1000 and 0.8 < ar < 1.2: green_rects.append((x, y, w, h)) # 绘制矩形轮廓并裁剪绿色区域 result = image.copy() for (x, y, w, h) in green_rects: # 在原图上绘制红色矩形轮廓 cv2.rectangle(result, (x, y), (x+w, y+h), (0, 0, 255), 5) # 裁剪出绿色区域并显示 cropped_area = image[y:y+h, x:x+w] cv2.imshow(f"Cropped Green Screen", cropped_area) # 显示最终结果 cv2.imshow("Green Screen with Rectangles", result) cv2.waitKey(0) cv2.destroyAllWindows()
注意事项
- 调整HSV范围:如果你的亮绿色和代码里的范围不匹配,可以用HSV颜色拾取工具(比如OpenCV自带的调色板工具)来获取准确的上下限数值。
- 调整筛选阈值:代码里的面积阈值(1000)和宽高比范围(0.8-1.2)可以根据你的实际需求修改,过滤掉太小或形状不对的区域。
- 单一区域处理:如果图像里有多个绿色矩形,但你只需要其中一个,可以在
green_rects里做进一步筛选(比如找面积最大的,或者位置最符合的)。
内容的提问来源于stack exchange,提问作者Mansi Shukla
相关产品推荐
相关产品推荐

