本篇是对下面这篇「田土豆」写的文章的补充和修正。
有关函数cv2.imshow()处理不同图像深度时的数据转化问题_田土豆的博客
另外也参考了官方API文档
OpenCV: High-level GUI-imshow()
显示图像的函数,第二个参数img代表了图像多维数组。
当图像多维数组是不同的数据类型,或者说图像是不同的位深度时,最后imshow处理的机制不同。
经测试,在OpenCV的4.5.5版本(不代表是最早不支持的版本)中,不支持CV_32S和CV_16F两种位深度图像。
官方文档的描述如下
- If the image is 8-bit unsigned, it is displayed as is.
- 如果图像是无符号八位整型,是多少数字就最后显示多少;换句话说,imshow()显示图像的精度范围是在0-255之间,正好对应无符号整型。
- If the image is 16-bit unsigned, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [0,255].
- 如果是16位无符号整型,那么由于范围是0-65535,需要将每个像素点除以255得到范围是0-255的深度,而后再显示。
- If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is, the value range [0,1] is mapped to [0,255].
- 如果是32位或64位浮点型,那么因为这个位深度的图像——各像素点的正常取值范围在0-1,像素点需要先乘以255再显示。
- 32-bit integer images are not processed anymore due to ambiguouty of required transform. Convert to 8-bit unsigned matrix using a custom preprocessing specific to image's context.
- 32位(有)符号整型不再加工(显示)由于必要转换的模糊性;因此如果实在要显示32S的图像,先用自定义预处理程序转换至无符号8位整型,才能顺利显示。
田大哥的文章中额外提到一个观点——如果浮点型多维数组有元素取值是负数,那么先取绝对值后再乘以255,最后按255截断。
我在测试他的最后一块代码时,发现并非如此。
我的OpenCV版本是4.5.5,他写文章时用的是4.1.0,兴许是版本更替所致吧!
在4.5.5版本中,不管浮点型多维数组有无负数,都是直接乘以255,得到的数然后进行0-255的饱和运算,也即如果小于0就等于0,如果大于255就等于255。
在Python中运行下列代码
- import numpy as np
- import cv2
- #新建numpy数组,注意np.zero()创建的数据类型为float64
- img=np.zeros((500,500,3))
- #openCV显示图像为BGR格式,通过下列方式,我们绘制三条粗红线
- print(cv2.__version__)
- img[150:170,150:350]=[0,0,-8000]
- img[250:270,150:350]=[0,0,8000]
- img[350:370,150:350]=[0,0,0.34]
- img[450:470,150:350]=[0,0,65555]
- cv2.imshow('img', img)
- cv2.waitKey()
- cv2.destroyAllWindows()
显示的图像如下。因为第一条对应的像素点原值是负数,所以最后饱和运算取值为0,显示成黑色;因为saturate_8U(0.34*255)=86.7,小于saturate_8U(8000*255)=255,所以第三条显示的颜色明显更浅!而由于第四条和第二条对应的像素点都是正整数,所以最后颜色深度相同。