Exemplo n.º 1
0
def get_centers_and_corners(ims: list, Hs: list) -> tuple:
    """
    get the corners and centers of each im in ims
    :param ims: list of grayscale images.
    :param Hs: list of 3x3 homography matrices.
    :return: tuple containing a list of x,y centers  and  a list with x_min,x_max,y_min and y_max
    """
    centers = []
    corners = np.empty((len(ims), 4))
    for i in range(len(ims)):
        rows_cor, cols_cor = ims[i].shape[0] - 1, ims[i].shape[1] - 1

        # get center of im[i]:
        curr_center = np.array([cols_cor / 2, rows_cor / 2]).reshape(1, 2)
        centers.append(apply_homography(curr_center, Hs[i])[0])

        # get corners of im[i]:
        curr_cornrs = np.array([[0, 0], [cols_cor, 0], [0, rows_cor],
                                [cols_cor, rows_cor]]).reshape(4, 2)
        curr_cornrs = apply_homography(curr_cornrs, Hs[i])
        corners[i, 0] = np.min(curr_cornrs[:, 0])  # curr_x_min
        corners[i, 1] = np.max(curr_cornrs[:, 0])  # curr_x_max
        corners[i, 2] = np.min(curr_cornrs[:, 1])  # curr_y_min
        corners[i, 3] = np.max(curr_cornrs[:, 1])  # curr_y_max

    # calc canvas corners
    x_min, x_max = int(np.min(corners[:, 0])), int(np.max(corners[:, 1]))
    y_min, y_max = int(np.min(corners[:, 2])), int(np.max(corners[:, 3]))
    corners = [x_min, x_max, y_min, y_max]
    return centers, corners
Exemplo n.º 2
0
def ransac_homography(pos1: np.ndarray, pos2: np.ndarray, num_iters: int,
                      inlier_tol: np.float32) -> tuple:
    """
    apply RANSAC homography fitting
    :param pos1: an array with n rows of [x,y] coordinates of matched points of first image.
    :param pos2: an array with n rows of [x,y] coordinates of matched points of second image.
    :param num_iters: number of RANSAC iterations to perform.
    :param inlier_tol: inlier tolerance threshold.
    :return: A 3x3 normalized homography matrix and An Array with shape (S,) where S is the number
    of inliers, containing the indices in pos1/pos2 of the maximal set of inlier matches found.
    """
    inliers = np.array([])
    for i in range(num_iters):
        rand_idx = np.random.choice(
            pos1.shape[0], size=NUM_OF_POINTS_TO_TRANS)  # choose 4 points
        pos1_smpl, pos2_smpl = pos1[rand_idx, :], pos2[rand_idx, :]
        h = sol4_add.least_squares_homography(pos1_smpl, pos2_smpl)
        if h is None:
            continue
        pos1_trans = apply_homography(pos1, h)
        e = np.linalg.norm(pos1_trans - pos2, axis=1)**2
        curr_inliers = np.where(
            e < inlier_tol)[0]  # indices of "good" points of pos2
        if len(curr_inliers) > len(inliers):
            inliers = curr_inliers

    H12 = sol4_add.least_squares_homography(pos1[inliers, :], pos2[inliers, :])
    return H12, inliers
Exemplo n.º 3
0
def harris_corner_detector(im: np.ndarray) -> np.ndarray:
    """
    extract harris-corner key feature points
    :param im: the image to extract key points
    :return: An array with shape (N,2) of [x,y] key points locations in im.
    """
    ix = sol4_utils.sp_signal.convolve2d(im, DER_FILTER, 'same', 'wrap')
    iy = sol4_utils.sp_signal.convolve2d(im, DER_FILTER.T, 'same', 'wrap')
    ix_2 = sol4_utils.blur_spatial(ix**2, BLUR_SIZE)
    iy_2 = sol4_utils.blur_spatial(iy**2, BLUR_SIZE)
    ix_iy = sol4_utils.blur_spatial(ix * iy, BLUR_SIZE)
    r = ix_2 * iy_2 - ix_iy**2 - K * (ix_2 +
                                      iy_2)**2  # R - the response of the
    max_of_r = sol4_add.non_maximum_suppression(r)
    pos = np.transpose(np.nonzero(
        max_of_r))  # array of the indices of non-zero pixels in max_of_r
    pos_for_spread = np.transpose(np.array(
        [pos[:, 1], pos[:, 0]]))  # school function works with [yx]
    return pos_for_spread
Exemplo n.º 4
0
def accumulate_homographies(H_successive: list, m: int) -> list:
    """
    get Hi,m from {Hi,i+1 : i = 0..M-1}.
    :param H_successive: A list of 3x3 homography matrices where H successive[i] is a homography
    that transforms points from coordinate system i to coordinate system i+1.
    :param m: Index of the coordinate system we would like to accumulate the given homographies towards.
    :return: A list of M 3x3 homography matrices, where H2m[i] transforms points from coordinate system i
    to coordinate system m.
    """
    less_than_m = H_successive[:m]  # all matrices for i<m
    less_than_m = list(accumulate(less_than_m[::-1],
                                  np.dot))[::-1]  # reverse again to 0-m
    less_than_m.append(np.eye(3))  # add for i=m
    bigger_than_m = H_successive[m:]  # all matrices for i>m
    bigger_than_m = list(map(np.linalg.inv, bigger_than_m))
    bigger_than_m = list(accumulate(bigger_than_m, np.dot))
    H2m = np.array(less_than_m + bigger_than_m)
    H2m = H2m.T / H2m[:, 2, 2]
    return list(H2m.T)
