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()
关键修改说明
- region_of_interest函数:
- 将
mask = np.zeros_like(img)改为mask = np.zeros_like(image),确保mask与传入图像的通道数一致 - 将
match_mask_color = 255,255,255改为match_mask_color = 255,适配灰度图的单通道格式
- 将
- 顶点坐标修正:
- 给每个顶点加上boundingRect的
x_rect和y_rect偏移量,确保感兴趣区域定位在面部的嘴巴区域
- 给每个顶点加上boundingRect的
- 二值化反转:
- 使用
cv2.THRESH_BINARY_INV替代cv2.THRESH_BINARY,实现嘴巴黑、面部白的效果
- 使用
- 像素遍历与统计:
- 每次循环重置计数,避免累积错误
- 使用
agiz.shape[:2]获取图像尺寸,通过agiz[y, x]访问像素 - 直接统计
agiz图像的像素值,而非原始图像
内容的提问来源于stack exchange,提问作者Eren Yanic
相关产品推荐
相关产品推荐

