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

Python OpenCV检测图像预定义HSL颜色区间占比的实现方法

高效实现方案

你当前用cv2.inRange+numpy切片抽样的思路是最优解,全走C层实现比Python层逐像素循环快100倍以上,只要补上数值范围对齐、跨0色相区间处理、通道顺序校准几个逻辑即可,不需要自己写遍历逻辑。

核心注意点

  • 通道顺序校准:cv2.COLOR_BGR2HLS输出的三通道顺序是H(色相) -> L(亮度) -> S(饱和度),不是常规HSL的H-S-L顺序,传阈值时不要把S和L的位置写反。
  • 数值范围对齐:OpenCV对uint8类型的HLS图像取值规则如下,你之前写的[75,0,0]~[155,1,1]阈值范围是错的,S和L通道要做对应转换:
    • H通道:取值0179,对应实际色相0360度(存储时值为实际角度/2)
    • L通道:取值0255,对应亮度01(存储时值为实际比例*255)
    • S通道:取值0255,对应饱和度01(存储时值为实际比例*255)
  • 抽样逻辑直接用numpy切片实现:sampled_hls = hls[::step, ::step],步长默认取5即可,不需要逐像素跳步遍历,切片操作无额外内存拷贝,速度极快。总抽样像素数直接通过sampled_hls.shape[0] * sampled_hls.shape[1]计算,适配任意尺寸图像。
  • 跨0色相区间处理:当hS>hE时(即色相区间跨越0度红色域),不需要写复杂的边界判断,把区间拆成hS~179和0~hE两段分别做inRange,再将两个掩码按位或即可得到完整命中掩码。
  • 多区间统计互不干扰:因为允许区间重叠,每个颜色区间单独生成掩码统计计数即可,最终占比为区间命中数/总抽样像素数*100,总和超过100%为正常情况。

可直接复用的实现代码

import cv2
import numpy as np

# 配置参数
SAMPLE_STEP = 5  # 像素抽样步长
# 替换为你自己的colorRange实例列表即可
color_range_list = [
    {"name": "常规绿色", "hS":70, "hE":150, "sS":0.2, "sE":1.0, "lS":0.1, "lE":0.9},
    {"name": "跨0度红色", "hS":340, "hE":20, "sS":0.3, "sE":1.0, "lS":0.2, "lE":0.8}
]

# ---------------------- 图像加载 ----------------------
# 本地文件读取放开这行即可
# img_bgr = cv2.imread("test.jpg")
# 摄像头Bayer格式缓冲区加载沿用你原有逻辑
img_raw = np.ndarray(buffer=component.data.copy(), dtype=np.uint8,
                     shape=(component.height, component.width, 1))
img_bgr = cv2.cvtColor(img_raw, cv2.COLOR_BayerBG2BGR)

# ---------------------- 预处理与抽样 ----------------------
img_hls = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HLS)
sampled_hls = img_hls[::SAMPLE_STEP, ::SAMPLE_STEP]
total_sample_px = sampled_hls.shape[0] * sampled_hls.shape[1]

stat_result = {}
# ---------------------- 逐个区间统计 ----------------------
for cr in color_range_list:
    h_start, h_end = cr["hS"], cr["hE"]
    # 阈值转换:H从0-360度转0-179,L/S从0-1转0-255
    lower_1 = np.array([
        h_start // 2,
        int(cr["lS"] * 255),
        int(cr["sS"] * 255)
    ], dtype=np.uint8)
    upper_1 = np.array([
        h_end // 2 if h_start < h_end else 179,
        int(cr["lE"] * 255),
        int(cr["sE"] * 255)
    ], dtype=np.uint8)
    mask_1 = cv2.inRange(sampled_hls, lower_1, upper_1)

    if h_start > h_end:
        # 处理跨0度的色相区间,拼接第二段掩码
        lower_2 = np.array([0, int(cr["lS"]*255), int(cr["sS"]*255)], dtype=np.uint8)
        upper_2 = np.array([h_end//2, int(cr["lE"]*255), int(cr["sE"]*255)], dtype=np.uint8)
        mask_2 = cv2.inRange(sampled_hls, lower_2, upper_2)
        final_mask = cv2.bitwise_or(mask_1, mask_2)
    else:
        final_mask = mask_1
    
    hit_count = cv2.countNonZero(final_mask)
    hit_ratio = round(hit_count / total_sample_px * 100, 2)
    stat_result[cr["name"]] = {"count": hit_count, "ratio": hit_ratio}

# 输出结果
print(f"总抽样分析像素数:{total_sample_px}")
for color_name, res in stat_result.items():
    print(f"{color_name}: 命中{res['count']}像素,占比{res['ratio']}%")

适配说明

如果你定义colorRange时H值已经是OpenCV要求的0179范围、S/L值已经是0255范围,直接去掉代码里对应的//2和*255转换逻辑即可。

这套实现全程无Python层像素遍历,哪怕步长设为1做全像素统计,处理1080P图像也能达到毫秒级速度,完全适配摄像头实时流处理场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 09:54:30