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')
La différence est simple - saturation vs pas de saturation.
cv2.subtract
effectue la saturation. Selon les documents:
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
ousigned 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)