Exemplo n.º 5
0
def render_panorama(ims: list, Hs: list) -> np.ndarray:
    """
    panorama rendering
    :param ims: list of grayscale images.
    :param Hs: list of 3x3 homography matrices. Hs[i] is a homography that transforms points from the
    coordinate system of ims [i] to the coordinate system of the panorama.
    :return: A grayscale panorama image composed of vertical strips, backwarped using homographies from Hs,
    one from every image in ims.
    """
    if len(ims) == 1:
        return ims[0]

    # get data of the shape of the panorama
    centers, corners = get_centers_and_corners(
        ims, Hs)  # corners = [x_min, x_max, y_min, y_max]
    x_min, x_max, y_min, y_max = corners[0], corners[1], corners[2], corners[3]
    width, height = x_max - x_min + 1, y_max - y_min + 1

    # calc a fake shape so it could fit the pyramid blending - only power of 2 sizes
    next_power_of_cols = next_power(width)
    next_power_of_rows = next_power(height)
    cols_pad = next_power_of_cols - width
    rows_pad = next_power_of_rows - height

    # create the canvas of the panorama
    x_pano, y_pano = np.meshgrid(np.arange(x_min, x_max + cols_pad + 1),
                                 np.arange(y_min, y_max + rows_pad + 1))
    panorama = np.zeros(x_pano.shape)  # the canvas of the panorama
    pan_rows, pan_cols = panorama.shape

    # create borders of strips
    borders = [
        int(np.round((centers[i][0] + centers[i + 1][0]) / 2) - x_min)
        for i in range(len(ims) - 1)
    ]
    borders.insert(0, 0)
    borders.append(x_pano.shape[1])

    # apply panorama
    for i in range(len(ims)):
        left = borders[i] - OVERLAP if i != 0 else borders[i]
        right = borders[i + 1] + OVERLAP if i != len(ims) - 1 else borders[i +
                                                                           1]
        x_coord, y_coord = x_pano[:, left:
                                  right], y_pano[:, left:
                                                 right]  # indices of the current part
        xi_yi = np.array([x_coord.flatten(), y_coord.flatten()]).T
        xi_yi = apply_homography(xi_yi, np.linalg.inv(Hs[i]))

        curr_im = map_coordinates(ims[i], [xi_yi[:, 1], xi_yi[:, 0]],
                                  order=1,
                                  prefilter=False)
        curr_im = curr_im.reshape(panorama[:, left:right].shape)

        # apply blending on panorama:
        if i == 0:
            panorama[:, left:right] = curr_im
            continue
        temp_canvas = np.zeros(panorama.shape)
        temp_canvas[:, left:right] = curr_im

        # create a mask and blend them:
        mask = np.ones(panorama.shape)
        mask[:, borders[i]:] = 0
        panorama = sol4_utils.pyramid_blending(panorama, temp_canvas, mask, 4,
                                               15, 15)
        panorama = panorama[:pan_rows, :pan_cols]

    panorama = panorama[:height, :width].astype(
        np.float32)  # back to real shape

    return panorama
Exemplo n.º 6
0
import sol4_utils
from sol4_utils import np
import sol4_add
from itertools import accumulate
import matplotlib.pyplot as plt
from scipy.ndimage.interpolation import map_coordinates

DER_FILTER = np.array([1, 0, -1], np.float32).reshape(1, 3)
BLUR_SIZE = 3
K = 0.04
N = M = 4  # defaults for spread_out_corners n and m
RADIUS = 3
DEFAULT_DESC_RAD = 3
DEFAULT_MIN_SCORE = 0.5
NUM_OF_POINTS_TO_TRANS = 4
EPSILON = 10**-5
OVERLAP = 30


def harris_corner_detector(im: np.ndarray) -> np.ndarray:
    """
    extract harris-corner key feature points
    :param im: the image to extract key points
    :return: An array with shape (N,2) of [x,y] key points locations in im.
    """
    ix = sol4_utils.sp_signal.convolve2d(im, DER_FILTER, 'same', 'wrap')
    iy = sol4_utils.sp_signal.convolve2d(im, DER_FILTER.T, 'same', 'wrap')
    ix_2 = sol4_utils.blur_spatial(ix**2, BLUR_SIZE)
    iy_2 = sol4_utils.blur_spatial(iy**2, BLUR_SIZE)
    ix_iy = sol4_utils.blur_spatial(ix * iy, BLUR_SIZE)
    r = ix_2 * iy_2 - ix_iy**2 - K * (ix_2 +