【问题标题】:How are the 2 gray scale images of the same image different?同一图像的 2 个灰度图像有何不同?
【发布时间】:2019-08-12 17:52:41
【问题描述】:

将图像读取为灰度图像与将 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_1gray_2 的相等性,它们不相等。

np.array_equal(gray_1, gray_2)

以上语句返回False。这是为什么? gray_1gray_2 有什么区别?

【问题讨论】:

标签: python opencv image-processing


【解决方案1】:

请注意,此答案没有说明,也从未说明,加载灰度与加载彩色并随后转换为灰度之间没有区别。它只是声明:

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 或其他一些无损格式。


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

【讨论】:

    【解决方案2】:

    OpenCV 在imload 函数中使用内部编解码器。但是对于 cvtColor,它使用这个公式:

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

    这是一种已知行为(但看起来像一个错误 :))。您可以跟踪它的历史记录herehere

    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:它们是不同的,没关系。忍受它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 2013-06-05
      • 2019-10-10
      • 1970-01-01
      相关资源
      最近更新 更多