Reputation: 141
I was trying to track how much next picture differs from the previous one, assuming some movement in the scene. Decided to apply subtraction of corresponding pixel values between two jpg images and then calculate the mean value of the resulting matrix in order to check if it's below or under some threshold level (for further analysis).
Subtraction was done by cv2.subtract and np.subtract methods. I've noticed quite big differences in the result. It seems like numpy somehow stretched the histogram and normalized resulting values, but why?
Images were loaded via cv2.open. I know this method use BGR order of channels but it doesn't explain what happened. Loaded images are numpy nd.array with np.uint values. Working on Spyder with Python 3.7.
Edit: argument 0 in cv2.imread tells to load image in greyscale
#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')
Upvotes: 12
Views: 28191
Reputation: 19071
The difference is simple -- saturation vs. no saturation.
cv2.subtract
performs saturation. According to the docs:
numpy.subtract
just performs a regular subtraction, so the results are subject to integer overflow (i.e. the values wrap around).
Saturation means that when the input value
v
is out of the range of the target type, the result is not formed just by taking low bits of the input, but instead the value is clipped. For example:uchar a = saturate_cast<uchar>(-100); // a = 0 (UCHAR_MIN) short b = saturate_cast<short>(33333.33333); // b = 32767 (SHRT_MAX)
Such clipping is done when the target type is
unsigned char
,signed char
,unsigned short
orsigned short
. For 32-bit integers, no clipping is done.
Example
>>> 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)
Upvotes: 19