简体   繁体   English

同一张图像的2个灰度图像有何不同?

[英]How are the 2 gray scale images of the same image different?

What is the difference between reading an image as grayscale and converting 3-channel image into a grayscale image? 将图像读取为灰度图像并将3通道图像转换为灰度图像之间有什么区别?

To make it clear, if I read an image as follows: 为了清楚起见,如果我阅读如下图像:

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)

Now, if I check the equality of the two numpy arrays gray_1 and gray_2 , they are not equal. 现在,如果我检查两个numpy数组gray_1gray_2相等性,则它们不相等。

np.array_equal(gray_1, gray_2)

The above statement returns False . 上面的语句返回False Why is that? 这是为什么? What is the difference between gray_1 and gray_2 ? gray_1gray_2什么gray_2

Please note that this answer does not state, and has never stated, there is no difference between loading in greyscale versus loading in colour and subsequently converting to greyscale. 请注意,该答案没有陈述,也从未说过,灰度加载与彩色加载以及随后转换为灰度之间没有区别。 It merely states that: 它仅指出:

1) OP would need to use cv2.COLOR_BGR2GRAY rather than cv2.COLOR_RGB2GRAY to make a correct comparison, and 1)OP需要使用cv2.COLOR_BGR2GRAY而不是cv2.COLOR_RGB2GRAY进行正确的比较,并且

2) the difference is likely negligible for anyone who is prepared to use lossy JPEG to store their images. 2)对于准备使用有损JPEG来存储其图像的任何人,差异可能微不足道。


OpenCV natively stores in BGR order, so the true comparison would actually be: OpenCV本机以BGR顺序存储,因此真正的比较实际上是:

gray_2 = cv2.cvtColor(colored, cv2.COLOR_BGR2GRAY)

as opposed to using cv2.COLOR_RGB2GRAY . 与使用cv2.COLOR_RGB2GRAY


It might be helpful to quantify "how different" the two images are as a result of being loaded directly in greyscale versus being loaded in colour and then subsequently converted, so I calculated the following statistics: 量化由于直接以灰度加载而不是彩色加载然后进行转换的结果,这两个图像的“差异”可能会有所帮助,因此我计算了以下统计信息:

  • Absolute Error - simply the number of pixels that differ 绝对误差 -只是像素数不同

  • Peak Absolute Error - the largest absolute difference between any two corresponding pixels 峰值绝对误差 -任何两个对应像素之间的最大绝对差

  • Mean Absolute Error - the average absolute difference between corresponding pixels 平均绝对误差 -相应像素之间的平均绝对差

  • Mean Squared Error - the average squared difference between corresponding pixels 均方误差 -相应像素之间的均方差

  • Root Mean Square Error - square root of the above 均方根误差 -上面的平方根

If you use the standard 512x512 Lena image, and compare the image loaded directly as greyscale with the image loaded as colour and subsequently converted, you will get these results: 如果您使用标准的512x512 Lena图像,并将直接加载为灰度的图像与加载为彩色并随后转换的图像进行比较,则会得到以下结果:

AE: 139
PAE: 4
MAE: 0.00072479248046875
MSE: 0.001220703125
RMSE: 0.034938562148434216

So, of the 262,144 pixels, only 139 pixels differ and the maximum difference between any two pixels is just 4 on a range of 0..255, ie less than 1.6% 因此,在262,144个像素中, 只有 139个像素存在差异,并且任何两个像素之间的最大差异在0..255范围内仅为4,即小于1.6%

By comparison, if you compare the Lena image saved with JPEG quality of 90 versus quality 89, you get the following difference: 相比之下,如果将保存为JPEG质量90和质量89的Lena图像进行比较,则会得到以下差异:

AE: 158575
PAE: 13
MAE: 0.9766883850097656
MSE: 2.2438392639160156
RMSE: 1.4979450136490378

So, I am saying that a 1% difference in JPEG quality causes 100x as many pixels to differ by up to 3x as much. 因此,我是说JPEG质量的1%差异会导致100倍的像素相差3倍之多。 So, the fact you choose to store your data as JPEG has a massively larger impact than the difference in the two greyscale conversion methods, and if you really care about accuracy you should rather use PNG/TIFF/PPM or some other lossless format. 因此,您选择将数据存储为JPEG的事实比两种灰度转换方法的差异具有更大的影响,并且,如果您真正关心准确性,则应该使用PNG / TIFF / PPM或其他无损格式。


#!/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))

OpenCV uses internal codecs in imload function. OpenCV在imload功能中使用内部编解码器。 But for cvtColor, it uses this formula: 但是对于cvtColor,它使用以下公式:

RGB[A] to Gray:Y←0.299⋅R + 0.587⋅G + 0.114⋅B

It is a known behaviour (but looks like a bug :) ). 这是一种已知的行为(但看起来像个错误:))。 You can track the history of it here and here . 您可以在这里这里跟踪其历史。

COLOR_BGR2GRAY , as proposed in another answer will not work: 另一个答案中提出的COLOR_BGR2GRAY将不起作用:

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: They are different and it is OK. TLDR:他们不同,没关系。 Just live with it. 只是忍受它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM