%%capture
!pip install kornia
!pip install kornia-rsEdge Detection
kornia.filters components.
import io
import requests
def download_image(url: str, filename: str = "") -> str:
filename = url.split("/")[-1] if len(filename) == 0 else filename
# Download
bytesio = io.BytesIO(requests.get(url).content)
# Save file
with open(filename, "wb") as outfile:
outfile.write(bytesio.getbuffer())
return filename
url = "https://github.com/kornia/data/raw/main/doraemon.png"
download_image(url)import cv2
import kornia as K
import kornia.utils
import numpy as np
import torch
import torchvision
from matplotlib import pyplot as plt
from PIL import ImageWe use Kornia to load an image to memory represented in a torch.tensor
x_rgb: torch.Tensor = (K.image_to_tensor(np.array(Image.open("doraemon.png").convert("RGB"))).float() / 255.0)[
None, ...
] # BxCxHxW
x_gray = K.color.rgb_to_grayscale(x_rgb)def imshow(input: torch.Tensor):
out = torchvision.utils.make_grid(input, nrow=2, padding=5)
out_np: np.ndarray = K.utils.tensor_to_image(out)
plt.imshow(out_np)
plt.axis("off")
plt.show()imshow(x_gray)1st order derivates
grads: torch.Tensor = K.filters.spatial_gradient(x_gray, order=1) # BxCx2xHxW
grads_x = grads[:, :, 0]
grads_y = grads[:, :, 1]# Show first derivatives in x
imshow(1.0 - grads_x.clamp(0.0, 1.0))# Show first derivatives in y
imshow(1.0 - grads_y.clamp(0.0, 1.0))2nd order derivatives
grads: torch.Tensor = K.filters.spatial_gradient(x_gray, order=2) # BxCx2xHxW
grads_x = grads[:, :, 0]
grads_y = grads[:, :, 1]# Show second derivatives in x
imshow(1.0 - grads_x.clamp(0.0, 1.0))# Show second derivatives in y
imshow(1.0 - grads_y.clamp(0.0, 1.0))Sobel Edges
Once with the gradients in the two directions we can computet the Sobel edges. However, in kornia we already have it implemented.
x_sobel: torch.Tensor = K.filters.sobel(x_gray)
imshow(1.0 - x_sobel)Laplacian edges
x_laplacian: torch.Tensor = K.filters.laplacian(x_gray, kernel_size=5)
imshow(1.0 - x_laplacian.clamp(0.0, 1.0))Canny edges
The Canny operator combines gaussian filtering, gradient magnitudes and hysteresis thresholding into the classic edge detector. It provides the magnitudes as well as the edges after the hysteresis process. Note that the edges are a binary image which is not differentiable! We demonstrate it on a second example image.
import kornia
import numpy as np
from PIL import Image
kornia.__version__Now we download the example image.
import io
import requests
def download_image(url: str, filename: str = "") -> str:
filename = url.split("/")[-1] if len(filename) == 0 else filename
# Download
bytesio = io.BytesIO(requests.get(url).content)
# Save file
with open(filename, "wb") as outfile:
outfile.write(bytesio.getbuffer())
return filename
url = "https://github.com/kornia/data/raw/main/paranoia_agent.jpg"
download_image(url)import kornia
import matplotlib.pyplot as plt
import torch
# read the image with Kornia
img_tensor = (kornia.image_to_tensor(np.array(Image.open("paranoia_agent.jpg").convert("RGB"))).float() / 255.0)[
None, ...
] # BxCxHxW
img_array = kornia.tensor_to_image(img_tensor)
plt.axis("off")
plt.imshow(img_array)
plt.show()To apply a filter, we create the Canny operator object and apply it to the data. It will provide the magnitudes as well as the edges after the hysteresis process. Note that the edges are a binary image which is not differentiable!
# create the operator
canny = kornia.filters.Canny()
# blur the image
x_magnitude, x_canny = canny(img_tensor)That’s it! We can compare the source image and the results from the magnitude as well as the edges:
# convert back to numpy
img_magnitude = kornia.tensor_to_image(x_magnitude.byte())
img_canny = kornia.tensor_to_image(x_canny.byte())
# Create the plot
fig, axs = plt.subplots(1, 3, figsize=(16, 16))
axs = axs.ravel()
axs[0].axis("off")
axs[0].set_title("image source")
axs[0].imshow(img_array)
axs[1].axis("off")
axs[1].set_title("canny magnitude")
axs[1].imshow(img_magnitude, cmap="Greys")
axs[2].axis("off")
axs[2].set_title("canny edges")
axs[2].imshow(img_canny, cmap="Greys")
plt.show()Note that our final result still recovers some edges whose magnitude is quite low. Let us increase the thresholds and compare the final edges.
# create the operator
canny = kornia.filters.Canny(low_threshold=0.4, high_threshold=0.5)
# blur the image
_, x_canny_threshold = canny(img_tensor)import torch.nn.functional as F
# convert back to numpy
img_canny_threshold = kornia.tensor_to_image(x_canny_threshold.byte())
# Create the plot
fig, axs = plt.subplots(1, 3, figsize=(16, 16))
axs = axs.ravel()
axs[0].axis("off")
axs[0].set_title("image source")
axs[0].imshow(img_array)
axs[1].axis("off")
axs[1].set_title("canny default")
axs[1].imshow(img_canny, cmap="Greys")
axs[2].axis("off")
axs[2].set_title("canny defined thresholds")
axs[2].imshow(img_canny_threshold, cmap="Greys")
plt.show()