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