Python - Window 中的图像外观在使用 OpenCV 保存到文件后有所不同
Python - Image Appearance in Window is different after it is saved on file using OpenCV
我有以下代码:
cv2.imshow('RGB Transform Image', rgb_transform)
cv2.waitKey()
cv2.imwrite('rgb_transformed_image', rgb_transform )
当我显示图像时,它看起来像下面这样:
但是看了存档后,图像是这样的:
太奇怪了。我哪里错了?
更新:
我的代码的上下文是我读取了一个灰度图像,拆分它的 RGB,然后在每个通道上执行转换,然后再次组合它。
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
image = imutils.resize(image, width = 500)
a = 255
b = 2 * (np.pi/255)
c = np.pi / 5
R = a * np.absolute(np.sin(b * image))
G = a * np.absolute(np.sin(b * image + c))
B = a * np.absolute(np.sin(b * image + 2 * c))
rgb_transform = np.stack((R,G,B),2)
cv2.imshow('RGB Transform Image', rgb_transform)
cv2.waitKey()
cv2.imwrite('rgb_transformed_image', rgb_transform )
当您给 cv2.imshow
和 cv2.imwrite
一个不同于 uint8
.
类型元素的数组时,这种问题往往会发生
函数 cv2.imshow
在显示图像之前做了一些转换(缩放):
The function may scale the image, depending on its depth:
- If the image is 8-bit unsigned, it is displayed as is.
- If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to
[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].
即使文档对此不是很清楚,cv2.imwrite
也没有进行任何缩放。它最多会转换为 uint8
,但不会进行任何缩放。
让我们来看看您的问题所在。你执行类似
a * np.absolute(np.sin(b * image))
在包含 [0,255] 范围内的值的输入图像上。这些操作的结果是一个 64 位浮点值数组(np.float64
,或在 OpenCV 中 CV_64F
)。经检查,值的范围仍然是 [0.0,255.0].
即使文档似乎没有明确提及这一点,cv2.imshow
也会像对待 32 位浮点数一样对待 64 位浮点数——即在将值显示为3 通道 8 位 BGR 图像。这意味着源图像中强度 > 1 的任何内容都会被裁剪,您看到的大部分是白色像素。
正如我之前提到的,cv2.imwrite
不进行任何缩放,它只是将数据类型转换为它可以使用的类型并保存外观合理的图像。
此问题的解决方案是将浮点值四舍五入为最接近的整数(因此您使用完整范围)并将结果转换为 np.uint8
,然后再将其传递给 cv2.imwrite
或 cv2.imshow
:
rgb_transform = np.uint8(np.around(rgb_transform))
作为一般性建议,了解您要传递给您使用的各种函数的数据类型并与文档进行交叉引用非常有用。
在使用 numpy 数组时,数组的以下几个属性对于检查很有用(我会用你的 rgb_transform
来说话,请随意替换适当的变量名):
rgb_transform.shape
-- 通道大小和数量
rgb_transform.dtype
-- 每个元素的数据类型
rgb_transform.min()
-- 数组中的最小值
rgb_transform.max()
-- 数组中的最大值
当您遇到问题时,最好检查它们的值(在交互式解释器中,或者说使用简单的打印语句)。了解您输入其他功能的数据并将其与文档交叉引用非常重要。
我有以下代码:
cv2.imshow('RGB Transform Image', rgb_transform)
cv2.waitKey()
cv2.imwrite('rgb_transformed_image', rgb_transform )
当我显示图像时,它看起来像下面这样:
但是看了存档后,图像是这样的:
太奇怪了。我哪里错了?
更新:
我的代码的上下文是我读取了一个灰度图像,拆分它的 RGB,然后在每个通道上执行转换,然后再次组合它。
image = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
image = imutils.resize(image, width = 500)
a = 255
b = 2 * (np.pi/255)
c = np.pi / 5
R = a * np.absolute(np.sin(b * image))
G = a * np.absolute(np.sin(b * image + c))
B = a * np.absolute(np.sin(b * image + 2 * c))
rgb_transform = np.stack((R,G,B),2)
cv2.imshow('RGB Transform Image', rgb_transform)
cv2.waitKey()
cv2.imwrite('rgb_transformed_image', rgb_transform )
当您给 cv2.imshow
和 cv2.imwrite
一个不同于 uint8
.
函数 cv2.imshow
在显示图像之前做了一些转换(缩放):
The function may scale the image, depending on its depth:
- If the image is 8-bit unsigned, it is displayed as is.
- If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the value range [0,255*256] is mapped to [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].
即使文档对此不是很清楚,cv2.imwrite
也没有进行任何缩放。它最多会转换为 uint8
,但不会进行任何缩放。
让我们来看看您的问题所在。你执行类似
a * np.absolute(np.sin(b * image))
在包含 [0,255] 范围内的值的输入图像上。这些操作的结果是一个 64 位浮点值数组(np.float64
,或在 OpenCV 中 CV_64F
)。经检查,值的范围仍然是 [0.0,255.0].
即使文档似乎没有明确提及这一点,cv2.imshow
也会像对待 32 位浮点数一样对待 64 位浮点数——即在将值显示为3 通道 8 位 BGR 图像。这意味着源图像中强度 > 1 的任何内容都会被裁剪,您看到的大部分是白色像素。
正如我之前提到的,cv2.imwrite
不进行任何缩放,它只是将数据类型转换为它可以使用的类型并保存外观合理的图像。
此问题的解决方案是将浮点值四舍五入为最接近的整数(因此您使用完整范围)并将结果转换为 np.uint8
,然后再将其传递给 cv2.imwrite
或 cv2.imshow
:
rgb_transform = np.uint8(np.around(rgb_transform))
作为一般性建议,了解您要传递给您使用的各种函数的数据类型并与文档进行交叉引用非常有用。
在使用 numpy 数组时,数组的以下几个属性对于检查很有用(我会用你的 rgb_transform
来说话,请随意替换适当的变量名):
rgb_transform.shape
-- 通道大小和数量rgb_transform.dtype
-- 每个元素的数据类型rgb_transform.min()
-- 数组中的最小值rgb_transform.max()
-- 数组中的最大值
当您遇到问题时,最好检查它们的值(在交互式解释器中,或者说使用简单的打印语句)。了解您输入其他功能的数据并将其与文档交叉引用非常重要。