def test_matrix(self, level=1): x = np.arange(9).reshape((3, 3)) + 1 theta = -np.pi / 2 M = np.array([[np.cos(theta), -np.sin(theta), 0], [np.sin(theta), np.cos(theta), 2], [0, 0, 1]]) x90 = transform.matrix(x, M, order=1) assert_array_almost_equal(x90, np.rot90(x))
def test_matrix(self,level=1): x = np.arange(9).reshape((3,3)) + 1 theta = -np.pi/2 M = np.array([[np.cos(theta), -np.sin(theta), 0], [np.sin(theta), np.cos(theta), 2], [0, 0, 1]]) x90 = transform.matrix(x, M, order=1) assert_array_almost_equal(x90, np.rot90(x))
def with_transform(images, matrices, weights=None, order=1, oshape=None, save_tiff=False, method='interpolate'): """Stack images after performing coordinate transformations. Parameters ---------- images : list of ndarray Images to be stacked. matrices : list of (3,3) ndarray Coordinate transformation matrices. weights : list of float Weight of each input image. By default, all images are weighted equally. The merging algorithm takes into account whether images overlap. order : int Order of the interpolant used by the scaling algorithm. Linear, by default. oshape : tuple of int Output shape. If not specified, the output shape is auto determined to include all images. save_tiff : bool Whether to save copies of the warped images. False by default. method : {'interpolate', 'polygon'} Use standard interpolation (default) or polygon interpolation. Note: Polygon interpolation is currently disabled. Notes ----- For each image, a 3x3 coordinate transformation matrix, ``A``, must be given. Each coordinate, ``c = [x,y,1]^T``, in the source image is then translated to its position in the destination image, ``d = A*c``. After warping the images, they are combined according to the given weights. Note that the overlap of frames is taken into account. For example, in areas where only one image occurs, the pixels of that image will carry a weight of one, whereas in other areas it may be less, depending on the overlap of other images. """ nr_images = len(images) if weights is None: weights = np.ones(nr_images, dtype=sc.ftype) / nr_images if not (len(images) == len(matrices) == len(weights)): raise ValueError("Number of images, transformation matrices and " "weights should match.") images = [np.atleast_2d(i) for i in images] affine_matrices = [np.atleast_2d(m) for m in matrices] reshape = (oshape is None) if reshape: all_tf_cnrs = np.empty((0,2)) for img, tf_matrix in zip(images, matrices): rows, cols = img.shape[:2] tf_cnrs = _tf_corners(rows, cols, tf_matrix) all_tf_cnrs = np.vstack((all_tf_cnrs, tf_cnrs)) # Calculate bounding box [(x0,y0),(x1,y1)] bbox_top_left = np.floor(all_tf_cnrs.min(axis=0)) bbox_bottom_right = np.ceil(all_tf_cnrs.max(axis=0)) oshape = np.array(images[0].shape) oshape[:2][::-1] = np.absolute(bbox_bottom_right - bbox_top_left).astype(int) + 1 sources = [] boundaries = [] for n, (img, tf_matrix, weight) in \ enumerate(zip(images, affine_matrices, weights)): if reshape: tf_matrix = tf_matrix.copy() tf_matrix[:2,2] -= bbox_top_left boundaries.append(_tf_corners(img.shape[0] + 1, img.shape[1] + 1, tf_matrix)) # if method == 'polygon': # sources.append(interp_transf_polygon(img, np.linalg.inv(tf_matrix), # oshape)) # else: sources.append(transform.matrix(img, tf_matrix, output_shape=oshape, order=order, mode='reflect')) log.info('Transformed image %d' % n) if save_tiff: from scipy.misc import imsave for n, (s, bounds) in enumerate(zip(sources, boundaries)): # Convert to 4-channel RGBA tmp = np.empty(np.append(s.shape[:2], 4), dtype=s.dtype) if s.ndim == 3: print tmp.shape, s.shape tmp[..., :3] = s[..., :3] # Keep red layer for use as mask s = s[..., 0] else: # Fill R, G, and B tmp.T.swapaxes(1, 2)[:] = s tmp[..., 3] = 0 mask = mask_roi(s.shape[0], s.shape[1], bounds) # Set the alpha mask t = tmp[...,3] t.fill(255) t[~mask] = 0 imsave('stack_%d.tiff' % n, tmp) out = np.zeros(oshape, dtype=sc.ftype) total_weights = np.zeros(oshape, dtype=float) for (s, bounds), w in zip(zip(sources, boundaries), weights): mask = mask_roi(s.shape[0], s.shape[1], bounds) out[mask] += (w * s)[mask] total_weights[mask] += w mask = (total_weights != 0) out[mask] = out[mask] / total_weights[mask] return out
def with_transform(images, matrices, weights=None, order=1, oshape=None, save_tiff=False, method='interpolate'): """Stack images after performing coordinate transformations. Parameters ---------- images : list of ndarray Images to be stacked. matrices : list of (3,3) ndarray Coordinate transformation matrices. weights : list of float Weight of each input image. By default, all images are weighted equally. The merging algorithm takes into account whether images overlap. order : int Order of the interpolant used by the scaling algorithm. Linear, by default. oshape : tuple of int Output shape. If not specified, the output shape is auto determined to include all images. save_tiff : bool Whether to save copies of the warped images. False by default. method : {'interpolate', 'polygon'} Use standard interpolation (default) or polygon interpolation. Note: Polygon interpolation is currently disabled. Notes ----- For each image, a 3x3 coordinate transformation matrix, ``A``, must be given. Each coordinate, ``c = [x,y,1]^T``, in the source image is then translated to its position in the destination image, ``d = A*c``. After warping the images, they are combined according to the given weights. Note that the overlap of frames is taken into account. For example, in areas where only one image occurs, the pixels of that image will carry a weight of one, whereas in other areas it may be less, depending on the overlap of other images. """ nr_images = len(images) if weights is None: weights = np.ones(nr_images, dtype=sc.ftype) / nr_images if not (len(images) == len(matrices) == len(weights)): raise ValueError("Number of images, transformation matrices and " "weights should match.") images = [np.atleast_2d(i) for i in images] affine_matrices = [np.atleast_2d(m) for m in matrices] reshape = (oshape is None) if reshape: all_tf_cnrs = np.empty((0, 2)) for img, tf_matrix in zip(images, matrices): rows, cols = img.shape[:2] tf_cnrs = _tf_corners(rows, cols, tf_matrix) all_tf_cnrs = np.vstack((all_tf_cnrs, tf_cnrs)) # Calculate bounding box [(x0,y0),(x1,y1)] bbox_top_left = np.floor(all_tf_cnrs.min(axis=0)) bbox_bottom_right = np.ceil(all_tf_cnrs.max(axis=0)) oshape = np.array(images[0].shape) oshape[:2][::-1] = np.absolute(bbox_bottom_right - bbox_top_left).astype(int) + 1 sources = [] boundaries = [] for n, (img, tf_matrix, weight) in \ enumerate(zip(images, affine_matrices, weights)): if reshape: tf_matrix = tf_matrix.copy() tf_matrix[:2, 2] -= bbox_top_left boundaries.append( _tf_corners(img.shape[0] + 1, img.shape[1] + 1, tf_matrix)) # if method == 'polygon': # sources.append(interp_transf_polygon(img, np.linalg.inv(tf_matrix), # oshape)) # else: sources.append( transform.matrix(img, tf_matrix, output_shape=oshape, order=order, mode='reflect')) log.info('Transformed image %d' % n) if save_tiff: from scipy.misc import imsave for n, (s, bounds) in enumerate(zip(sources, boundaries)): # Convert to 4-channel RGBA tmp = np.empty(np.append(s.shape[:2], 4), dtype=s.dtype) if s.ndim == 3: print tmp.shape, s.shape tmp[..., :3] = s[..., :3] # Keep red layer for use as mask s = s[..., 0] else: # Fill R, G, and B tmp.T.swapaxes(1, 2)[:] = s tmp[..., 3] = 0 mask = mask_roi(s.shape[0], s.shape[1], bounds) # Set the alpha mask t = tmp[..., 3] t.fill(255) t[~mask] = 0 imsave('stack_%d.tiff' % n, tmp) out = np.zeros(oshape, dtype=sc.ftype) total_weights = np.zeros(oshape, dtype=float) for (s, bounds), w in zip(zip(sources, boundaries), weights): mask = mask_roi(s.shape[0], s.shape[1], bounds) out[mask] += (w * s)[mask] total_weights[mask] += w mask = (total_weights != 0) out[mask] = out[mask] / total_weights[mask] return out