def fast_warp(img, tf, output_shape, mode='constant', mode_cval=0, order=0): """Warp an image according to a given coordinate transformation. This wrapper function is faster than skimage.transform.warp Args: img: `ndarray`, input image tf: For 2-D images, you can directly pass a transformation object e.g. skimage.transform.SimilarityTransform, or its inverse. output_shape: tuple, (rows, cols) mode: mode for transformation available modes: {`constant`, `edge`, `symmetric`, `reflect`, `wrap`} mode_cval: float, Used in conjunction with mode `constant`, the value outside the image boundaries order: int, The order of interpolation. The order has to be in the range 0-5: 0: Nearest-neighbor 1: Bi-linear (default) 2: Bi-quadratic 3: Bi-cubic 4: Bi-quartic 5: Bi-quintic Returns: warped, double `ndarray` """ m = tf.params t_img = np.zeros((img.shape[0], ) + output_shape, img.dtype) for i in range(t_img.shape[0]): t_img[i] = _warp_fast(img[i], m, output_shape=output_shape, mode=mode, cval=mode_cval, order=order) return t_img
def fast_warp(img, tf, output_shape, mode="constant", order=0): """ This wrapper function is faster than skimage.transform.warp """ m = tf.params t_img = np.zeros((img.shape[0],) + output_shape, img.dtype) for i in range(t_img.shape[0]): t_img[i] = _warp_fast(img[i], m, output_shape=output_shape, mode=mode, order=order) return t_img
def fast_warp(img, tf, output_shape, mode='constant', order=0): """ This wrapper function is faster than skimage.transform.warp """ m = tf.params t_img = np.zeros((img.shape[0],) + output_shape, img.dtype) for i in range(t_img.shape[0]): t_img[i] = _warp_fast(img[i], m, output_shape=output_shape, mode=mode, order=order) return t_img
def compute_drt(img, angles=None, n_beams=600): if (img.ndim != 2): raise ValueError("Error: Input image must be 2D") if (angles is None): angles = np.arange(360) # full 360 degrees for rotational invariance # Scale image for desired beam count scale = n_beams / np.ceil(np.sqrt(2) * max(img.shape)) img = rescale(img, scale=scale, mode="reflect") # Pad image (same as radon_transform.py) diagonal = np.sqrt(2) * max(img.shape) pad = [int(np.ceil(diagonal - s)) for s in img.shape] new_center = [(s + p) // 2 for s, p in zip(img.shape, pad)] old_center = [s // 2 for s in img.shape] pad_before = [nc - oc for oc, nc in zip(old_center, new_center)] pad_width = [(pb, p - pb) for pb, p in zip(pad_before, pad)] padded_image = np.pad(img, pad_width, mode="constant", constant_values=0) assert padded_image.shape[0] == padded_image.shape[ 1] # assert padded image is square # Define radon image vars sinogram = np.zeros((padded_image.shape[0], len(angles))) center = padded_image.shape[0] // 2 shift0 = np.array([[1, 0, -center], [0, 1, -center], [0, 0, 1]]) shift1 = np.array([[1, 0, center], [0, 1, center], [0, 0, 1]]) # Construct matrix for rotating (beam directions) def build_rotation(angle): T = np.deg2rad(angle) R = np.array([[np.cos(T), np.sin(T), 0], [-np.sin(T), np.cos(T), 0], [0, 0, 1]]) return shift1.dot(R).dot(shift0) # Build sinogram for i in range(len(angles)): rotated_img = _warp_fast(padded_image, build_rotation(angles[i])) # Compute ith angle beam sum vector, i.e. all beams on current angle sinogram[:, i] = rotated_img.sum(0) return sinogram
def __radon(self, image, theta=None): if image.ndim != 2: raise ValueError('The input image must be 2-D') if theta is None: raise ValueError('there is no theta in __radon!!!') height, width = image.shape diagonal = np.sqrt(height**2 + width**2) heightpad = np.ceil(diagonal - height) widthpad = np.ceil(diagonal - width) #padding image, so whole img is visible to "rays" while rotating padded_image = np.zeros((int(height + heightpad), int(width + widthpad))) y0, y1 = int(np.ceil(heightpad / 2)), int((np.ceil(heightpad / 2) + height)) x0, x1 = int((np.ceil(widthpad / 2))), int((np.ceil(widthpad / 2) + width)) padded_image[y0:y1, x0:x1] = image #plt.imshow(padded_image, cmap=plt.cm.Greys_r) #plt.show() if self.__firstGen: sinogram = np.zeros((padded_image.shape[0], len(theta))) else: sinogram = np.zeros((self.__detNum, len(theta))) h, w = padded_image.shape dh, dw = h // 2, w // 2 for i in xrange(len(theta)): # apply transformation matrix to img, requires inverse of transformation matrix rotated = _warp_fast(padded_image, np.linalg.inv(self.__build_rotation(-theta[i], dw, dh)), mode="wrap") #rotated = warp(padded_image, np.linalg.inv(self.__build_rotation(-theta[i], dw, dh))) if not self.__firstGen: sinogram[:, i] = self.__radon_view(rotated) else: sinogram[:, i] = rotated.sum(0)[::-1] return sinogram
def fast_warp(img, tf, mode='constant', order=0): m = tf.params t_img = np.zeros(img.shape, img.dtype) for i in range(t_img.shape[0]): t_img[i] = _warp_fast(img[i], m, mode=mode, order=order) return t_img
def perform(self, node, inputs, out_storage): x, rot, shear, scale, trans, oshape = inputs #foobar.append_ndarray_signature(x, 'AffineImageWarp x') aff = AffineTransform(rotation=rot, shear=shear, scale=scale, translation=trans) if str(x.dtype) != node.inputs[0].dtype: raise TypeError("Wrong dtype argument to AffineImageWarp", x.dtype) if np.any(x < 0): raise ValueError('X should be positive') if np.any(x > 1.0): raise ValueError('X should be less than 1') N, C, H, W = x.shape rows, cols = oshape rval = out_storage[0][0] rval_shape = (N, C, rows, cols) if ((rval is None) or (rval.dtype != x.dtype) or rval.shape != rval_shape): rval3 = np.empty((N * C, rows, cols), dtype=x.dtype) bg_check = True else: rval3 = rval.reshape((N * C, rows, cols)) bg_check = False xx = x.reshape(N * C, H, W) # -- a small exactly-representable float for out-of-bounds pixels oob = -1.0 / 2 ** 16 order = 1 # TODO: TRY ORDER=2 (WHY DOES RANGE GET LARGER?) tform = np.linalg.inv(aff._matrix) for i in xrange(N * C): if bg_check and i == 0: rval3[i] = _warp_fast(xx[i], tform, output_shape=oshape, order=order, cval=oob) oob_ratio = np.mean(rval3[i] == oob) if oob_ratio > 0.5: raise InvalidDescription('too much background', oob_ratio) rval3[i] = np.maximum(0, rval3[i]) else: rval3[i] = _warp_fast(xx[i], np.linalg.inv(aff._matrix), output_shape=oshape, order=order, cval=0) if 0 and i == 0: print 'Debugprint from AffineImageWarp...' for sym in 'rot', 'shear', 'scale', 'trans', 'oshape': print sym, ':', locals()[sym] import matplotlib.pyplot as pl pl.subplot(2, 1, 1) pl.imshow(xx[i], cmap=pl.cm.gray) pl.subplot(2, 1, 2) pl.imshow(rval3[i], cmap=pl.cm.gray) pl.show() time.sleep(2) # -- give some time to ctrl-C if np.any(rval3 > 1.001) or np.any(rval3 < 0.0): min3 = np.min(rval3) max3 = np.max(rval3) raise ValueError('interpolated pixel values out of range', (min3, max3)) out_storage[0][0] = rval3.reshape(rval_shape)
def __iradon(self, radon_image, theta=None, output_size=None, fft_filter=False, filter="ramp"): th = (np.pi / 180.0) * theta n = radon_image.shape[0] img = radon_image.copy() if fft_filter: #fft filter # resize image to next power of two for fourier analysis # speeds up fourier and lessens artifacts order = max(64., 2**np.ceil(np.log(2 * n) / np.log(2))) # zero pad input image img.resize((order, img.shape[1])) #construct the fourier filter f = fftshift(abs(np.mgrid[-1:1:2 / order])).reshape(-1, 1) w = 2 * np.pi * f # start from first element to avoid divide by zero if filter == "ramp": pass elif filter == "shepp-logan": f[1:] = f[1:] * np.sin(w[1:] / 2) / (w[1:] / 2) elif filter == "cosine": f[1:] = f[1:] * np.cos(w[1:] / 2) elif filter == "hamming": f[1:] = f[1:] * (0.54 + 0.46 * np.cos(w[1:])) elif filter == "hann": f[1:] = f[1:] * (1 + np.cos(w[1:])) / 2 elif filter == None: f[1:] = 1 else: raise ValueError("Unknown filter: %s" % filter) filter_ft = np.tile(f, (1, len(theta))) # apply filter in fourier domain projection = fft(img, axis=0) * filter_ft radon_filtered = np.real(ifft(projection, axis=0)) else: #normal filter filter_size = 10 filter_tab = np.zeros((2*filter_size+1)) for k in xrange(-filter_size,filter_size): if(k%2!=0): filter_tab[k+filter_size] = -4.0 / (np.pi**2 * k**2) filter_tab[filter_size]=1 radon_filtered = np.zeros((img.shape[0], img.shape[1])) for i in xrange(img.shape[1]): radon_filtered[:,i] = np.convolve(img[:,i],filter_tab, mode='same') # resize filtered image back to original size radon_filtered = radon_filtered[:radon_image.shape[0], :] reconstructed = np.zeros((output_size, output_size)) mid_index = np.ceil(n / 2.0) x = output_size y = output_size [X, Y] = np.mgrid[0.0:x, 0.0:y] xpr = X - int(output_size) // 2 ypr = Y - int(output_size) // 2 # reconstruct image by interpolation for i in xrange(len(theta)): t = xpr * np.sin(th[i]) - ypr * np.cos(th[i]) a = np.floor(t) b = mid_index + a b0 = ((((b + 1 > 0) & (b + 1 < n)) * (b + 1)) - 1).astype(np.int) b1 = ((((b > 0) & (b < n)) * b) - 1).astype(np.int) reconstructed += (t - a) * radon_filtered[b0, i] + (a - t + 1) * radon_filtered[b1, i] #debug #print b0 #print i #print b1 #plt.subplot(221) #plt.imshow(reconstructed, cmap=plt.cm.Greys_r) #plt.subplot(222) #plt.imshow((t - a) * radon_filtered[b0, i], cmap=plt.cm.Greys_r) #plt.subplot(223) #plt.imshow((a - t + 1) * radon_filtered[b1, i], cmap=plt.cm.Greys_r) #plt.show() h, w = reconstructed.shape dh, dw = h // 2, w // 2 if not self.__firstGen: rotated = _warp_fast(reconstructed, np.linalg.inv(self.__build_rotation(90, dw, dh))) #rotated = warp(reconstructed, np.linalg.inv(self.__build_rotation(-90, dw, dh))) result = self.normalize_array(rotated * np.pi / (2 * len(th)) ) else: result = self.normalize_array(reconstructed * np.pi / (2 * len(th)) ) return result #print("A %d %d") % (result.shape[0], result.shape[1]) if(self.__firstGen==0): scale = 1/self.__detSize * (self.__emmiterDistance + output_size+self.__detectorsDistance)/(self.__emmiterDistance + output_size/2) #print("scale %f") % (scale) margin = (output_size-output_size*scale)/2 if(margin != 0): result = result[margin:-margin , margin:-margin] #print("B %d %d") % (result.shape[0], result.shape[1]) result = rescale(result, (1/scale, 1/scale)) #print("C %d %d") % (result.shape[0], result.shape[1]) result = result[0:output_size, 0:output_size] return result
def radon_real_geom(image, theta=None, circle=True, noise=1): def build_rotation(theta): T = np.deg2rad(theta) R = np.array([[np.cos(T), np.sin(T), 0], [-np.sin(T), np.cos(T), 0], [0, 0, 1]]) return shift1.dot(R).dot(shift0) if image.ndim != 2: raise ValueError('The input image must be 2-D!') if theta is None: theta = np.arange(180) else: # Pad the image so when it's rotated, nothing relevant gets cut out diagonal = np.sqrt(2) * max(image.shape) pad = [int(np.ceil(diagonal - s)) for s in image.shape] new_center = [(s + p) // 2 for s, p in zip(image.shape, pad)] old_center = [s // 2 for s in image.shape] pad_before = [nc - oc for oc, nc in zip(old_center, new_center)] pad_width = [(pb, p - pb) for pb, p in zip(pad_before, pad)] padded_image = np.pad(image, pad_width, mode='constant', constant_values=0) # padded_image should be square assert padded_image.shape[0] == padded_image.shape[1] radon_image = np.zeros((padded_image.shape[0], len(theta))) # For later comparison radon_image_unaltered = np.zeros((2 * padded_image.shape[0], len(theta))) # Upscale padded image with nearest neighbour filtering padded_image = np.array( Image.fromarray(padded_image).resize( (2 * padded_image.shape[0], 2 * padded_image.shape[1]))) center = padded_image.shape[0] // 2 shift0 = np.array([[1, 0, -center], [0, 1, -center], [0, 0, 1]]) shift1 = np.array([[1, 0, center], [0, 1, center], [0, 0, 1]]) for i in range(len(theta)): rotated = _warp_fast(padded_image, build_rotation(theta[i])) measurement = rotated.sum(0) # Coordinates of the projection pixels xp = np.arange(0, np.shape(measurement)[0]) xp = xp - np.shape(measurement)[0] / 2 + 0.5 # Translate and scale coordinates xr = (xp - np.sin(np.pi * theta[i] / 180) * np.shape(image)[0] / 2) / np.cos(np.pi * theta[i] / 180) # Get values at new coordinates f = interpolate.interp1d(xr, measurement, bounds_error=False, fill_value=0) measurement_new = f(xp) # Downscale measurement_new to correct size measurement_new = np.reshape(measurement_new, (1, np.shape(measurement_new)[0])) measurement_new = np.array( Image.fromarray(measurement_new).resize( (int(np.shape(measurement_new)[1] / 2), 1), resample=Image.BILINEAR)) # For comparison radon_image_unaltered[:, i] = measurement radon_image[:, i] = measurement_new if noise == 1: # Add 5% measurement noise noise = np.random.normal(1, 0.05, size=(radon_image.shape[0], radon_image.shape[1])) radon_image = radon_image * noise # Visualisation #radon_image_unaltered = np.array(Image.fromarray(radon_image_unaltered).resize((13, 272), resample=Image.BILINEAR)) #plt.figure() #plt.subplot(2, 1, 1) #plt.imshow(np.transpose(radon_image_unaltered)) #plt.subplot(2, 1, 2) #plt.imshow(np.transpose(radon_image)) return radon_image
def perform(self, node, inputs, out_storage): x, rot, shear, scale, trans, oshape = inputs #foobar.append_ndarray_signature(x, 'AffineImageWarp x') aff = AffineTransform(rotation=rot, shear=shear, scale=scale, translation=trans) if str(x.dtype) != node.inputs[0].dtype: raise TypeError("Wrong dtype argument to AffineImageWarp", x.dtype) if np.any(x < 0): raise ValueError('X should be positive') if np.any(x > 1.0): raise ValueError('X should be less than 1') N, C, H, W = x.shape rows, cols = oshape rval = out_storage[0][0] rval_shape = (N, C, rows, cols) if ((rval is None) or (rval.dtype != x.dtype) or rval.shape != rval_shape): rval3 = np.empty((N * C, rows, cols), dtype=x.dtype) bg_check = True else: rval3 = rval.reshape((N * C, rows, cols)) bg_check = False xx = x.reshape(N * C, H, W) # -- a small exactly-representable float for out-of-bounds pixels oob = -1.0 / 2**16 order = 1 # TODO: TRY ORDER=2 (WHY DOES RANGE GET LARGER?) tform = np.linalg.inv(aff._matrix) for i in xrange(N * C): if bg_check and i == 0: rval3[i] = _warp_fast(xx[i], tform, output_shape=oshape, order=order, cval=oob) oob_ratio = np.mean(rval3[i] == oob) if oob_ratio > 0.5: raise InvalidDescription('too much background', oob_ratio) rval3[i] = np.maximum(0, rval3[i]) else: rval3[i] = _warp_fast(xx[i], np.linalg.inv(aff._matrix), output_shape=oshape, order=order, cval=0) if 0 and i == 0: print 'Debugprint from AffineImageWarp...' for sym in 'rot', 'shear', 'scale', 'trans', 'oshape': print sym, ':', locals()[sym] import matplotlib.pyplot as pl pl.subplot(2, 1, 1) pl.imshow(xx[i], cmap=pl.cm.gray) pl.subplot(2, 1, 2) pl.imshow(rval3[i], cmap=pl.cm.gray) pl.show() time.sleep(2) # -- give some time to ctrl-C if np.any(rval3 > 1.001) or np.any(rval3 < 0.0): min3 = np.min(rval3) max3 = np.max(rval3) raise ValueError('interpolated pixel values out of range', (min3, max3)) out_storage[0][0] = rval3.reshape(rval_shape)