将图像读取为灰度图像并将3通道图像转换为灰度图像有什么区别?
为了清楚起见,如果我按如下方式读取图像:
gray_1 = cv2.imread("model.jpg", 0)
colored = cv2.imread("model.jpg")
gray_2 = cv2.cvtColor(colored, cv2.COLOR_RGB2GRAY)
print(gray_1.shape) #(1152,1536)
print(gray2.shape) #(1152, 1536)
现在,如果我检查两个numpy数组gray_1
和gray_2
的相等性,则它们不相等。
np.array_equal(gray_1, gray_2)
上面的语句返回False
。这是为什么? gray_1
和gray_2
有什么区别?
答案 0 :(得分:3)
请注意,此答案并未说明,也从未声明,灰度加载与彩色加载以及随后转换为灰度之间没有区别。它只是说:
1)OP需要使用cv2.COLOR_BGR2GRAY
而不是cv2.COLOR_RGB2GRAY
进行正确的比较,并且
2)对于准备使用有损JPEG来存储其图像的任何人来说,差异可能微不足道。
OpenCV 本机以BGR顺序存储,因此真正的比较实际上是:
gray_2 = cv2.cvtColor(colored, cv2.COLOR_BGR2GRAY)
与使用cv2.COLOR_RGB2GRAY
相对。
量化两个图像“有何不同” 可能是有帮助的,这两个图像是直接以灰度加载而不是彩色加载然后进行转换的结果,因此我计算了以下统计数据:
绝对错误-只是不同的像素数
峰值绝对误差-任何两个对应像素之间的最大绝对差
平均绝对误差-相应像素之间的平均绝对差
均方误差-相应像素之间的均方差
均方根误差-均方根误差
如果使用标准的512x512 Lena图像,并将直接加载为灰度的图像与加载为彩色并随后转换的图像进行比较,则会得到以下结果:
AE: 139
PAE: 4
MAE: 0.00072479248046875
MSE: 0.001220703125
RMSE: 0.034938562148434216
因此,在262,144个像素中,仅 个像素有139个像素的差异,两个像素之间的最大差异在0..255范围内仅为4,即较小比1.6%
通过比较,如果将保存为JPEG质量90和质量89的Lena图像进行比较,则会得到以下差异:
AE: 158575
PAE: 13
MAE: 0.9766883850097656
MSE: 2.2438392639160156
RMSE: 1.4979450136490378
因此,我说JPEG质量的1%差异会导致100倍的像素差异最多3倍。因此,您选择将数据存储为JPEG的事实比两种灰度转换方法的差异具有更大的影响,并且,如果您真正关心准确性,则应该使用PNG / TIFF / PPM或其他无损格式。 / p>
#!/usr/bin/env python3
import math
import numpy as np
from PIL import Image
import cv2
def compare(im1, im2, metric):
"""
Compare two images in terms of given metric.
'AE' Absolute Error. Simply the number of pixels that are different.
'PAE' Peak Absolute Error. The largest absolute difference between two corresponding pixels.
'MAE' Mean Absolute Error. The average difference between correspondng pixels.
'MSE' Mean Squared Error.
'RMSE' Root Mean Squared Error.
"""
assert(im1.shape==im2.shape)
im1 = np.ravel(im1).astype(np.int64)
im2 = np.ravel(im2).astype(np.int64)
if metric == 'AE':
# Return count of pixels that differ
res = (im1 != im2).sum()
return res
if metric == 'PAE':
# Return largest absolute difference
res = np.abs((im1-im2)).max()
return res
if metric == 'MAE':
# Return average absolute difference between corresponding pixels
res = np.abs((im1-im2)).mean()
return res
# Calculate mean squared difference between corresponding pixels
res = ((im1-im2)*(im1-im2)).mean()
if metric == 'MSE':
return res
if metric == 'RMSE':
return math.sqrt(res)
# Uncomment any one of the three following blocks
# Create greyscale image 640x480 filled with mid-grey
#w,h = 640,480
#im1 = np.zeros([h,w,1], dtype=np.uint8) + 128
#im2 = im1.copy()
#im2[1,1]=7
# Load first image as greyscale, second as colour but then convert to greyscale afterwards
#gray_1 = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
#coloured = cv2.imread('lena.jpg',cv2.IMREAD_COLOR)
#gray_2 = cv2.cvtColor(coloured, cv2.COLOR_BGR2GRAY)
# Load Lena in 89 and 90 JPEG quality
gray_1 = cv2.imread('lena89.jpg',cv2.IMREAD_GRAYSCALE)
gray_2 = cv2.imread('lena90.jpg',cv2.IMREAD_GRAYSCALE)
res = compare(gray_1, gray_2, 'AE')
print('AE: {}'.format(res))
res = compare(gray_1, gray_2, 'PAE')
print('PAE: {}'.format(res))
res = compare(gray_1, gray_2, 'MAE')
print('MAE: {}'.format(res))
res = compare(gray_1, gray_2, 'MSE')
print('MSE: {}'.format(res))
res = compare(gray_1, gray_2, 'RMSE')
print('RMSE: {}'.format(res))
答案 1 :(得分:2)
OpenCV在imload
函数中使用内部编解码器。但是对于cvtColor,它使用以下公式:
RGB[A] to Gray:Y←0.299⋅R + 0.587⋅G + 0.114⋅B
这是一个已知的行为(但看起来像一个错误:))。您可以跟踪here和here的历史记录。
{p>COLOR_BGR2GRAY
(如another answer所建议的那样无效:
In [6]: gray1 = cv2.imread('1.png', 0)
In [7]: col = cv2.imread('1.png')
In [8]: gray2 = cv2.cvtColor(col, cv2.COLOR_RGB2GRAY)
In [10]: np.array_equal(gray1, gray2)
Out[10]: False
In [16]: gray3 = cv2.cvtColor(col, cv2.COLOR_BGR2GRAY)
In [17]: np.array_equal(gray1, gray3)
Out[17]: False
TLDR::它们不同,可以。只要忍受它。