uz_assignments/assignment4/a4_utils.py

108 lines
2.8 KiB
Python
Raw Permalink Normal View History

2022-11-26 14:42:48 +01:00
import numpy as np
import cv2
from matplotlib import pyplot as plt
def gauss(sigma):
x = np.arange(np.floor(-3 * sigma), np.ceil(3 * sigma + 1))
k = np.exp(-(x ** 2) / (2 * sigma ** 2))
k = k / np.sum(k)
return np.expand_dims(k, 0)
def gaussdx(sigma):
x = np.arange(np.floor(-3 * sigma), np.ceil(3 * sigma + 1))
k = -x * np.exp(-(x ** 2) / (2 * sigma ** 2))
k /= np.sum(np.abs(k))
return np.expand_dims(k, 0)
def convolve(I: np.ndarray, *ks):
"""
Convolves input image I with all given kernels.
:param I: Image, should be of type float64 and scaled from 0 to 1.
:param ks: 2D Kernels
:return: Image convolved with all kernels.
"""
for k in ks:
k = np.flip(k) # filter2D performs correlation, so flipping is necessary
I = cv2.filter2D(I, cv2.CV_64F, k)
return I
def simple_descriptors(I, Y, X, n_bins = 16, radius = 40, sigma = 2):
"""
Computes descriptors for locations given in X and Y.
I: Image in grayscale.
Y: list of Y coordinates of locations. (Y: index of row from top to bottom)
X: list of X coordinates of locations. (X: index of column from left to right)
Returns: tensor of shape (len(X), n_bins^2), so for each point a feature of length n_bins^2.
"""
assert np.max(I) <= 1, "Image needs to be in range [0, 1]"
assert I.dtype == np.float64, "Image needs to be in np.float64"
g = gauss(sigma)
d = gaussdx(sigma)
Ix = convolve(I, g.T, d)
Iy = convolve(I, g, d.T)
Ixx = convolve(Ix, g.T, d)
Iyy = convolve(Iy, g, d.T)
mag = np.sqrt(Ix ** 2 + Iy ** 2)
mag = np.floor(mag * ((n_bins - 1) / np.max(mag)))
feat = Ixx + Iyy
feat += abs(np.min(feat))
feat = np.floor(feat * ((n_bins - 1) / np.max(feat)))
desc = []
for y, x in zip(Y, X):
miny = max(y - radius, 0)
maxy = min(y + radius, I.shape[0])
minx = max(x - radius, 0)
maxx = min(x + radius, I.shape[1])
r1 = mag[miny:maxy, minx:maxx].reshape(-1)
r2 = feat[miny:maxy, minx:maxx].reshape(-1)
a = np.zeros((n_bins, n_bins))
for m, l in zip(r1, r2):
a[int(m), int(l)] += 1
a = a.reshape(-1)
a /= np.sum(a)
desc.append(a)
return np.array(desc)
def display_matches(I1, pts1, I2, pts2):
"""
Displays matches between images.
I1, I2: Image in grayscale.
pts1, pts2: Nx2 arrays of coordinates of feature points for each image (first columnt is x, second is y coordinates)
"""
assert I1.shape[0] == I2.shape[0] and I1.shape[1] == I2.shape[1], "Images need to be of the same size."
I = np.hstack((I1, I2))
w = I1.shape[1]
plt.imshow(I, cmap='gray')
for p1, p2 in zip(pts1, pts2):
x1 = p1[0]
y1 = p1[1]
x2 = p2[0]
y2 = p2[1]
plt.plot(x1, y1, 'bo', markersize=3)
plt.plot(x2 + w, y2, 'bo', markersize=3)
plt.plot([x1, x2 + w], [y1, y2], 'r', linewidth=.8)
plt.show()