from kornia_moons.feature import (
laf_from_opencv_kpts,
opencv_kpts_from_laf,
laf_from_opencv_ORB_kpts, laf_from_opencv_SIFT_kpts)
Viz
visualize_LAF
visualize_LAF (img, LAF, img_idx=0, color='r', linewidth=1, draw_ori=True, fig=None, ax=None, return_fig_ax=False, **kwargs)
Let’s detect ORB keypoints and convert them to and from OpenCV
= cv2.cvtColor(cv2.imread('data/strahov.png'), cv2.COLOR_BGR2RGB)
img
= cv2.ORB_create(500)
det = det.detectAndCompute(img, None)
kps, descs
= cv2.drawKeypoints(img, kps, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
out_img plt.imshow(out_img)
<matplotlib.image.AxesImage>
= cv2.cvtColor(cv2.imread('data/strahov.png'), cv2.COLOR_BGR2RGB)
img
= cv2.ORB_create(500)
det = det.detectAndCompute(img, None)
kps, descs = laf_from_opencv_kpts(kps, 1.0, with_resp=True)
lafs, r =plt.figure()
figFalse), lafs, 0, 'y', draw_ori=False,figsize=(8,6), linewidth=2) visualize_LAF(image_to_tensor(img,
<Figure size 432x288 with 0 Axes>
= cv2.cvtColor(cv2.imread('data/strahov.png'), cv2.COLOR_BGR2RGB)
img
= cv2.ORB_create(500)
det = det.detectAndCompute(img, None)
kps, descs = laf_from_opencv_kpts(kps, 1.0, with_resp=True)
lafs, r = opencv_kpts_from_laf(lafs, 1.0, r)
kps_back = cv2.drawKeypoints(img, kps_back, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
out_img plt.imshow(out_img)
<matplotlib.image.AxesImage>
OpenCV uses different conventions for the local feature scale.
E.g. to get equivalent kornia LAF from ORB keypoints, one should you mrSize = 0.5, while for SIFT – 6.0. The orientation convention is also different for kornia and OpenCV.
epilines_to_start_end_points
epilines_to_start_end_points (epi, h, w)
draw_LAF_matches
draw_LAF_matches (lafs1, lafs2, tent_idxs, img1, img2, inlier_mask=None, draw_dict={'inlier_color': (0.2, 1, 0.2), 'tentative_color': (0.8, 0.8, 0), 'feature_color': (0.2, 0.5, 1), 'vertical': False}, Fm:Optional[<built- infunctionarray>]=None, H:Optional[<built- infunctionarray>]=None, fig=None, ax:Optional=None, return_fig_ax=False)
This function draws LAFs, tentative matches, inliers epipolar lines (if F is provided), and image1 corners reprojection into image 2 (if H is provided)
We will visualize ORB features (blue), tentative matches (yellow) and inliers(greenish)
import numpy as np
= cv2.ORB_create(100)
det = 'data/strahov.png'
img1_fname = det.detectAndCompute(cv2.imread(img1_fname,0), None)
kps1, descs1 = laf_from_opencv_ORB_kpts(kps1)
lafs1 = torch.stack([torch.arange(50),torch.arange(50)], dim=-1)
idxs = draw_LAF_matches(lafs1, lafs1, idxs,
fig, ax
img1_fname,img1_fname, True if i%2 == 0 else False for i in range(len(idxs))],
[={"inlier_color": (0.2, 1, 0.2),
draw_dict"tentative_color": (0.8, 0.8, 0),
"feature_color": (0.2, 0.5, 1),
"vertical": False}, return_fig_ax=True)
Now let’s try with epipolar matrix for the translation. Inliers should lie on the horizontal epipolar lines
= np.array([[0., 0., 0.],
Fmat 0, 0, -1],
[0, 1, 0]])
[
draw_LAF_matches(lafs1, lafs1, idxs,
img1_fname,img1_fname, True if i%2 == 0 else False for i in range(len(idxs))],
[={"inlier_color": (0.2, 1, 0.2),
draw_dict"tentative_color": (0.8, 0.8, 0),
"feature_color": (0.2, 0.5, 1),
"vertical": True}, Fm = Fmat)
libpng warning: iCCP: known incorrect sRGB profile
libpng warning: iCCP: known incorrect sRGB profile
Now we will transform the image, match it, find the homography and visualize it.
import numpy as np
= cv2.SIFT_create(100)
det = 'data/strahov.png'
img1_fname = cv2.cvtColor(cv2.imread(img1_fname), cv2.COLOR_BGR2RGB)
img1
= np.array([[0.5, 0.1, 10],
Hgt -0.1, 0.5, 10],
[0, 0, 1]])
[= cv2.warpPerspective(img1, Hgt, img1.shape[:2][::-1], borderValue=(255,255,255))
img2
= det.detectAndCompute(img1, None)
kps1, descs1 = laf_from_opencv_SIFT_kpts(kps1)
lafs1
= det.detectAndCompute(img2, None)
kps2, descs2 = laf_from_opencv_SIFT_kpts(kps2)
lafs2
= kornia.feature.match_snn(torch.from_numpy(descs1).float(),
match_dists, match_idxs float(), 0.98)
torch.from_numpy(descs2).
= cv2.findHomography(kornia.feature.get_laf_center(lafs1[:,match_idxs[:,0]]).detach().cpu().numpy().reshape(-1,2),
H, mask 1]]).detach().cpu().numpy().reshape(-1,2),
kornia.feature.get_laf_center(lafs2[:,match_idxs[:,0.5)
cv2.USAC_MAGSAC,
draw_LAF_matches(lafs1, lafs2, match_idxs,
img1, img2,
mask,={"inlier_color": (0.2, 1, 0.2),
draw_dict"tentative_color": (0.8, 0.8, 0),
"feature_color": None,
"vertical": False}, H = H)
And the same with fundamental matrix
import numpy as np
= cv2.SIFT_create(75)
det = 'data/strahov.png'
img1_fname = cv2.cvtColor(cv2.imread(img1_fname), cv2.COLOR_BGR2RGB)
img1
= np.array([[0.75, -0.1, 10],
Hgt 0.1, 0.75, 10],
[0, 0, 1]])
[
= cv2.warpPerspective(img1, Hgt, img1.shape[:2][::-1], borderValue=(255,255,255))
img2
= det.detectAndCompute(img1, None)
kps1, descs1 = laf_from_opencv_SIFT_kpts(kps1)
lafs1
= det.detectAndCompute(img2, None)
kps2, descs2 = laf_from_opencv_SIFT_kpts(kps2)
lafs2
= kornia.feature.match_snn(torch.from_numpy(descs1).float(),
match_dists, match_idxs float(), 0.95)
torch.from_numpy(descs2).
= cv2.findFundamentalMat(kornia.feature.get_laf_center(lafs1[:,match_idxs[:,0]]).detach().cpu().numpy().reshape(-1,2),
Fmat, mask 1]]).detach().cpu().numpy().reshape(-1,2),
kornia.feature.get_laf_center(lafs2[:,match_idxs[:,0.5)
cv2.USAC_MAGSAC,
draw_LAF_matches(lafs1, lafs2, match_idxs,
img1, img2,
mask,={"inlier_color": None,#(0.2, 1, 0.2),
draw_dict"tentative_color": (0.8, 0.8, 0),
"feature_color": None,
"vertical": True})
draw_LAF_matches_from_result_dict
draw_LAF_matches_from_result_dict (result_dict, img1, img2, draw_dict={'inlier_color': (0.2, 1, 0.2), 'tentative_color': (0.8, 0.8, 0), 'feature_color': (0.2, 0.5, 1), 'vertical': False})
draw_LAF_inliers_perspective_repjojected
draw_LAF_inliers_perspective_repjojected (lafs1, lafs2, tent_idxs, img1, img2, inlier_mask=None, draw_dict={'inlier_color': (0.2, 1, 0.2), 'reprojected_color': (0.2, 0.5, 1), 'vertical': False}, H:<built-infunctionarray>=None, fig=None, ax:Optional=None, return_fig_ax=False)
This function draws tentative matches and inliers given the homography H
= cv2.SIFT_create(500)
det = 'data/img1.ppm'
img1_fname = 'data/img4.ppm'
img2_fname
= cv2.cvtColor(cv2.imread(img1_fname), cv2.COLOR_BGR2RGB)
img1 = cv2.cvtColor(cv2.imread(img2_fname), cv2.COLOR_BGR2RGB)
img2
= np.loadtxt('data/H1to4p')
Hgt = cv2.warpPerspective(img1, Hgt, img1.shape[:2][::-1], borderValue=(255,255,255))
img2
= det.detectAndCompute(img1, None)
kps1, descs1 = laf_from_opencv_SIFT_kpts(kps1)
lafs1 = det.detectAndCompute(img2, None)
kps2, descs2 = laf_from_opencv_SIFT_kpts(kps2)
lafs2
= kornia.feature.match_snn(torch.from_numpy(descs1).float(),
match_dists, match_idxs float(), 0.98)
torch.from_numpy(descs2).
= cv2.findHomography(kornia.feature.get_laf_center(lafs1[:,match_idxs[:,0]]).detach().cpu().numpy().reshape(-1,2),
H, mask 1]]).detach().cpu().numpy().reshape(-1,2),
kornia.feature.get_laf_center(lafs2[:,match_idxs[:,0.5)
cv2.USAC_MAGSAC,
draw_LAF_inliers_perspective_repjojected(lafs1, lafs2, match_idxs,
cv2.cvtColor(cv2.cvtColor(img1,cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB),
cv2.cvtColor(cv2.cvtColor(img2,cv2.COLOR_RGB2GRAY), cv2.COLOR_GRAY2RGB),= H) mask, H
draw_epipolar_errors_in_single_image
draw_epipolar_errors_in_single_image (kp1:<built-infunctionarray>, kp2:<built-infunctionarray>, Fm1to2:<built-infunctionarray>, img, draw_dict={'error_color': (1, 0.2, 0.2), 'feature_color': (0.2, 0.5, 1), 'figsize': (10, 10), 'markersize': 8}, img_index:int=2, ax:Optional=None, title=None)
This function draws epipolar errors in single image
= np.random.randint(0, 450, (10, 2)).astype(np.float32)
kps1 = kps1 + np.array([20., 20.]).astype(np.float32)
kps2
= image_to_tensor(cv2.cvtColor(cv2.imread('data/strahov.png'), cv2.COLOR_BGR2RGB), False).float()/255.
timg = torch.tensor([[0, 0, 0],
Fm 0, 0, 1],
[0, -1, 0.]]).float()
[
= draw_epipolar_errors_in_single_image(kps1, kps2, Fm, timg) ax
plot_color_line_matches
plot_color_line_matches (lines, lw=2, indices=(0, 1))
Plot line matches for existing images with multiple colors. Args: lines: list of ndarrays of size (N, 2, 2). order: […, 0] is y, […, 0] is x lw: line width as float pixels. indices: indices of the images to draw the matches on.
plot_lines
plot_lines (lines, line_colors='orange', point_colors='cyan', ps=4, lw=2, indices=(0, 1))
Plot lines and endpoints for existing images. Args: lines: list of ndarrays of size (N, 2, 2). order: […, 0] is y, […, 0] is x colors: string, or list of list of tuples (one for each keypoints). ps: size of the keypoints as float pixels. lw: line width as float pixels. indices: indices of the images to draw the matches on.
plot_images
plot_images (imgs, titles=None, cmaps='gray', dpi=100, size=6, pad=0.5)
Plot a set of images horizontally. Args: imgs: a list of NumPy or PyTorch images, RGB (H, W, 3) or mono (H, W). titles: a list of strings, as titles for each image. cmaps: colormaps for monochrome images.
We will visualize line segments from kornia SOLD2
= image_to_tensor(cv2.cvtColor(cv2.imread('data/img1.ppm'), cv2.COLOR_BGR2RGB), False).float()/255.
timg1 = image_to_tensor(cv2.cvtColor(cv2.imread('data/img3.ppm'), cv2.COLOR_BGR2RGB), False).float()/255.
timg2
= kornia.feature.SOLD2(pretrained=True, config=None)
sold2
= kornia.color.rgb_to_grayscale(timg1)
timg1_gray = kornia.color.rgb_to_grayscale(timg2)
timg2_gray
with torch.inference_mode():
= sold2(torch.cat([timg1_gray, timg2_gray], dim=0))
outputs
= outputs["line_segments"][0]
line_seg1 = outputs["line_segments"][1]
line_seg2 = outputs["dense_desc"][0]
desc1 = outputs["dense_desc"][1]
desc2
= [tensor_to_image(timg1_gray), tensor_to_image(timg2_gray)]
imgs_to_plot
= [line_seg1.numpy(), line_seg2.numpy()]
lines_to_plot
"Image 1 - detected lines", "Image 2 - detected lines"])
plot_images(imgs_to_plot, [=3, lw=2, indices={0, 1})
plot_lines(lines_to_plot, ps
with torch.inference_mode():
= sold2.match(line_seg1, line_seg2, desc1[None], desc2[None])
matches
= matches != -1
valid_matches = matches[valid_matches]
match_indices
= line_seg1[valid_matches]
matched_lines1 = line_seg2[match_indices]
matched_lines2
"Image 1 - matched lines", "Image 2 - matched lines"])
plot_images(imgs_to_plot, [=2) plot_color_line_matches([matched_lines1, matched_lines2], lw
import cv2
= cv2.imread('data/img1.ppm', 0)
img_gray
= cv2.createLineSegmentDetector(0)
lsd = lsd.detect(img_gray)[0].reshape(-1, 2, 2)
lines
= lines[..., ::-1]
lines
# OpenCV LSD detector return xy order
"Image 1 - detected LSD lines"])
plot_images([img_gray], [=3, lw=2, indices={0}) plot_lines([lines], ps