Reading with Pillow¶

When the TIF file is opened with Pillow, it is automatically recognized as a 32-bit floating point image with one channel.

We can verify this with Image.mode, and the value should be F.

See: https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes

In [1]:
from pathlib import Path

import matplotlib.pyplot as plt
from PIL import Image
In [2]:
rgb_path = Path("515d7757-dbe1-4bb8-a817-a917043aae9c", "RGB_camera_0.jpg")
depth_path = Path("515d7757-dbe1-4bb8-a817-a917043aae9c", "DepthRaw_camera_0.tif")

rgb = Image.open(rgb_path)
depth = Image.open(depth_path)
depth.mode
Out[2]:
'F'
In [3]:
fig, axs = plt.subplots(1, 2, figsize=(20, 8))
axs[0].imshow(rgb)
axs[1].imshow(depth);
No description has been provided for this image

Numpy processing¶

When we convert the PIL Image into a Numpy array, we get an array of shape (h, w), which is typical of single-channel images. We recommend the PIL -> Numpy method when working with depth images as arrays.

The values of the array are the distances of the camera to the pixels, in meters.

In [4]:
import cv2
import numpy as np
In [5]:
depth_arr = np.array(depth)  # convert from PIL to Numpy
depth_arr.shape
Out[5]:
(1080, 1920)
In [6]:
# You can also read with OpenCV, which gives the same array, but our tests use
# the Pillow approach so it is more well-maintained.
cv2_arr = cv2.imread(depth_path, cv2.IMREAD_UNCHANGED)
(depth_arr == cv2_arr).all()
Out[6]:
np.True_
In [7]:
depth_arr.min(), depth_arr.max()
Out[7]:
(np.float32(73.0333), np.float32(1061.6786))
In [8]:
plt.figure(figsize=(16, 9))
# clamp to (0, 300) for a more pronounced visualization
plt.imshow(depth_arr, vmin=0, vmax=300)
plt.colorbar()

for x, y in [
    (1355, 640),
    (660, 430),
    (1750, 200),
]:
    plt.annotate(
        f"{depth_arr[y, x]:.2f} m",
        (x, y),
        textcoords="offset points",
        xytext=(0, 10),
        ha="center",
    )
    plt.plot(x, y, "ro")
No description has been provided for this image