Anurag Sharma
Anurag Sharma

Reputation: 5039

Displaying tif files in jupyter notebook vie ipywidgets

I am trying to display .tif images using the ipywidgets in jupyter-notebooks. The below code works for .png and .jpg files

from ipywidgets import Image
png_image_path = r"C:\Users\xxxxxxxx\Work\Exercises\images\000000000.png"
file = open(png_image_path, "rb")
im = file.read()

Image(
    value=im,
    width=300,
    height=400,
)

type(im) # <class 'bytes'>

The ipywidget from the above code renders the desired image. For reading a tif file I am using gdal.

img = gdal.Open(tif_img_path).ReadAsArray()
print(img.shape) # (3, 1024, 1024)
print(img.transpose(1,2, 0).shape) # (1024, 1024, 3)

type(img.transpose(1,2,0).tobytes()) # <class 'bytes'>

Image(
    value=img.transpose(1,2,0).tobytes(),
    width=300,
    height=400,
)

I get the following output, the image is not properly displayed in the ipywidget

I get the following output

Upvotes: 1

Views: 1969

Answers (1)

Mark Setchell
Mark Setchell

Reputation: 207465

The fact that you just do file.read() on the PNG image implies to me that Jupyter widgets expect a PNG or JPEG-encoded image, with a header and compressed pixel data.

If you open your TIFF with GDAL you will have a Numpy array, so you will need to encode it into an "in-memory" PNG or JPEG before passing to Jupyter widgets. You can do that with OpenCV like this:

import cv2

# Open TIFF image into Numpy array
img = gdal.Open(tif_img_path).ReadAsArray()

# Encode into in-memory PNG for Jupyter
_, PNG = cv2.imencode('.png', img)

As you rightly note in the comments, OpenCV uses BGR ordering so you would need to reverse the order of the colour channels with:

RGBimage =  cv2.cvtColor(BGRimage, cv2.COLOR_BGR2RGB)

As an alternative to introducing the OpenCV dependency and its weird channel ordering, you could use PIL/Pillow which uses regular RGB ordering. In that case, you would convert a Numpy array you got from GDAL into a PNG with:

from io import BytesIO

im = ... read from GDAL ...

# Write Numpy array to in-memory PNG
membuf = BytesIO()
Image.fromarray(im).save(membuf, format="png") 

... you can now use membuf.getvalue()

Note also, that in general TIFFs may contain float or float64 values that cannot be expressed in an 8-bit JPEG, so you may need to re-scale your data to fit the smaller range.

Upvotes: 2

Related Questions