Чем отличаются два серых изображения одного и того же изображения? - PullRequest
2 голосов
/ 21 марта 2019

В чем разница между чтением изображения в градациях серого и преобразованием 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?

Ответы [ 2 ]

3 голосов
/ 21 марта 2019

Обратите внимание, что в этом ответе не говорится и никогда не указывалось, что нет разницы между загрузкой в ​​оттенках серого и загрузкой в ​​цвете и последующим преобразованием в оттенки серого. Это просто утверждает, что:

1) OP должен будет использовать cv2.COLOR_BGR2GRAY вместо cv2.COLOR_RGB2GRAY для правильного сравнения и

2) разница, вероятно, незначительна для тех, кто готов использовать JPEG с потерями для хранения своих изображений.


OpenCV изначально хранится в порядке BGR, поэтому истинное сравнение будет на самом деле:

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

вместо использования cv2.COLOR_RGB2GRAY.


Может быть полезно количественно определить «насколько различны» два изображения в результате загрузки непосредственно в оттенках серого по сравнению с загрузкой в ​​цвете и последующим преобразованием, поэтому я вычислил следующую статистику:

  • Абсолютная ошибка - просто количество пикселей, которые отличаются

  • Пиковая абсолютная ошибка - наибольшая абсолютная разница между любыми двумя соответствующими пикселями

  • Средняя абсолютная ошибка - средняя абсолютная разница между соответствующими пикселями

  • Средняя квадратичная ошибка - средняя квадратическая разница между соответствующими пикселями

  • Ошибка среднего квадратного корня - квадратный корень из вышеперечисленного

Если вы используете стандартное изображение Lena 512x512 и сравниваете изображение, загруженное непосредственно в оттенках серого, с изображением, загруженным в цвет и затем преобразованным, вы получите следующие результаты:

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

Таким образом, из 262 144 пикселей только отличаются 139 пикселей, а разница максимум между любыми двумя пикселями составляет всего 4 в диапазоне 0..255, т.е. меньше 1.6 %

Для сравнения, если сравнить изображение Lena, сохраненное с качеством JPEG 90 и качеством 89, вы получите следующую разницу:

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 голосов
/ 21 марта 2019

OpenCV использует внутренние кодеки в функции imload.Но для cvtColor он использует следующую формулу:

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

Это известное поведение (но выглядит как ошибка :)).Вы можете отследить историю этого здесь и здесь .

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: Они разные, и это нормально.Просто живи с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...