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

Python OpenCV基于YCbCr色彩空间的颜色检测问题咨询

OpenCV YCbCr色彩空间绿色区域检测问题排查

现有代码的核心错误

你当前代码检测不到绿色的根本原因是阈值定义完全不符合cv.inRange()的调用规则:

  • cv.inRange()要求lower数组每个通道的数值必须小于等于upper数组对应通道的数值,你当前定义的lower_green = [93, 147, 72]、upper_green = [75, 113, 87]中,Y通道93>75、Cr通道147>113,阈值区间完全无效,生成的掩膜会是全黑状态,自然检测不到任何区域。
  • 注意OpenCV中cv.COLOR_BGR2YCrCb转换后的通道顺序是[Y(亮度), Cr(红色差分量), Cb(蓝色差分量)],不是很多资料里写的Y、Cb、Cr顺序,通道顺序搞反再怎么调阈值都不会有正确结果。

绿色在YCrCb空间下的参考阈值(可根据你自己数据集的光照情况微调):

  • Y通道:30~250(不要把亮度区间卡太死,避免明暗变化导致漏检)
  • Cr通道:70~120(绿色对应的Cr分量偏低)
  • Cb通道:90~130

修正后的基础检测代码如下:

import cv2 as cv
import numpy as np

img_ycrcb = cv.cvtColor(img3, cv.COLOR_BGR2YCrCb)
# 保证所有通道下限值 <= 上限值,明确dtype避免类型错误
lower_green = np.array([30, 70, 90], dtype=np.uint8)
upper_green = np.array([250, 120, 130], dtype=np.uint8)
mask_green = cv.inRange(img_ycrcb, lower_green, upper_green)
# 如需显示正常的彩色绿色区域,要在原始BGR图上做掩膜运算,不要在YCrCb图上操作
green_area = cv.bitwise_and(img3, img3, mask=mask_green)

cv.imshow('YCrCb converted image', img_ycrcb)
cv.imshow('Green mask', mask_green)
cv.imshow('Detected green area', green_area)
cv.waitKey(0)
cv.destroyAllWindows()

两个高频疑问解答

1. 同时检测红、绿区域是否需要做按位或运算

根据你的实际需求选择:

  • 如果需要一次性提取图中所有红色+绿色的区域:分别生成红色掩膜、绿色掩膜后,对两个掩膜做按位或运算,用合并后的掩膜提取区域即可。不要直接把两个颜色的阈值拼到一组上下限里,因为红、绿在Cr、Cb通道的数值区间不连续,硬拼阈值会出现大量漏检、误检。
  • 如果需要分别统计红、绿区域的面积、位置等独立指标:不要合并掩膜,保留两个颜色的独立掩膜单独计算即可。

附YCrCb空间下红色的参考阈值(通道顺序Y、Cr、Cb):lower_red = np.array([30, 140, 80], dtype=np.uint8),upper_red = np.array([250, 190, 130], dtype=np.uint8),可根据实际场景微调。

2. 掩膜计算的执行时机

不要等所有图像都存入数组后再做掩膜计算,应该在遍历导入图像的过程中同步处理,原因如下:

  • 内存占用更低:如果把所有原始图像全量存入数组,哪怕仅100张1080P分辨率的图片,也会占用数GB内存,边读边处理只需要保留单张原图和处理后的结果,内存压力会小很多。
  • 逻辑更简单:不需要额外写循环遍历高维图像数组做逐图计算,读一张、处理一张、存储需要的结果即可。

批量处理参考代码:

import os
import cv2 as cv
import numpy as np

# 提前固定阈值
lower_green = np.array([30, 70, 90], dtype=np.uint8)
upper_green = np.array([250, 120, 130], dtype=np.uint8)
lower_red = np.array([30, 140, 80], dtype=np.uint8)
upper_red = np.array([250, 190, 130], dtype=np.uint8)

img_folder = "your/image/dataset/path"
process_result = []

for filename in os.listdir(img_folder):
    if filename.lower().endswith(('.png', '.jpg', '.jpeg')):
        # 读入单张图片
        img = cv.imread(os.path.join(img_folder, filename))
        # 色彩空间转换+掩膜计算
        img_ycrcb = cv.cvtColor(img, cv.COLOR_BGR2YCrCb)
        mask_green = cv.inRange(img_ycrcb, lower_green, upper_green)
        mask_red = cv.inRange(img_ycrcb, lower_red, upper_red)
        # 需要合并区域就做按位或
        mask_total = cv.bitwise_or(mask_green, mask_red)
        detect_res = cv.bitwise_and(img, img, mask=mask_total)
        # 仅存储需要的结果,不要冗余存储原始大图
        process_result.append({
            "filename": filename,
            "green_pixel_count": np.sum(mask_green > 0),
            "red_pixel_count": np.sum(mask_red > 0),
            "detect_img": detect_res
        })

# 全部处理完成后,再按需把结果转成numpy数组
X = np.array([item["detect_img"] for item in process_result])

小提示:不要直接硬抄公开的阈值数值,最好拿自己数据集里的3~5张样图,用OpenCV滚动条写个简易实时调参工具,调到阈值能准确覆盖目标颜色再固定,比手动试数效率高很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 17:12:28