Как подсказывает @HansHirse в комментариях, разница в преобразовании оттенков серого между OpenCV и PIL заключается в том, что OpenCV использует округление до ближайшего целого числа (nint()
), тогда как PIL использует округление до (int()
).
Следующая программа демонстрирует, что путем генерации 1x1 пикселей изображения чистого красного цвета с 0..255, затем чистого зеленого с 0..255 и затем чистого синего с 0..255 и преобразования их с использованием OpenCV и PIL.
#!/usr/bin/env python3
import cv2
from PIL import Image
import numpy as np
print("Varying red through 0..255, showing red component, OpenCV grey, PIL grey")
for r in range(256):
ocvim = np.zeros((1,1,3), dtype=np.uint8)
ocvim[0,0,0] = r
ocvgrey = cv2.cvtColor(ocvim,cv2.COLOR_RGB2GRAY)
pilim = Image.new('RGB',(1,1),(r,0,0)).convert('L')
print(r,ocvgrey[0,0],pilim.getpixel((0,0)))
print("Varying green through 0..255, showing green component, OpenCV grey, PIL grey")
for g in range(256):
ocvim = np.zeros((1,1,3), dtype=np.uint8)
ocvim[0,0,1] = g
ocvgrey = cv2.cvtColor(ocvim,cv2.COLOR_RGB2GRAY)
pilim = Image.new('RGB',(1,1),(0,g,0)).convert('L')
print(g,ocvgrey[0,0],pilim.getpixel((0,0)))
print("Varying blue through 0..255, showing blue component, OpenCV grey, PIL grey")
for b in range(256):
ocvim = np.zeros((1,1,3), dtype=np.uint8)
ocvim[0,0,2] = b
ocvgrey = cv2.cvtColor(ocvim,cv2.COLOR_RGB2GRAY)
pilim = Image.new('RGB',(1,1),(0,0,b)).convert('L')
print(b,ocvgrey[0,0],pilim.getpixel((0,0)))
Если вы хотите, чтобы OpenCV пришел к тому же результату, что и PIL , возможно, самый простой способ - OpenCV выполнить вычисление для значения с плавающей запятой(вместо np.uint8
), чтобы получить дополнительную точность, а затем округлите ее так же, как PIL . Таким образом, вместо:
grey = cv2.cvtColor(uint8im,cv2.COLOR_BGR2GRAY)
вы бы использовали:
grey = cv2.cvtColor(uint8im.astype(np.float32),cv2.COLOR_BGR2GRAY).astype(np.uint8)
Если вы измените формулы в коде в начале моего ответа на этот формат, значения шкалы серого, рассчитанные как OpenCV совпадают с PIL .