Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
830 views
in Technique[技术] by (71.8m points)

python - OpenCV image subtraction vs Numpy subtraction

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

OpenCV subtraction result

Numpy subtraction result

#loading images

img_cam0 = cv2.imread(r'C:UsersKrzysztofDesktop1.jpg',0)
img_cam1 = cv2.imread(r'C:UsersKrzysztofDesktop2.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('
')

#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')
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The difference is simple -- saturation vs. no saturation.

cv2.subtract performs saturation. According to the docs:

dst(I) = saturate(src1(I) - src2(I))

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 or signed 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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...