Looking at the cv2 documentation, I got the impression that one should be able in Python to match the writing out of np.float64
data by a np.clip
followed by type coercion to np.uint8
. However, this doesn't seem to be the case. Reproducible example:
import cv2
import numpy as np
arr = np.random.uniform(low=0, high=300, size=(64,48,3))
arr2 = np.clip(arr, 0, 255)
arr3 = arr2.astype(np.uint8)
cv2.imwrite('out1.png', arr)
cv2.imwrite('out2.png', arr2)
cv2.imwrite('out3.png', arr3)
arr1a = cv2.imread('out1.png')
arr2a = cv2.imread('out2.png')
arr3a = cv2.imread('out3.png')
print((arr1a==arr2a).all())
print((arr1a==arr3a).all())
yields True
for the first check and False
for the second check.
This indicates that (1) cv2.imwrite
indeed calls np.clip(arr, 0, 255)
on the array before writing it out; (2) it doesn't then call .astype(np.uint8)
(or at least, that's not all).
My goal is to understand what exactly cv2.imwrite
is doing to arr
. In other words, how can I calculate an array identical to arr1a
in my example above, without saving an intermediate file?
CodePudding user response:
The difference between arr2
and arr3
is that arr3
has had the fractional component of each value truncated. The difference between arr2a
and arr3a
is sometimes 0, and sometimes 1. It looks like imwrite()
might round the values before converting to integers, rather than just removing the fractional part as astype()
does.
Let's do some experimenting to see if this is true.
cv2.imwrite('out2b.png', arr2-0.5)
produces a PNG file that is identical to out3.png
. Likewise,
arr3 = np.round(arr2).astype(np.uint8)
cv2.imwrite('out3b.png', arr3)
produces a PNG file that is identical to out2.png
. Thus, it seems that indeed imwrite()
will round the input floating-point values.