nvImageCodec with cuCIM (Linux only)ΒΆ

[1]:
import os
from matplotlib import pyplot as plt
import cupy as cp

Setting resource folder

[2]:
resources_dir = os.getenv("PYNVIMGCODEC_EXAMPLES_RESOURCES_DIR", "../assets/images/")

Import nvImageCodec module and create both Decoder and Encoder

[3]:
from nvidia import nvimgcodec
decoder = nvimgcodec.Decoder()
encoder = nvimgcodec.Encoder()

Read and decode Jpeg2000 file with nvImageCodec

[4]:
nv_img = decoder.read(resources_dir + "cat-1046544_640.jp2")

Convert to cupy ndarray

[5]:
cp_img = cp.asarray(nv_img)
[6]:
cp_img_single_channel = cp_img[:, :, 1]
[7]:
from cucim.skimage.filters import gaussian
cp_img_blurred = gaussian(cp_img_single_channel, sigma=5)
image = cp.asnumpy(cp_img_blurred)
plt.imshow(image, cmap='gray')
[7]:
<matplotlib.image.AxesImage at 0x7fa34c6adc10>
../_images/samples_cucim_sample_11_1.png
[8]:
from cucim.skimage.filters import threshold_otsu
# determine threshold
threshold = threshold_otsu(cp_img_blurred)

# binarize image by apply the threshold
cp_binary_gpu = cp_img_blurred > threshold

image = cp.asnumpy(cp_binary_gpu)
plt.imshow(image, cmap='gray')
[8]:
<matplotlib.image.AxesImage at 0x7fa32432bc40>
../_images/samples_cucim_sample_12_1.png
[9]:
from cucim.skimage.morphology import binary_erosion, disk

eroded_gpu = binary_erosion(cp_binary_gpu, selem=disk(2))
image = cp.asnumpy(eroded_gpu)
plt.imshow(image, cmap='gray')

/tmp/ipykernel_472/1058723275.py:3: FutureWarning: `selem` is a deprecated argument name for `binary_erosion`. It will be removed in cuCIM version 23.02.00.Please use `footprint` instead.
  eroded_gpu = binary_erosion(cp_binary_gpu, selem=disk(2))
[9]:
<matplotlib.image.AxesImage at 0x7fa3242de6d0>
../_images/samples_cucim_sample_13_2.png

We can pass directly nvImageCodec Image object to cuCIM

[10]:
cp_img_blurred_color = gaussian(nv_img, sigma=5)
image = cp.asnumpy(cp_img_blurred_color)
plt.imshow(image)
/tmp/ipykernel_472/2899640136.py:1: FutureWarning: Automatic detection of the color channel was deprecated in v0.19, and `channel_axis=None` will be the new default in v0.21. Set `channel_axis=-1` explicitly to silence this warning.
  cp_img_blurred_color = gaussian(nv_img, sigma=5)
[10]:
<matplotlib.image.AxesImage at 0x7fa324322fa0>
../_images/samples_cucim_sample_15_2.png

Please notice that cuCIM returned blurred color image as a HWC and in float so it must be converted

[11]:
print(cp_img_blurred_color.__cuda_array_interface__)
cp_img_blurred_color = cp_img_blurred_color*255
cp_img_blurred_color_int = cp_img_blurred_color.astype("u1")
print(cp_img_blurred_color_int.__cuda_array_interface__)
{'shape': (475, 640, 3), 'typestr': '<f4', 'descr': [('', '<f4')], 'stream': 1, 'version': 3, 'strides': None, 'data': (140338949783552, False)}
{'shape': (475, 640, 3), 'typestr': '|u1', 'descr': [('', '|u1')], 'stream': 1, 'version': 3, 'strides': None, 'data': (140338943492096, False)}

Pass to nvImageCodec

[12]:
nv_img = nvimgcodec.as_image(cp_img_blurred_color_int)
[13]:
encoder.write("blurred.jpg", nv_img)

Read back with OpenCV to verify

[14]:
import cv2
image = cv2.imread("blurred.jpg")
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)

[14]:
<matplotlib.image.AxesImage at 0x7fa308242d30>
../_images/samples_cucim_sample_22_1.png