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

OpenCV统计粉色像素占比恒为0但黑色检测正常的问题修复

问题描述

编写了基于OpenCV的指定图像内黑色、粉色像素占比检测代码,目前黑色像素统计结果符合预期,但即便图像中明确包含粉色内容,粉色像素占比始终返回0.0%,原始实现代码如下:

import cv2 as cv
import numpy as np
import os

for i in os.listdir("C:\\Users\\vikas\\Documents\\PyTest"):
    img = cv.cvtColor(cv.imread(f"C:\\Users\\vikas\\Documents\\PyTest\\{i}"), cv.COLOR_BGR2RGB)

    black = [0,0,0]
    pink = [255, 192, 203]

    diff_black = 20
    diff_pink = 20

    boundaries_black = [([ black[0], black[1], black[2] ],[ black[0]+diff_black, black[1]+diff_black, black[2]+diff_black ])]
    boundaries_pink = [([ pink[0]-diff_pink, pink[1]-diff_pink, pink[2]-diff_pink ],[ pink[0]+diff_pink, pink[1]+diff_pink, pink[2]+diff_pink ])]

    scale = 0.3
    height = int(img.shape[0]*scale)
    width = int(img.shape[1]*scale)
    newSize = (width, height)

    img = cv.resize(img, newSize, None, None, None, cv.INTER_AREA)

    for (lower, upper) in boundaries_black:
        lower = np.array(lower, dtype=np.uint8)
        upper = np.array(upper, dtype=np.uint8)

        mask = cv.inRange(img, lower, upper)

        ratio_black = cv.countNonZero(mask)/(img.size/3)
        colorPercent = (ratio_black*100)/scale

        print(f"black pixel percentage: {np.round(colorPercent, 2)}")

    for (lower, upper) in boundaries_pink:
        lower = np.array(lower, dtype=np.uint8)
        upper = np.array(upper, dtype=np.uint8)

        mask = cv.inRange(img, lower, upper)

        ratio_pink = cv.countNonZero(mask)/(img.size/3)
        colorPercent = (ratio_pink*100)/scale

        print(f"pink pixel percentage: {np.round(colorPercent, 2)}")
问题根源
  • 核心错误:粉色阈值计算触发uint8类型溢出
    定义的标准粉色RGB值为[255, 192, 203],设置容差diff_pink=20后,R通道的上界计算为255+20=275,但np.uint8类型的取值范围只有0~255,275会被截断为275-256=19。此时R通道的判断区间变成「≥235 且 ≤19」,属于无效区间,cv.inRange要求每个通道的下界值必须小于等于上界值,该区间不会匹配到任何像素,因此粉色像素统计结果始终为0。
  • 占比计算逻辑错误
    将图片缩放到原尺寸的30%后,图片总像素数已经发生变化,此时直接统计mask非零像素占当前图片总像素的比例即可,额外除以scale的操作属于逻辑错误,会导致最终占比结果失真。
  • 鲁棒性缺失
    遍历目标文件夹时没有过滤非图片文件,也没有判断图片是否读取成功,遇到文件夹、非图片格式文件时会直接触发程序报错。
修复方案
  1. 计算颜色阈值上下界时,手动把通道值截断到0~255的合法区间,避免uint8溢出/下溢
  2. 删除占比计算时多余的/scale操作,缩放后直接计算当前图的像素占比即可
  3. 增加文件过滤、图片读取成功判断,提升代码鲁棒性
  4. 可选优化:粉色属于对色相敏感的颜色,在HSV颜色空间做阈值分割,抗光照变化干扰的效果比RGB空间更好

修复后可正常运行的代码如下:

import cv2 as cv
import numpy as np
import os

target_dir = "C:\\Users\\vikas\\Documents\\PyTest"
# 支持的图片格式后缀
valid_exts = ('.jpg', '.jpeg', '.png', '.bmp')

# 定义颜色和容差
black = [0,0,0]
pink = [255, 192, 203]
diff_black = 20
diff_pink = 20

# 提前计算阈值,手动截断到0-255区间避免uint8溢出
def get_boundary(color, diff):
    lower = np.array([max(0, c - diff) for c in color], dtype=np.uint8)
    upper = np.array([min(255, c + diff) for c in color], dtype=np.uint8)
    return lower, upper

black_lower, black_upper = get_boundary(black, diff_black)
pink_lower, pink_upper = get_boundary(pink, diff_pink)

scale = 0.3

for i in os.listdir(target_dir):
    # 过滤非图片文件
    if not i.lower().endswith(valid_exts):
        continue
    img_path = os.path.join(target_dir, i)
    img = cv.imread(img_path)
    # 判断图片是否读取成功
    if img is None:
        print(f"跳过无法读取的文件:{i}")
        continue
    # OpenCV默认读入为BGR格式,转RGB
    img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

    # 缩放图片
    height = int(img.shape[0]*scale)
    width = int(img.shape[1]*scale)
    newSize = (width, height)
    img = cv.resize(img, newSize, interpolation=cv.INTER_AREA)
    total_pixel = img.shape[0] * img.shape[1]

    # 统计黑色像素占比
    mask_black = cv.inRange(img, black_lower, black_upper)
    ratio_black = cv.countNonZero(mask_black) / total_pixel * 100
    print(f"文件:{i} | 黑色像素占比: {np.round(ratio_black, 2)}%")

    # 统计粉色像素占比
    mask_pink = cv.inRange(img, pink_lower, pink_upper)
    ratio_pink = cv.countNonZero(mask_pink) / total_pixel * 100
    print(f"文件:{i} | 粉色像素占比: {np.round(ratio_pink, 2)}%")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:34:01