def output( self, classes, classes_refl, rot, shifts=None, coefs=None, ): """ Return class averages. :param classes: class indices (refering to src). (n_img, n_nbor) :param classes_refl: Bool representing whether to reflect image in `classes` :param rot: Array of in-plane rotation angles (Radians) of image in `classes` :param shifts: Optional array of shifts for image in `classes`. :coefs: Optional Fourier bessel coefs (avoids recomputing). :return: Stack of Synthetic Class Average images as Image instance. """ logger.info(f"Select {self.n_classes} Classes from Nearest Neighbors") # generate indices for random sample (can do something smart with corr later). # For testing just take the first n_classes so it matches earlier plots for manual comparison # This is assumed to be reasonably random. selection = np.arange(self.n_classes) imgs = self.src.images(0, self.src.n) fb_avgs = np.empty((self.n_classes, self.fb_basis.count), dtype=self.src.dtype) for i in tqdm(range(self.n_classes)): j = selection[i] # Get the neighbors neighbors_ids = classes[j] # Get coefs in Fourier Bessel Basis if not provided as an argument. if coefs is None: neighbors_imgs = Image(imgs[neighbors_ids]) if shifts is not None: neighbors_imgs.shift(shifts[i]) neighbors_coefs = self.fb_basis.evaluate_t(neighbors_imgs) else: neighbors_coefs = coefs[neighbors_ids] if shifts is not None: neighbors_coefs = self.fb_basis.shift( neighbors_coefs, shifts[i]) # Rotate in Fourier Bessel neighbors_coefs = self.fb_basis.rotate(neighbors_coefs, rot[j], classes_refl[j]) # Averaging in FB fb_avgs[i] = np.mean(neighbors_coefs, axis=0) # Now we convert the averaged images from FB to Cartesian. return ArrayImageSource(self.fb_basis.evaluate(fb_avgs))
class ImageTestCase(TestCase): def setUp(self): # numpy array for top-level functions that directly expect it self.im_np = misc.face( gray=True).astype('float64')[:768, :768][:, :, np.newaxis] # Independent Image object for testing Image methods self.im = Image(misc.face(gray=True).astype('float64')[:768, :768]) def tearDown(self): pass def testImShift(self): # Ensure that the two separate im_translate functions we have return the same thing # A single shift applied to all images shifts = np.array([100, 200]) im = self.im.shift(shifts) im1 = _im_translate(self.im_np, shifts.reshape(1, 2)) # Note the difference in the concept of shifts for _im_translate2 - negative sign/transpose im2 = _im_translate2(self.im_np, -shifts.reshape(2, 1)) # Pure numpy 'shifting' # 'Shifting' an Image corresponds to a 'roll' of a numpy array - again, note the negated signs and the axes im3 = np.roll(self.im.asnumpy()[:, :, 0], -shifts, axis=(0, 1)) self.assertTrue(np.allclose(im.asnumpy(), im1)) self.assertTrue(np.allclose(im1, im2)) self.assertTrue(np.allclose(im1[:, :, 0], im3)) def testArrayImageSource(self): # An Image can be wrapped in an ArrayImageSource when we need to deal with ImageSource objects. src = ArrayImageSource(self.im) im = src.images(start=0, num=np.inf) self.assertTrue(np.allclose(im.asnumpy(), self.im_np))
class ImageTestCase(TestCase): def setUp(self): # numpy array for top-level functions that directly expect it self.im_np = misc.face(gray=True).astype( np.float64)[np.newaxis, :768, :768] # Independent Image object for testing Image methods self.im = Image(misc.face(gray=True).astype(np.float64)[:768, :768]) # Construct a simple stack of Images self.n = 3 self.ims_np = np.empty((3, *self.im_np.shape[1:]), dtype=self.im_np.dtype) for i in range(self.n): self.ims_np[i] = self.im_np * (i + 1) / float(self.n) # Independent Image stack object for testing Image methods self.ims = Image(self.ims_np) def tearDown(self): pass def testImShift(self): # Ensure that the two separate im_translate functions we have return the same thing # A single shift applied to all images shifts = np.array([100, 200]) im = self.im.shift(shifts) im1 = self.im._im_translate(shifts) # Note the difference in the concept of shifts for _im_translate2 - negative sign im2 = _im_translate2(self.im_np, -shifts) # Pure numpy 'shifting' # 'Shifting' an Image corresponds to a 'roll' of a numpy array - again, note the negated signs and the axes im3 = np.roll(self.im.asnumpy()[0], -shifts, axis=(0, 1)) self.assertTrue(np.allclose(im.asnumpy(), im1.asnumpy())) self.assertTrue(np.allclose(im1.asnumpy(), im2.asnumpy())) self.assertTrue(np.allclose(im1.asnumpy()[0, :, :], im3)) def testArrayImageSource(self): # An Image can be wrapped in an ArrayImageSource when we need to deal with ImageSource objects. src = ArrayImageSource(self.im) im = src.images(start=0, num=np.inf) self.assertTrue(np.allclose(im.asnumpy(), self.im_np)) def testImageSqrt(self): self.assertTrue( np.allclose(self.im.sqrt().asnumpy(), np.sqrt(self.im_np))) self.assertTrue( np.allclose(self.ims.sqrt().asnumpy(), np.sqrt(self.ims_np))) def testImageTranspose(self): self.assertTrue( np.allclose(self.im.flip_axes().asnumpy(), np.transpose(self.im_np, (0, 2, 1)))) # This is equivalent to checking np.tranpose(..., (0, 2, 1)) for i in range(self.ims_np.shape[0]): self.assertTrue( np.allclose(self.ims.flip_axes()[i], self.ims_np[i].T)) # Check against the contruction. self.assertTrue( np.allclose(self.ims.flip_axes()[i], self.im_np[0].T * (i + 1) / float(self.n)))
im = Image(img_data, dtype=np.float64) # %% # Plot the Image Stack # -------------------- # Plot the Image stack im.show() # %% # Apply a Uniform Shift # --------------------- # Apply a single shift to each image. shifts = np.array([100, 30]) im.shift(shifts).show() # %% # Apply Image-wise Shifts # ----------------------- # Or apply shifts corresponding to to each image. shifts = np.array([[300 * i, 100 * i] for i in range(1, im.n_images + 1)]) im.shift(shifts).show() # %% # Downsampling # ------------ im.downsample(80).show()