2022-12-10 13:14:44 +01:00
|
|
|
|
import numpy as np
|
|
|
|
|
import numpy.typing as npt
|
|
|
|
|
from matplotlib import pyplot as plt
|
|
|
|
|
import cv2
|
|
|
|
|
import uz_framework.image as uz_image
|
|
|
|
|
import uz_framework.text as uz_text
|
|
|
|
|
|
|
|
|
|
def one_a() -> None:
|
|
|
|
|
"""
|
|
|
|
|
d = (f * px)/pz + f(T - px)/pz => d = (f * T) / pz
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def one_b() -> None:
|
|
|
|
|
"""
|
|
|
|
|
Write a script that computes the disparity for a range of values of pz. Plot the values
|
|
|
|
|
to a figure and set the appropriate units to axes. Use the following parameters of
|
|
|
|
|
the system: focal length is f = 2.5mm and stereo system baseline is T = 12cm
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
pz_values = np.arange(0.001, 0.1, 0.001)
|
|
|
|
|
f = 0.0025
|
|
|
|
|
T = 0.12
|
|
|
|
|
|
|
|
|
|
d = (f * T) / pz_values
|
|
|
|
|
|
|
|
|
|
plt.plot(pz_values, d)
|
|
|
|
|
|
|
|
|
|
plt.xlabel('pz [m]')
|
|
|
|
|
plt.ylabel('d [m]')
|
|
|
|
|
plt.title('Disparity for a range of values of pz')
|
|
|
|
|
plt.show()
|
|
|
|
|
|
|
|
|
|
def one_c() -> None:
|
|
|
|
|
"""
|
|
|
|
|
In order to get a better grasp on the idea of distance and disparity, you will calculate
|
|
|
|
|
the numbers for a specific case. We will take the parameters from a specification of
|
|
|
|
|
a commercial stereo camera Bumblebee2 manufactured by the company PointGray:
|
|
|
|
|
f = 2.5mm, T = 12cm, whose image sensor has a resolution of 648×488 pixels that
|
|
|
|
|
are square and the width of a pixel is 7.4µm. We assume that there is no empty
|
|
|
|
|
space between pixels and that both cameras are completely parallel and equal. Lets
|
|
|
|
|
say that we use this system to observe a (point) object that is detected at pixel 550
|
|
|
|
|
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
|
2022-12-11 14:52:22 +01:00
|
|
|
|
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 point’s 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.
|
2022-12-10 13:14:44 +01:00
|
|
|
|
"""
|
2022-12-11 14:52:22 +01:00
|
|
|
|
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))
|
2022-12-10 13:14:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ######## #
|
|
|
|
|
# SOLUTION #
|
|
|
|
|
# ######## #
|
|
|
|
|
|
|
|
|
|
def main():
|
2022-12-11 14:52:22 +01:00
|
|
|
|
#one_d()
|
|
|
|
|
two_c()
|
2022-12-10 13:14:44 +01:00
|
|
|
|
#ex2()
|
|
|
|
|
#ex3()
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|