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

OpenCV图像像素遍历报错与二值化蒙版颜色异常求助

问题解决方案

1. 修复像素遍历报错(AttributeError: 'numpy.ndarray' object has no attribute 'width')

OpenCV读取的图像是numpy数组,没有width/height属性,且不能使用PIL的getpixel方法访问像素。修改方式如下:

  • 通过数组.shape获取尺寸:shape[0]是高度(行数),shape[1]是宽度(列数)
  • 直接通过numpy数组索引访问像素:数组[y, x](注意行优先顺序,y对应高度方向,x对应宽度方向)

2. 实现预期的黑白蒙版效果并统计颜色数量

核心问题点与修复:

  • 通道不匹配:region_of_interest函数中,mask应基于传入的灰度图创建,而非原始彩色图;灰度图的蒙版颜色应为单通道的255
  • 坐标错误:感兴趣区域的顶点需转换为原始图像的全局坐标(加上boundingRect的偏移量x,y)
  • 二值化方向:使用THRESH_BINARY_INV反转二值化结果,确保嘴巴区域为黑色(0)、面部区域为白色(255)
  • 统计对象错误:应统计裁剪后agiz图像的像素,而非原始图像

修改后的完整代码

import cv2
import numpy as np

img = cv2.imread("saskin.jpg")

black_count = 0
white_count = 0

def region_of_interest(image, vertices):
    # 基于传入的image创建mask,保证通道数匹配
    mask = np.zeros_like(image)
    # 灰度图使用单通道蒙版颜色
    match_mask_color = 255
    cv2.fillPoly(mask, vertices, match_mask_color)
    masked_image = cv2.bitwise_and(image, mask)
    return masked_image

while True:
    ycrbc = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
    
    minYCrCb = np.array([0,140,90],np.uint8)
    maxYCrCb = np.array([230,170,120],np.uint8)
    imgeYCrCb = cv2.cvtColor(img,cv2.COLOR_BGR2YCR_CB)
    skinRegionYCrCb = cv2.inRange(imgeYCrCb,minYCrCb,maxYCrCb)
    skinYCrCb = cv2.bitwise_and(img, img, mask = skinRegionYCrCb)
    median_ycrcb = cv2.medianBlur(skinYCrCb, 3)
    
    _, esik = cv2.threshold(median_ycrcb, 20, 255, cv2.THRESH_BINARY)
    median_binary = cv2.medianBlur(esik, 7)
    
    gray = cv2.cvtColor(median_binary, cv2.COLOR_BGR2GRAY)
    
    contours, hierarchy = cv2.findContours(gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    areas = [cv2.contourArea(c) for c in contours]
    max_index = np.argmax(areas)
    x_rect, y_rect, w_rect, h_rect = cv2.boundingRect(contours[max_index])
    
    # 修正顶点坐标:转换为原始图像的全局坐标
    region_of_interest_vertices = [
        (x_rect + w_rect//4, y_rect + 11*h_rect//12),
        (x_rect + w_rect//4, y_rect + 13*h_rect//16),
        (x_rect + 3*w_rect//4, y_rect + 13*h_rect//16),
        (x_rect + 3*w_rect//4, y_rect + 11*h_rect//12)
    ]
    gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cropped_image = region_of_interest(gray_image, np.array([region_of_interest_vertices], np.int32))
    
    # 使用THRESH_BINARY_INV反转二值化,让嘴巴为黑、面部为白
    _, agiz = cv2.threshold(cropped_image, 20, 255, cv2.THRESH_BINARY_INV)

    # 重置计数(避免循环累积)
    black_count = 0
    white_count = 0
    # 获取图像尺寸
    height, width = agiz.shape[:2]
    # 遍历像素
    for y in range(height):
        for x in range(width):
            pixel = agiz[y, x]
            if pixel == 0:
                black_count += 1
            elif pixel == 255:
                white_count += 1
    # 打印统计结果
    print(f"黑色像素数:{black_count},白色像素数:{white_count}")

    cv2.imshow("ycrbc",ycrbc)
    cv2.imshow("skinYCrCb",median_ycrcb)
    cv2.imshow("binary goruntu", esik)
    cv2.imshow("median_binary", median_binary)
    cv2.imshow("Kesilmiş Görüntü",cropped_image)
    cv2.imshow("agiz", agiz)
    
    if cv2.waitKey(5) & 0xFF == ord("q"):
        break

cv2.destroyAllWindows()

关键修改说明

  1. region_of_interest函数:
    • 将mask = np.zeros_like(img)改为mask = np.zeros_like(image),确保mask与传入图像的通道数一致
    • 将match_mask_color = 255,255,255改为match_mask_color = 255,适配灰度图的单通道格式
  2. 顶点坐标修正:
    • 给每个顶点加上boundingRect的x_rect和y_rect偏移量,确保感兴趣区域定位在面部的嘴巴区域
  3. 二值化反转:
    • 使用cv2.THRESH_BINARY_INV替代cv2.THRESH_BINARY,实现嘴巴黑、面部白的效果
  4. 像素遍历与统计:
    • 每次循环重置计数,避免累积错误
    • 使用agiz.shape[:2]获取图像尺寸,通过agiz[y, x]访问像素
    • 直接统计agiz图像的像素值,而非原始图像

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:50:43