web-dev-qa-db-fra.com

Soustraction d'image OpenCV vs soustraction Numpy

J'essayais de suivre à quel point l'image suivante diffère de la précédente, en supposant un certain mouvement dans la scène. Décidé d'appliquer la soustraction des valeurs de pixels correspondantes entre deux images jpg, puis de calculer la valeur moyenne de la matrice résultante afin de vérifier si elle est inférieure ou inférieure à un certain seuil (pour une analyse plus approfondie).

La soustraction a été effectuée par les méthodes cv2.subtract et np.subtract. J'ai remarqué de grandes différences dans le résultat. Il semble que numpy ait en quelque sorte étiré l'histogramme et les valeurs résultantes normalisées, mais pourquoi?

Les images ont été chargées via cv2.open. Je sais que cette méthode utilise l'ordre BGR des canaux mais elle n'explique pas ce qui s'est passé. Les images chargées sont numpy nd.array avec des valeurs np.uint. Travailler sur Spyder avec Python 3.7.

Edit: l'argument 0 dans cv2.imread indique de charger l'image en niveaux de gris

résultat de la soustraction OpenCV

résultat de la soustraction Numpy

#loading images

img_cam0 = cv2.imread(r'C:\Users\Krzysztof\Desktop\1.jpg',0)
img_cam1 = cv2.imread(r'C:\Users\Krzysztof\Desktop\2.jpg', 0)
print('img0 type:',type(img_cam0), 'and shape:', img_cam0.shape)
print('img1 type:',type(img_cam1),'and shape:', np.shape(img_cam1))
print('\n')

#opencv subtraction

cv2_subt = cv2.subtract(img_cam0,img_cam1)
cv2_mean = cv2.mean(cv2_subt)

print('open cv mean is:', cv2_mean)
f.show_im(cv2_subt, 'cv2_subtr')

#np subtraction and mean

np_subtr = np.subtract(img_cam0, img_cam1)
np_mean = np.mean(np_subtr)

print('numpy mean is:', np_mean)
f.show_im(np_subtr, 'np_subtr')
6
AnotherLazyPeon

La différence est simple - saturation vs pas de saturation.

cv2.subtract effectue la saturation. Selon les documents:

dst(I</a loading= saturate(src1(I) - src2(I))">) ==

numpy.subtract effectue juste une soustraction régulière, donc les résultats sont sujets à débordement d'entier (c'est-à-dire que les valeurs se terminent).


La saturation signifie que lorsque la valeur d'entrée v est hors de la plage du type cible, le résultat n'est pas formé simplement en prenant low bits de l'entrée, mais à la place, la valeur est tronquée. Par exemple:

uchar a = saturate_cast<uchar>(-100); // a = 0 (UCHAR_MIN)
short b = saturate_cast<short>(33333.33333); // b = 32767 (SHRT_MAX)

Un tel découpage est effectué lorsque le type cible est unsigned char, signed char, unsigned short ou signed short. Pour les entiers 32 bits, aucun découpage n'est effectué.


Exemple

>>> import cv2
>>> import numpy as np

>>> a = np.arange(9, dtype=np.uint8).reshape(3,3)
>>> a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]], dtype=uint8)
>>> b = np.full((3,3), 4, np.uint8)
>>> b
array([[4, 4, 4],
       [4, 4, 4],
       [4, 4, 4]], dtype=uint8)

>>> np.subtract(b,a)
array([[  4,   3,   2],
       [  1,   0, 255],
       [254, 253, 252]], dtype=uint8)

>>> cv2.subtract(b,a)
array([[4, 3, 2],
       [1, 0, 0],
       [0, 0, 0]], dtype=uint8)
12
Dan Mašek