Mamo neki

main
Gasper Spagnolo 2022-12-11 08:52:22 -05:00
parent bae4983ce1
commit cf2f58566f
3 changed files with 257 additions and 39 deletions

View File

@ -1,29 +0,0 @@
import numpy as np
import cv2
from matplotlib import pyplot as plt
def normalize_points(P):
# P must be a Nx2 vector of points
# first coordinate is x, second is y
# returns: normalized points in homogeneous coordinates and 3x3 transformation matrix
mu = np.mean(P, axis=0) # mean
scale = np.sqrt(2) / np.mean(np.sqrt(np.sum((P-mu)**2,axis=1))) # scale
T = np.array([[scale, 0, -mu[0]*scale],[0, scale, -mu[1]*scale],[0,0,1]]) # transformation matrix
P = np.hstack((P,np.ones((P.shape[0],1)))) # homogeneous coordinates
res = np.dot(T,P.T).T
return res, T
def draw_epiline(l,h,w):
# l: line equation (vector of size 3)
# h: image height
# w: image width
x0, y0 = map(int, [0, -l[2]/l[1]])
x1, y1 = map(int, [w-1, -(l[2]+l[0]*w)/l[1]])
plt.plot([x0,x1],[y0,y1],'r')
plt.ylim([0,h])
plt.gca().invert_yaxis()

View File

@ -4,14 +4,6 @@ from matplotlib import pyplot as plt
import cv2
import uz_framework.image as uz_image
import uz_framework.text as uz_text
import os
##############################################
# EXCERCISE 1: Exercise 1: Image derivatives #
##############################################
def ex1():
one_b()
def one_a() -> None:
"""
@ -50,16 +42,114 @@ def one_c() -> None:
in x axis in the left camera and at the pixel 300 in the right camera. How far is the
object (in meters) in this case? How far is the object if the object is detected at
pixel 540 in the right camera? Solve this task analytically and bring your solution
to the presentation of the exercise.
to the presentation of the exercise
z1 = 0,16216m
z2 = 0.402m
"""
def one_d() -> None:
"""
Write a script that calculates the disparity for an image pair. Use
the images in the directory disparity. Since the images were pre-processed we can
limit the search for the most similar pixel to the same row in the other image. Since
just the image intensity carries too little information, we will instead compare small
"""
left_image = uz_image.imread_gray('/home/gasperspagnolo/Documents/faks_git/uz_assignments/assignment5/data/disparity/office_left.png', uz_image.ImageType.float64)
right_image = uz_image.imread_gray('/home/gasperspagnolo/Documents/faks_git/uz_assignments/assignment5/data/disparity/office_right.png', uz_image.ImageType.float64)
d = uz_image.get_disparity(left_image, right_image)
plt.imshow(d, cmap='gray')
plt.show()
def two_b() -> None:
"""
mplement a function fundamental_matrix that is given a set of (at least) eight
pairs of points from two images and computes the fundamental matrix using the
eight-point algorithm.
As the eight-point algorithm can be numerically unstable, it is usually not executed
directly on given pairs of points. Instead, the input is first normalized by centering
them to their centroid and scaling their positions so that the average distance to the
centroid is 2. To achieve this, you can use the function normalize_points from
the supplementary material.
Extend the function fundamental_matrix so that it first normalizes the input point-
set of the left camera (we get transformed points and the transformation matrix T1)
and then transform the input point set of the right camera (we get the transformed
points and the transformation matrix T2). Using the transformed points the algo-
rithm computes fundamental matrix ˆF, then transforms it into the original space
using both transformation matrices F = TT
2 ˆFT1.
Test your function for fundamental matrix estimation using ten correspondence
pairs that you load from the file house_points.txt. The columns are formatted as
follows: x1, y1, x2, y2, i.e. the first column contains the x-coordinates of the points for
the first image etc. Compute the fundamental matrix F and for each point in each
image calculate the corresponding epipolar line in the other image. You can draw the
epipolar lines using draw_epiline from the supplementary material. According to
epipolar geometry the corresponding epipolar line should pass through the point. As
a testing reference the correct fundamental matrix is included in the supplementary
material in file house_fundamental.txt
"""
points = np.loadtxt('./data/epipolar/house_points.txt')
left_image = uz_image.imread_gray('./data/epipolar/house1.jpg', uz_image.ImageType.float64)
right_image = uz_image.imread_gray('./data/epipolar/house2.jpg', uz_image.ImageType.float64)
p1 = points[:, :2]
p2 = points[:, 2:]
lines_p1, lines_p2 = uz_image.get_epipolar_lines(p1, p2)
plt.imshow(left_image, cmap='gray')
for line, point in zip(lines_p1, p1):
uz_image.draw_epiline(line, left_image.shape[0], left_image.shape[1])
plt.plot(point[0], point[1], 'r', marker='o', markersize=10)
plt.show()
plt.imshow(right_image, cmap='gray')
for line, point in zip(lines_p2, p2):
uz_image.draw_epiline(line, right_image.shape[0], right_image.shape[1])
plt.plot(point[0], point[1], 'r', marker='o', markersize=10)
plt.show()
def two_c() -> None:
"""
We use the reprojection error as a quantitative measure of the quality of the estimated fundamental matrix.
Write a function reprojection_error that calculates the reprojection error of a
fundamental matrix F given two matching points. For each point, the function
should calculate the corresponding epipolar line from the points match in the other
image, then calculate the perpendicular distance between the point and the line
where a, b and c are the parameters of the epipolar line. Finally, the function should
return the average of the two distances.
Write a script that performs two tests: (1) compute the reprojection error for points
p1 = [85, 233]T
in the left image-plane and p2 = [67, 219]T
in right image-plane using
the fundamental matrix (the error should be approximately 0.15 pixels). (2) Load
the points from the file house_points.txt and compute the average of symmetric
reprojection errors for all pairs of points. If your calculation is correct, the average
error should be approximately 0.33 pixels.
"""
points = np.loadtxt('./data/epipolar/house_points.txt')
p1 = points[:, :2]
p2 = points[:, 2:]
F = uz_image.fundamential_matrix(p1, p2)
print('Reprojection error for house points', uz_image.reprojection_error(F, np.array([[85, 233], [85, 233]]), np.array([[67, 219], [67, 219]])))
print('Reprojection error for house points', uz_image.reprojection_error(F, p1, p2))
# ######## #
# SOLUTION #
# ######## #
def main():
ex1()
#one_d()
two_c()
#ex2()
#ex3()

