%%capture
!pip install kornia
!pip install py7zr
Convert RGB to YUV420
Basic
Color spaces
kornia.color
In this tutorial we are going to learn how to convert image from RGB color to YUV420 using
kornia.color
.
Get data and libraries to work with
import io
import requests
def download_image(url: str, filename: str = "") -> str:
= url.split("/")[-1] if len(filename) == 0 else filename
filename # Download
= io.BytesIO(requests.get(url).content)
bytesio # Save file
with open(filename, "wb") as outfile:
outfile.write(bytesio.getbuffer())
return filename
= "https://github.com/kornia/data/raw/main/foreman_qcif.7z"
url download_image(url)
'foreman_qcif.7z'
Import needed libs
import kornia
import numpy as np
# prepare the data, decompress so we have a foreman_qcif.yuv ready
import py7zr
import torch
with py7zr.SevenZipFile("foreman_qcif.7z", mode="r") as z:
z.extractall()
Define functions for reading the yuv file to torch tensor for use in Kornia
import matplotlib.pyplot as plt
def read_frame(fname, framenum):
# A typical 420 yuv file is 3 planes Y, u then v with u/v a quartyer the size of Y
# Build rgb png images from foreman that is 3 plane yuv420
= np.fromfile(fname, dtype=np.uint8, count=int(176 * 144 * 1.5), offset=int(176 * 144 * 1.5) * framenum)
yuvnp = torch.from_numpy(yuvnp[0 : 176 * 144].reshape((1, 1, 144, 176)).astype(np.float32) / 255.0)
y
= yuvnp[176 * 144 : int(144 * 176 * 3 / 2)].reshape((1, 2, int(144 / 2), int(176 / 2)))
uv_tmp # uv (chroma) is typically defined from -0.5 to 0.5 (or -128 to 128 for 8-bit)
= torch.from_numpy(uv_tmp.astype(np.float32) / 255.0) - 0.5
uv return (y, uv)
Sample what the images look like Y, u, v channels separaatly and then converted to rgn through kornia (and back to numpy in this case)
= read_frame("foreman_qcif.yuv", 0) # using compression classic foreman
(y, uv) 0, 0, :, :] * 255.0).astype(np.uint8), cmap="gray")
plt.imshow((y.numpy()[
plt.figure()0, 0, :, :] + 0.5) * 255.0).astype(np.uint8), cmap="gray")
plt.imshow(((uv.numpy()[
plt.figure()0, 1, :, :] + 0.5) * 255.0).astype(np.uint8), cmap="gray")
plt.imshow(((uv.numpy()[
= np.moveaxis(kornia.color.yuv420_to_rgb(y, uv).numpy(), 1, 3).reshape((144, 176, 3))
rgb
print("as converted through kornia")
plt.figure()* 255).astype(np.uint8)) plt.imshow((rgb
as converted through kornia
We can use these in some internal Kornia algorithm implementations. Lets pretend we want to do LoFTR on the red channel
import cv2
= kornia.feature.LoFTR("outdoor")
loftr = read_frame("foreman_qcif.yuv", 175)
(y0, uv0) = read_frame("foreman_qcif.yuv", 185)
(y1, uv1) = kornia.color.yuv420_to_rgb(y0, uv0)
rgb0 = kornia.color.yuv420_to_rgb(y1, uv1)
rgb1
with torch.no_grad():
= loftr({"image0": rgb0[:, 0:1, :, :], "image1": rgb1[:, 0:1, :, :]})
matches
= cv2.drawMatches(
matched_image 0, :, :, :] * 255.0, 0, 2).astype(np.uint8),
np.moveaxis(rgb0.numpy()[0], x[1], 0) for x in matches["keypoints0"].numpy()],
[cv2.KeyPoint(x[0, :, :, :] * 255.0, 0, 2).astype(np.uint8),
np.moveaxis(rgb1.numpy()[0], x[1], 0) for x in matches["keypoints1"].numpy()],
[cv2.KeyPoint(x[0) for x in range(len(matches["keypoints1"].numpy()))],
[cv2.DMatch(x, x, None,
)
=(30, 30))
plt.figure(figsize plt.imshow(matched_image)