Python OpenCV中np.zeros初始化图像imshow显示全黑/全白异常排查
问题背景
在Python环境下使用OpenCV练习图像拷贝功能(已知可直接调用np.copy()实现该需求),编写测试代码如下:
import numpy as np import cv2 as cv img = cv.imread('Photos/image_1.jpg') r, c, d = img.shape img_copy = np.zeros((r, c, d)) for i in range(r): for j in range(c): for k in range(d): img_copy[i, j, k] = img[i, j, k] cv.imshow('original image', img) cv.imshow('copied image', img_copy) cv.waitKey(0)
运行代码出现异常:
- 通过
np.zeros((r,c,d))初始化的img_copy经三重for循环逐像素赋值后,cv.imshow显示为全黑图像 - 若替换为
img_copy = np.ones(rows, cols, 3)初始化数组再执行相同逐像素赋值逻辑,cv.imshow显示为近乎全白的过曝图像 - 原始图像可正常显示,异常效果参考如下:


问题产生原因
核心问题是NumPy数组的数据类型、创建规则和OpenCV的图像显示规则不匹配,具体分为两点:
- 数据类型不符合OpenCV显示要求
cv.imread()读取返回的图像数组默认是uint8(无符号8位整数)类型,像素值合法范围为0~255,对应cv.imshow从纯黑到纯白的亮度映射。
而调用np.zeros()、np.ones()创建数组时,如果不手动指定dtype参数,默认生成的是float64(双精度浮点数)类型数组。cv.imshow对浮点类型数组的亮度映射规则是:仅把0~1.0范围的值映射为纯黑到纯白,所有大于1.0的像素值会被截断为1.0(纯白),小于0的值截断为0(纯黑)。
逐像素赋值给浮点数组的是0~255范围的整数值,几乎所有像素值都远大于1.0,按规则本应显示为全白,出现全黑现象大概率是循环赋值时存在隐式类型转换截断、或OpenCV版本兼容问题,但本质诱因都是未指定正确的数组数据类型。 np.ones()传参错误
NumPy的np.ones()、np.zeros()等数组创建方法,第一个参数要求传入代表数组维度的元组,写np.ones(rows, cols, 3)是把三个整数作为独立位置参数传入,会被函数识别为:shape=rows(仅创建长度为rows的一维数组)、dtype=cols、order=3,直接会触发参数错误,即使不报错,生成的数组形状也和原图不匹配,赋值后自然无法正常显示。
修复方法
初始化拷贝数组时显式指定数据类型为uint8,同时正确传入形状元组即可:
# 正确初始化方式 img_copy = np.zeros((r, c, d), dtype=np.uint8)
如果只是做图像拷贝,直接使用img_copy = img.copy()(和np.copy(img)效果一致)即可,无需写三重循环逐像素赋值,Python层循环效率远低于NumPy内置的向量操作。
内容的提问来源于stack exchange,提问作者Hanif Khan
相关产品推荐
相关产品推荐

