Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use `cv2.imshow` correctly for the float image returned by `cv2.distanceTransform`?

Something weird is going on with cv2.imshow. I was writing a piece of code and wondering why one of my operations wasn't working (as diagnosed by observing cv2.imshow). In exasperation I ended up writing the very same image to a file wherein it looks fine. Why is cv2.imshow showing a binary image (first image below) while cv2.imwrite writing the grayscale image as intended (second image)? I've never had problems with displaying grayscale images before!

cv2.imshow('Latest', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

distTransform = cv2.distanceTransform(src=image,distanceType=cv2.DIST_L2,maskSize=5)
cv2.imwrite('distanceTransform.png', distTransform)

cv2.imshow('Latest', distTransform)
cv2.waitKey(0)
cv2.destroyAllWindows()

This is the image as it's displayed by cv2.imshow: distanceTransform.png as displayed by cv2.imshow (also the same as the input image)

This is the image as it's saved by imwrite: distanceTransform.png as written by imwrite

like image 906
vheissu Avatar asked Jan 18 '18 22:01

vheissu


1 Answers

When use cv2.imshow, you should know:

imshow(winname, mat) -> None
. The function may scale the image, depending on its depth:
. - If the image is 8-bit unsigned, it is displayed as is.
. - If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. 
    That is, the value range [0,255\*256] is mapped to [0,255].
. - If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is, the
.   value range [0,1] is mapped to [0,255].

The function distaceTransform return type float. So when directly display the dist, it first multiply 255, then map to [0,255]. So the result just like binary image. (0*255=>0, 1*255=>255, ...*255=>255).

To display correctly:

(1) you can clip the float dist to [0,255] and change the datatype to np.uint8 by cv2.convertScaleAbs

dist1 = cv2.convertScaleAbs(dist)

(2) you can also normalize float dist to [0,255] and change datatype by cv2.normalize

dist2 = cv2.normalize(dist, None, 255,0, cv2.NORM_MINMAX, cv2.CV_8UC1)

Here is an example with panda:

enter image description here

The result:

enter image description here


Full code:

#!/ust/bin/python3
# 2018.01.19 10:24:58 CST
img = cv2.imread("panda.png", 0)
dist = cv2.distanceTransform(src=img,distanceType=cv2.DIST_L2,maskSize=5)
dist1 = cv2.convertScaleAbs(dist)
dist2 = cv2.normalize(dist, None, 255,0, cv2.NORM_MINMAX, cv2.CV_8UC1)

cv2.imshow("dist", dist)
cv2.imshow("dist1", dist1)
cv2.imshow("dist2", dist2)
cv2.waitKey()
like image 127
Kinght 金 Avatar answered Oct 22 '22 22:10

Kinght 金