def compose_panorama(self, image_left, image_right): """Try to compose the given images into the final panorama. This happens under the assumption that the image transformations were estimated or loaded before. Args: image_left (ndarray): Input left image. image_right (ndarray): Input right image. Returns: ndarray: panorama (stitched image) """ image_left = helpers.add_alpha_channel(image_left) image_right = helpers.add_alpha_channel(image_right) if self.rectify: image_left = self.rectificator.rectify_image(image_left) image_right = self.rectificator.rectify_image(image_right) bounds = helpers.get_boundaries(self.size_left, self.size_right, self.homo_left, self.homo_right) pano_size = (math.ceil(bounds.xmax - bounds.xmin), math.ceil(bounds.ymax - bounds.ymin)) image_left = cv2.warpPerspective(image_left, self.homo_left, pano_size) image_right = cv2.warpPerspective(image_right, self.homo_right, pano_size) alpha = 0.5 cv2.addWeighted(image_left, alpha, image_right, 1 - alpha, 0, image_left) return image_left
def test_add_alpha_channel(left_img): color = left_img['color'] w, h = left_img['size'] # test color image without alpha channel target = helpers.add_alpha_channel(color) assert target.shape == (h, w, 4) # test black and white image img_bw = left_img['bw'] target = helpers.add_alpha_channel(img_bw) assert target.shape == (h, w, 4) # test already alpha img_alpha = np.zeros((3000, 4000, 4), dtype=np.uint8) helpers.add_alpha_channel(img_alpha) assert img_alpha.shape == (h, w, 4) # provoke exception img_not = np.zeros((3000, 4000, 5), dtype=np.uint8) with pytest.raises(Exception): helpers.add_alpha_channel(img_not) # provoke exception img_not = np.zeros((3000, 4000, 5, 4), dtype=np.uint8) with pytest.raises(Exception): helpers.add_alpha_channel(img_not)
def create_prepared_image_dict(img, angle, config): img_alpha = helpers.add_alpha_channel(img['img']) rectificator = prep.Rectificator(config) rect_img = rectificator.rectify_image(img_alpha) rect_detections = rectificator.rectify_points(img['detections'], img['size']) rect_img_w_detections = rectificator.rectify_image(img['img_w_detections']) rot_img, rot_mat = prep.rotate_image(rect_img, angle) rot_detections = prep.rotate_points(rect_detections, angle, img['size']) rot_img_w_detections, rot_mat = prep.rotate_image(rect_img_w_detections, angle) d = dict() d['img'] = rot_img d['detections'] = rot_detections d['img_w_detections'] = rot_img_w_detections return d
def _prepare_image(self, image, angle=0): """Prepare image for stitching. It rotates and rectifies the image. Ff the Stitcher is initialized with ``rectify=False`` the image will not be rectified. Args: image (ndarray): Image to prepare. angle (int): angle in degree to rotate image. Returns: - **image** (ndarray) -- rotated (and rectified) image. - **affine** (ndarray) -- An affine *(3,3)*--matrix for rotation of image or points. """ image = helpers.add_alpha_channel(image) if self.rectify: image = self.rectificator.rectify_image(image) image_rot, affine = prep.rotate_image(image, angle) return image_rot, affine
def pick(self, images, all_pts=True): """Initialise a GUI to pick points on multiple images. A matplot GUI will be initialised, where the user can pick multiple points on the **N** ``images``. Afterwards the :obj:`PointPicker` will return **N** ndarrays, which holds the coordinates of the marked points. Each ndarray holds the points for one image. Args: images (list(ndarray)): List of images (ndarray) all_pts (bool): If ``True`` all points will be returned and else just 'selected' \ points will be returned. Returns: list(ndarray): Returns a List of length **N**, where each cell contains a ndarray \ *(M,2)*, which holds the coordinates of the *M* marked points per image. """ imgs_a = [] for img in images: imgs_a.append(helpers.add_alpha_channel(img)) count_images = len(imgs_a) # creating one list per image, which will hold the draggable marks # e.g. for 2 images: # dms_per_image = [[<dragableMarks first image>],[<dragableMarks second image>]] dms_per_image = [] for __ in range(count_images): dms_per_image.append(draggs.DraggableMarkList()) def _on_click(event): # double click left mouse button if event.button == 1 and event.dblclick: for i, ax in enumerate(axes): if event.inaxes == ax: marker, = ax.plot(event.xdata, event.ydata, 'xr', markersize=10, markeredgewidth=2) dm = draggs.DraggableMark(marker, imgs_a[i]) dm.connect() dms_per_image[i].append(dm) fig.canvas.draw() fig, axes = plt.subplots(nrows=1, ncols=count_images, tight_layout=False) fig.canvas.mpl_connect('button_press_event', _on_click) fig.canvas.set_window_title( 'Point Picker | r-refine point | s-select point | z-zoom | ' 'p-pan | q-quit/finish') # if the nrows == 1 and ncols == 1 the function of plt.subplots returns a single # class 'matplotlib.axes._subplots.AxesSubplot' but we want always an array if count_images == 1: axes = np.array([axes]) for i, image in enumerate(imgs_a): # don't draw y-axis on every image, just on first image if i > 0: plt.setp(axes[i].get_yticklabels(), visible=False) axes[i].imshow(image) plt.show() points = [] for i, dms in enumerate(dms_per_image): points_per_image = dms.get_points(all_pts=all_pts) points.append(points_per_image) return points