View File

@ -1460,3 +1460,160 @@ def sift(grayscale_image: npt.NDArray[np.float64],
keypoints = keypoints[:, :-2]
return np.array(keypoints), np.array(descriptors)
def get_disparity(left_image: npt.NDArray[np.float64], right_image: npt.NDArray[np.float64],\
window_size: int = 35, patch_size: int = 11, reduce_size: float = 0.5) -> npt.NDArray[np.float64]:
if(patch_size % 2 == 0 or window_size % 2 == 0):
raise ValueError("Patch/window size must be odd")
# Reduce the size of the images
left_image = cv2.resize(left_image, None, fx=reduce_size, fy=reduce_size)
right_image = cv2.resize(right_image, None, fx=reduce_size, fy=reduce_size)
disparity = np.zeros(left_image.shape)
def get_patches_per_row(y, image, patch_size):
# Get the patches for the given y value
dd = patch_size//2
patches = []
for x in range(dd, image.shape[1] - dd, 1):
patches.append(image[y-dd:y+dd, x-dd:x+dd+1])
return np.array(patches)
def compute_ncc(a, bs):
nccs = []
a = a - np.average(a)
for b in bs:
b = b - np.average(b)
nccs.append(np.sum(a*b) / (np.sqrt(np.sum(a**2)) * np.sqrt(np.sum(b**2))))
return np.array(nccs)
# Get the patches
dd = patch_size//2
dw = window_size//2
for y in tqdm(range(dd, left_image.shape[0] - dd, 1), desc="Computing disparity"):
# Get the patches for the right image
right_patches = get_patches_per_row(y, right_image, patch_size)
left_patches = get_patches_per_row(y, left_image, patch_size)
dd = patch_size//2
dw = window_size//2
xlen = len(left_patches)
for ix in range(xlen):
# Compute the NCC
x = ix + dd
patch = left_patches[ix]
window = right_patches[max(0, ix-dw):min(xlen, ix+dw+1)]
ncc = compute_ncc(patch, window)
# Get the index of the maximum value
index = np.argmax(ncc) + 1
# Compute the disparity
disparity[y, x] = abs(dw - index)
return disparity
def normalize_points(P):
# P must be a Nx2 vector of points
# first coordinate is x, second is y
# returns: normalized points in homogeneous coordinates and 3x3 transformation matrix
mu = np.mean(P, axis=0) # mean
scale = np.sqrt(2) / np.mean(np.sqrt(np.sum((P-mu)**2,axis=1))) # scale
T = np.array([[scale, 0, -mu[0]*scale],[0, scale, -mu[1]*scale],[0,0,1]]) # transformation matrix
P = np.hstack((P,np.ones((P.shape[0],1)))) # homogeneous coordinates
res = np.dot(T,P.T).T
return res, T
def draw_epiline(l,h,w):
# l: line equation (vector of size 3)
# h: image height
# w: image width
x0, y0 = map(int, [0, -l[2]/l[1]])
x1, y1 = map(int, [w-1, -(l[2]+l[0]*w)/l[1]])
plt.plot([x0,x1],[y0,y1],'r')
plt.ylim([0,h])
plt.gca().invert_yaxis()
def fundamential_matrix(P1, P2):
# P1 and P2 are Nx2 vectors of points
# returns: fundamental matrix
N = P1.shape[0]
# normalize points
P1n, T1 = normalize_points(P1)
P2n, T2 = normalize_points(P2)
# compute fundamental matrix
A = np.zeros((N,9))
for i in range(N):
u = P1n[i,0]
v = P1n[i,1]
u_ = P2n[i,0]
v_ = P2n[i,1]
A[i,:] = [u*u_, u_*v, u_, u*v_, v*v_, v_, u, v, 1]
U,S,V = np.linalg.svd(A)
# F is the last column of V
F = V[-1,:].reshape((3,3))
# enforce rank 2
U,S,V = np.linalg.svd(F)
S[-1] = 0
F = np.dot(U,np.dot(np.diag(S),V))
# denormalize
F = np.dot(T2.T,np.dot(F,T1))
return F
def get_epipolar_lines(p1, p2):
F = fundamential_matrix(p1, p2)
p1 = np.hstack((p1, np.ones((p1.shape[0], 1))))
p2 = np.hstack((p2, np.ones((p2.shape[0], 1))))
lines_p2 = np.dot(F, p1.T).T
lines_p1 = np.dot(F.T, p2.T).T
return lines_p1, lines_p2
def reprojection_error(F, p1, p2):
# Add a column of ones to the points, even if there is single point
p1 = np.hstack((p1, np.ones((p1.shape[0], 1))))
p2 = np.hstack((p2, np.ones((p2.shape[0], 1))))
lines_right = []
lines_left = []
for p_left, p_right in zip(p1, p2):
# Left to right
lines_right.append(np.dot(F, p_left).T)
# Right to left
lines_left.append(np.dot(F.T, p_right).T)
lines_right = np.array(lines_right)
lines_left = np.array(lines_left)
# Normalize
lines_right = lines_right / lines_right[:, 2][:, np.newaxis]
lines_left = lines_left / lines_left[:, 2][:, np.newaxis]
# Compute the distances
d_left = np.abs(np.sum(lines_right * p2, axis=1)) / np.sqrt(lines_right[:, 0] ** 2 + lines_right[:, 1] ** 2)
d_right = np.abs(np.sum(lines_left * p1, axis=1)) / np.sqrt(lines_left[:, 0] ** 2 + lines_left[:, 1] ** 2)
repr_err = np.sum((d_left + d_right) ) / (2 * p1.shape[0])
return repr_err