def transform_scalars(dataset, threshold=None): """Remove bad pixels in tilt series.""" from tomviz import utils import scipy.ndimage import numpy as np tiltSeries = utils.get_array(dataset).astype(np.float32) for i in range(tiltSeries.shape[2]): I = tiltSeries[:, :, i] I_pad = np.lib.pad(I, (1, 1), 'edge') # calculate standard deviation in a 3 x 3 window averageI2 = scipy.ndimage.filters.uniform_filter(I_pad ** 2) averageI = scipy.ndimage.filters.uniform_filter(I_pad) std = np.sqrt(abs(averageI2 - averageI**2))[1:-1, 1:-1] medianI = scipy.ndimage.filters.median_filter(I_pad, 2)[1:-1, 1:-1] #identiy bad pixels badPixelsMask = abs(I - medianI) > std * threshold I[badPixelsMask] = medianI[badPixelsMask] tiltSeries[:, :, i] = I # Set the result as the new scalars. utils.set_array(dataset, tiltSeries)
def transform_scalars(self, dataset, N=25): """Add Poisson noise to tilt images""" self.progress.maximum = 1 tiltSeries = utils.get_array(dataset).astype(float) if tiltSeries is None: raise RuntimeError("No scalars found!") Ndata = tiltSeries.shape[0] * tiltSeries.shape[1] self.progress.maximum = tiltSeries.shape[2] step = 0 for i in range(tiltSeries.shape[2]): if self.canceled: return tiltImage = tiltSeries[:, :, i].copy() tiltImage = tiltImage / np.sum(tiltSeries[:, :, i]) * (Ndata * N) tiltImage = np.random.poisson(tiltImage) tiltImage = tiltImage * np.sum(tiltSeries[:, :, i]) / (Ndata * N) tiltSeries[:, :, i] = tiltImage.copy() step += 1 self.progress.value = step utils.set_array(dataset, tiltSeries)
def transform_scalars(dataset, clipNum=5): """Set values outside a cirular range to minimum(dataset) to remove reconstruction artifacts""" from tomviz import utils import numpy as np array = utils.get_array(dataset) # Constant values numX = array.shape[1] numY = array.shape[2] minVal = array.min() # Find the values to be clipped maxR = min([numX, numY]) / 2 - clipNum XX, YY = np.mgrid[0:numX, 0:numY] RR = np.sqrt((XX - numX / 2) ** 2 + (YY - numY / 2) ** 2) clipThese = np.where(RR >= maxR) # Apply the mask along the original tilt axis direction # (always the first direction in the array) for ii in range(0, array.shape[0]): curImage = array[ii, :, :] # points to the relevant 2D part of the array curImage[clipThese] = minVal # Return to tomviz utils.set_array(dataset, array)
def transform_scalars(dataset): """Downsample volume by a factor of 2""" from tomviz import utils import scipy.ndimage import numpy as np array = utils.get_array(dataset) # Downsample the dataset x2 using order 1 spline (linear) # Calculate out array shape zoom = (0.5, 0.5, 0.5) result_shape = utils.zoom_shape(array, zoom) result = np.empty(result_shape, array.dtype, order='F') scipy.ndimage.interpolation.zoom(array, zoom, output=result, order=1, mode='constant', cval=0.0, prefilter=False) # Set the result as the new scalars. utils.set_array(dataset, result) # Update tilt angles if dataset is a tilt series. try: tilt_angles = utils.get_tilt_angles(dataset) result_shape = utils.zoom_shape(tilt_angles, 0.5) result = np.empty(result_shape, array.dtype, order='F') tilt_angles = scipy.ndimage.interpolation.zoom(tilt_angles, 0.5, output=result) utils.set_tilt_angles(dataset, result) except: # noqa # TODO What exception are we ignoring? pass
def transform_scalars(dataset, firstSlice=None, lastSlice=None, axis=2): """Delete Slices in Dataset""" from tomviz import utils import numpy as np # Get the current dataset. array = utils.get_array(dataset) # Get indices of the slices to be deleted. indices = np.linspace(firstSlice, lastSlice, lastSlice - firstSlice + 1).astype(int) # Delete the specified slices. array = np.delete(array, indices, axis) # Set the result as the new scalars. utils.set_array(dataset, array) # Delete corresponding tilt anlges if dataset is a tilt series. if axis == 2: try: tilt_angles = utils.get_tilt_angles(dataset) tilt_angles = np.delete(tilt_angles, indices) utils.set_tilt_angles(dataset, tilt_angles) except: # noqa # TODO what exception are we ignoring here? pass
def transform_scalars(dataset): """Pad dataset""" from tomviz import utils import numpy as np #----USER SPECIFIED VARIABLES-----# ###padWidthX### ###padWidthY### ###padWidthZ### ###padMode_index### #---------------------------------# padModes = ['constant','edge','wrap','minimum','median'] padMode = padModes[padMode_index] array = utils.get_array(dataset) #get data as numpy array if array is None: #Check if data exists raise RuntimeError("No data array found!") pad_width = (padWidthX,padWidthY,padWidthZ) # pad the data. array = np.lib.pad(array, pad_width, padMode) # Set the data so that it is visible in the application. utils.set_array(dataset, array) # If dataset is marked as tilt series, update tilt angles if padWidthZ[0]+padWidthZ[1] >0: try: tilt_angles = utils.get_tilt_angles(dataset) tilt_angles = np.lib.pad(tilt_angles,padWidthZ, padMode) utils.set_tilt_angles(dataset, tilt_angles) except: pass
def label_object_principal_axes(dataset, label_value): import numpy as np from tomviz import utils labels = utils.get_array(dataset) num_voxels = np.sum(labels == label_value) xx, yy, zz = utils.get_coordinate_arrays(dataset) data = np.zeros((num_voxels, 3)) selection = labels == label_value assert np.any(selection), \ "No voxels with label %d in label map" % label_value data[:, 0] = xx[selection] data[:, 1] = yy[selection] data[:, 2] = zz[selection] # Compute PCA on coordinates from scipy import linalg as la m, n = data.shape center = data.mean(axis=0) data -= center R = np.cov(data, rowvar=False) evals, evecs = la.eigh(R) idx = np.argsort(evals)[::-1] evecs = evecs[:, idx] evals = evals[idx] return (evecs, center)
def transform_scalars(dataset): #----USER SPECIFIED VARIABLES-----# ###ROT_AXIS### #Specify Tilt Axis Dimensions x=0, y=1, z=2 ###ROT_ANGLE### #Rotate the dataset by an Angle (in degrees) #---------------------------------# from tomviz import utils import numpy as np from scipy import ndimage data_py = utils.get_array(dataset) #get data as numpy array if data_py is None: #Check if data exists raise RuntimeError("No data array found!") if ROT_AXIS == []: #If tilt axis is not given, assign one. #Find smallest array dimension, assume it is the tilt angle axis if data_py.ndim >= 2: ROT_AXIS = np.argmin( data_py.shape ) else: raise RuntimeError("Data Array is not 2 or 3 dimensions!") if ROT_ANGLE == []: #If tilt axis is not given, assign it to 90 degrees. ROT_ANGLE = 90; print('Rotating Images...') data_py_return = ndimage.interpolation.rotate( data_py, ROT_ANGLE, axes=((ROT_AXIS+1)%3, (ROT_AXIS+2)%3) ) utils.set_array(dataset, data_py_return) print('Rotate Complete')
def transform_scalars(dataset, resampling_factor=[1, 1, 1]): """Resample dataset""" from tomviz import utils import scipy.ndimage import numpy as np array = utils.get_array(dataset) # Transform the dataset. result_shape = utils.zoom_shape(array, resampling_factor) result = np.empty(result_shape, array.dtype, order='F') scipy.ndimage.interpolation.zoom(array, resampling_factor, output=result) # Set the result as the new scalars. utils.set_array(dataset, result) # Update tilt angles if dataset is a tilt series. if resampling_factor[2] != 1: try: tilt_angles = utils.get_tilt_angles(dataset) result_shape = utils.zoom_shape(tilt_angles, resampling_factor[2]) result = np.empty(result_shape, array.dtype, order='F') scipy.ndimage.interpolation.zoom( tilt_angles, resampling_factor[2], output=result) utils.set_tilt_angles(dataset, result) except: # noqa # TODO What exception are we ignoring? pass
def transform_scalars(dataset): """3D Reconstruct from a tilt series using constraint-based Direct Fourier Method""" from tomviz import utils import numpy as np ###Niter### ###Niter_update_support### ###supportSigma### ###supportThreshold### #percent supportThreshold = supportThreshold/100.0 nonnegativeVoxels = True tilt_angles = utils.get_tilt_angles(dataset) #Get Tilt angles tilt_images = utils.get_array(dataset) if tilt_images is None: raise RuntimeError("No scalars found!") #Direct Fourier recon without constraints (recon,recon_F) = dfm3(tilt_images,tilt_angles,np.size(tilt_images,0)*2) kr_cutoffs = np.linspace(0.05,0.5,10); I_data = radial_average(tilt_images,kr_cutoffs) #average Fourier magnitude of tilt series as a function of kr #Search for solutions that satisfy additional constraints recon = difference_map_update(recon_F,nonnegativeVoxels,I_data,kr_cutoffs,Niter,Niter_update_support,supportSigma,supportThreshold) print('Reconsruction Complete') # Set the result as the new scalars. utils.set_array(dataset, recon) # Mark dataset as volume utils.mark_as_volume(dataset)
def transform_scalars(dataset): '''For each tilt image, the method uses average pixel value of selected region as the background level and subtracts it from the image.''' '''It does NOT set negative pixels to zero.''' from tomviz import utils import numpy as np #----USER SPECIFIED VARIABLES-----# ###XRANGE### ###YRANGE### ###ZRANGE### #---------------------------------# data_bs = utils.get_array(dataset) # Get data as numpy array. data_bs = data_bs.astype(np.float32) # Change tilt series type to float. if data_bs is None: #Check if data exists raise RuntimeError("No data array found!") for i in range(ZRANGE[0],ZRANGE[1]): a = data_bs[:,:,i] - np.average(data_bs[XRANGE[0]:XRANGE[1],YRANGE[0]:YRANGE[1],i]) data_bs[:,:,i] = a utils.set_array(dataset, data_bs)
def transform_scalars(dataset): """3D Reconstruct from a tilt series using Weighted Back-projection Method""" from tomviz import utils import numpy as np interpolation_methods = ('linear','nearest','spline','cubic') filter_methods = ('none','ramp','shepp-logan','cosine','hamming','hann') ###Nrecon### ###filter### ###interp### #Get Tilt angles tilt_angles = utils.get_tilt_angles(dataset) data_py = utils.get_array(dataset) if data_py is None: raise RuntimeError("No scalars found!") recon = wbp3(data_py,tilt_angles,Nrecon,filter_methods[filter],interpolation_methods[interp]) print('Reconsruction Complete') # set the result as the new scalars. utils.set_array(dataset, recon) # Mark dataset as volume utils.mark_as_volume(dataset)
def transform_scalars(dataset): """Delete Slices in Dataset""" from tomviz import utils import numpy as np axis = 0; #----USER SPECIFIED VARIABLES-----# ###firstSlice### ###lastSlice### ###axis### #Axis along which to delete the subarray #---------------------------------# #get current dataset array = utils.get_array(dataset) #Get indices of the slices to be deleted indices = np.linspace(firstSlice,lastSlice,lastSlice-firstSlice+1).astype(int) # delete slices array = np.delete(array,indices,axis) #set the result as the new scalars. utils.set_array(dataset, array) #Delete corresponding tilt anlges if dataset is a tilt series if axis == 2: try: tilt_angles = utils.get_tilt_angles(dataset) tilt_angles = np.delete(tilt_angles,indices) utils.set_tilt_angles(dataset, tilt_angles) except: pass
def transform_scalars(dataset): """3D Reconstruct from a tilt series using Algebraic Reconstruction Technique (ART)""" ###Niter### # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) # Get Tilt Series tiltSeries = utils.get_array(dataset) (Nslice,Nray,Nproj) = tiltSeries.shape if tiltSeries is None: raise RuntimeError("No scalars found!") # Generate measurement matrix A = parallelRay(Nray,1.0,tiltAngles,Nray,1.0) #A is a sparse matrix recon = np.zeros((Nslice,Nray,Nray)) art3(A.todense(),tiltSeries,recon,Niter) # Set the result as the new scalars. utils.set_array(dataset, recon) # Mark dataset as volume utils.mark_as_volume(dataset)
def transform_scalars(dataset, SHIFT=None, rotation_angle=90.0): from tomviz import utils from scipy import ndimage import numpy as np data_py = utils.get_array(dataset) # Get data as numpy array. if data_py is None: #Check if data exists raise RuntimeError("No data array found!") if SHIFT is None: SHIFT = np.zeros(len(data_py.shape), dtype=np.int) data_py_return = np.empty_like(data_py) ndimage.interpolation.shift(data_py, SHIFT, order=0, output=data_py_return) rotation_axis = 2 # This operator always assumes the rotation axis is Z if rotation_angle == []: # If tilt angle not given, assign it to 90 degrees. rotation_angle = 90 axis1 = (rotation_axis + 1) % 3 axis2 = (rotation_axis + 2) % 3 axes = (axis1, axis2) shape = utils.rotate_shape(data_py_return, rotation_angle, axes=axes) data_py_return2 = np.empty(shape, data_py_return.dtype, order='F') ndimage.interpolation.rotate( data_py_return, rotation_angle, output=data_py_return2, axes=axes) utils.set_array(dataset, data_py_return2)
def transform_scalars(dataset): """Resample dataset""" from tomviz import utils import numpy as np import scipy.ndimage #----USER SPECIFIED VARIABLES-----# #resampingFactor = [1,1,1] #Specify the shifts (x,y,z) applied to data ###resampingFactor### #---------------------------------# array = utils.get_array(dataset) # Transform the dataset. result = scipy.ndimage.interpolation.zoom(array, resampingFactor) # Set the result as the new scalars. utils.set_array(dataset, result) # Update tilt angles if dataset is a tilt series. if resampingFactor[2] != 1: try: tilt_angles = utils.get_tilt_angles(dataset) tilt_angles = scipy.ndimage.interpolation.zoom(tilt_angles, resampingFactor[2]) utils.set_tilt_angles(dataset, tilt_angles) except: pass
def transform_scalars(dataset): """Generate Tilt Series from Volume""" from tomviz import utils import numpy as np import scipy.ndimage #----USER SPECIFIED VARIABLES-----# ###startAngle### #Starting angle ###angleIncrement### #Angle increment ###Nproj### #Number of tilts #---------------------------------# # Generate Tilt Angles angles = np.linspace(startAngle,startAngle+(Nproj-1)*angleIncrement,Nproj); array = utils.get_array(dataset) N = array.shape[0]; Nslice = array.shape[2]; #Number of slices along rotation axis tiltSeries = np.zeros((Nslice, N ,Nproj)) for i in range(Nproj): #Rotate volume rotatedArray = scipy.ndimage.interpolation.rotate(array, angles[i],axes=(0,1),reshape=False) #Calculate Projection tiltSeries[:,:,i] = np.sum(rotatedArray,axis=0).transpose() # set the result as the new scalars. utils.set_array(dataset, tiltSeries) # Mark dataset as tilt series utils.mark_as_tiltseries(dataset) # Save tilt angles utils.set_tilt_angles(dataset, angles)
def transform_scalars(dataset): from tomviz import utils import numpy as np #----USER SPECIFIED VARIABLES-----# TILT_AXIS = [] #Specify the tilt axis, if none is specified #it assume it is the smallest dimension ANGLES = [] #Specify the angles used in the tiltseries #For example, ANGLES = np.linspace(0,140,70) #---------------------------------# data_py = utils.get_array(dataset) if data_py is None: raise RuntimeError("No scalars found!") if TILT_AXIS == []: #If tilt axis is not given, find it #Find smallest array dimension, assume it is the tilt angle axis if data_py.ndim == 3: TILT_AXIS = np.argmin( data_py.shape ) elif data_py.ndim == 2: raise RuntimeError("Data Array is 2 dimensions, it should be 3!") else: raise RuntimeError("Data Array is not 2 or 3 dimensions!") if ANGLES == []: #If angles are not given, assume 2 degree tilts angles = np.linspace(0,146,74) dimx = np.size(data_py,0) #IN THE FUTURE THIS SHOULD NOT BE ASSUMED result3D = dfm3(data_py,angles,dimx) # set the result as the new scalars. utils.set_array(dataset, result3D) print('Reconsruction Complete')
def transform_scalars(dataset): #----USER SPECIFIED VARIABLES-----# TILT_AXIS = [] #Specify Tilt Axis Dimensions x=0, y=1, z=2 #---------------------------------# from tomviz import utils import numpy as np data_py = utils.get_array(dataset) #get data as numpy array if data_py is None: #Check if data exists raise RuntimeError("No data array found!") if TILT_AXIS == []: #If tilt axis is not given, find it #Find smallest array dimension, assume it is the tilt angle axis if data_py.ndim == 3: TILT_AXIS = np.argmin( data_py.shape ) elif data_py.ndim == 2: raise RuntimeError("Data Array is 2 dimensions, it should be 3!") else: raise RuntimeError("Data Array is not 2 or 3 dimensions!") print('Aligning Images by Cross Correlation') for i in range(1,np.size(data_py,TILT_AXIS)):#Align image to previous if TILT_AXIS == 2: im0 = np.fft.fft2(data_py[:,:,i-1]) im1 = np.fft.fft2(data_py[:,:,i]) xcor = abs(np.fft.ifft2((im0 * im1.conjugate()))) shift = np.unravel_index(xcor.argmax(), xcor.shape) print( shift ) data_py[:,:,i] = np.roll( data_py[:,:,i], shift[0], axis = 0) data_py[:,:,i] = np.roll( data_py[:,:,i], shift[1], axis = 1) elif TILT_AXIS == 1: im0 = np.fft.fft2(data_py[:,i-1,:]) im1 = np.fft.fft2(data_py[:,i,:]) xcor = abs(np.fft.ifft2((im0 * im1.conjugate()))) print( np.amax(xcor) ) shift = np.unravel_index(xcor.argmax(), xcor.shape) print( shift ) data_py[:,i,:] = np.roll( data_py[:,i,:], shift[0], axis = 0) data_py[:,i,:] = np.roll( data_py[:,i,:], shift[2], axis = 2) elif TILT_AXIS == 0: im0 = np.fft.fft2(data_py[i-1,:,:]) im1 = np.fft.fft2(data_py[i,:,:]) xcor = abs(np.fft.ifft2((im0 * im1.conjugate()))) print( np.amax(xcor) ) shift = np.unravel_index(xcor.argmax(), xcor.shape) print( shift ) data_py[i,:,:] = np.roll( data_py[i,:,:], shift[1], axis = 1) data_py[i,:,:] = np.roll( data_py[i,:,:], shift[2], axis = 2) else: raise RuntimeError("Python Transform Error: Unknown TILT_AXIS.") utils.set_array(dataset, data_py) print('Align Images Complete')
def transform_scalars(self, dataset, Nrecon=None, filter=None, interp=None): """ 3D Reconstruct from a tilt series using Weighted Back-projection Method """ self.progress.maximum = 1 from tomviz import utils interpolation_methods = ('linear', 'nearest', 'spline', 'cubic') filter_methods = ('none', 'ramp', 'shepp-logan', 'cosine', 'hamming', 'hann') # Get Tilt angles tilt_angles = utils.get_tilt_angles(dataset) tiltSeries = utils.get_array(dataset) if tiltSeries is None: raise RuntimeError("No scalars found!") Nslice = tiltSeries.shape[0] self.progress.maximum = Nslice step = 0 recon = np.empty([Nslice, Nrecon, Nrecon], dtype=float, order='F') t0 = time.time() counter = 1 etcMessage = 'Estimated time to complete: n/a' for i in range(Nslice): if self.canceled: return self.progress.message = 'Slice No.%d/%d. ' % ( i + 1, Nslice) + etcMessage recon[i, :, :] = wbp2(tiltSeries[i, :, :], tilt_angles, Nrecon, filter_methods[filter], interpolation_methods[interp]) step += 1 self.progress.value = step timeLeft = (time.time() - t0) / counter * (Nslice - counter) counter += 1 timeLeftMin, timeLeftSec = divmod(timeLeft, 60) timeLeftHour, timeLeftMin = divmod(timeLeftMin, 60) etcMessage = 'Estimated time to complete: %02d:%02d:%02d' % ( timeLeftHour, timeLeftMin, timeLeftSec) # Set up the output dataset from vtk import vtkImageData recon_dataset = vtkImageData() recon_dataset.CopyStructure(dataset) utils.set_array(recon_dataset, recon) utils.mark_as_volume(recon_dataset) returnValues = {} returnValues["reconstruction"] = recon_dataset return returnValues
def transform_scalars(self, dataset): """Automatically align tilt images by cross-correlation""" self.progress.maximum = 1 tiltSeries = utils.get_array(dataset).astype(float) tiltAngles = utils.get_tilt_angles(dataset) # determine reference image index zeroDegreeTiltImage = np.where(tiltAngles == 0)[0] if zeroDegreeTiltImage: referenceIndex = zeroDegreeTiltImage[0] else: referenceIndex = tiltSeries.shape[2] // 2 # create Fourier space filter filterCutoff = 4 (Ny, Nx, Nproj) = tiltSeries.shape ky = np.fft.fftfreq(Ny) kx = np.fft.fftfreq(Nx) [kX, kY] = np.meshgrid(kx, ky) kR = np.sqrt(kX**2 + kY**2) kFilter = (kR <= (0.5 / filterCutoff)) * \ np.sin(2 * filterCutoff * np.pi * kR)**2 # create real sapce filter to remove edge discontinuities y = np.linspace(1, Ny, Ny) x = np.linspace(1, Nx, Nx) [X, Y] = np.meshgrid(x, y) rFilter = (np.sin(np.pi * X / Nx) * np.sin(np.pi * Y / Ny)) ** 2 self.progress.maximum = tiltSeries.shape[2] - 1 step = 0 for i in range(referenceIndex, Nproj - 1): if self.canceled: return self.progress.message = 'Processing tilt image No.%d/%d' % ( i + 1, Nproj) tiltSeries[:, :, i + 1] = crossCorrelationAlign( tiltSeries[:, :, i + 1], tiltSeries[:, :, i], rFilter, kFilter) step += 1 self.progress.value = step for i in range(referenceIndex, 0, -1): if self.canceled: return self.progress.message = 'Processing tilt image No.%d/%d' % ( i, Nproj) tiltSeries[:, :, i - 1] = crossCorrelationAlign( tiltSeries[:, :, i - 1], tiltSeries[:, :, i], rFilter, kFilter) step += 1 self.progress.value = step utils.set_array(dataset, tiltSeries)
def transform_scalars(dataset): """Set negative voxels to zero""" from tomviz import utils data = utils.get_array(dataset) data[data < 0] = 0 # Set negative voxels to zero # Set the result as the new scalars. utils.set_array(dataset, data)
def transform_scalars(self, dataset): """Automatic align the tilt axis to the center of images""" self.progress.maximum = 1 from tomviz import utils # Get Tilt angles tilt_angles = utils.get_tilt_angles(dataset) tiltSeries = utils.get_array(dataset) if tiltSeries is None: raise RuntimeError("No scalars found!") Nx, Ny, Nz = tiltSeries.shape shifts = (np.linspace(-20, 20, 41)).astype('int') numberOfSlices = 5 # number of slices used for recon # randomly choose slices with top 50% total intensities tiltSeriesSum = np.sum(tiltSeries, axis=(1, 2)) temp = tiltSeriesSum.argsort()[Nx // 2:] slices = temp[np.random.permutation(temp.size)[:numberOfSlices]] print('Reconstruction slices:') print(slices) I = np.zeros(shifts.size) self.progress.maximum = shifts.size - 1 step = 0 for i in range(shifts.size): if self.canceled: return shiftedTiltSeries = np.roll( tiltSeries[slices, :, :, ], shifts[i], axis=1) for s in range(numberOfSlices): self.progress.message = ('Reconstructing slice No.%d with %d ' 'pixels shift' % (slices[s], shifts[i])) recon = wbp2(shiftedTiltSeries[s, :, :], tilt_angles, Ny, 'ramp', 'linear') I[i] = I[i] + np.amax(recon) step += 1 self.progress.value = step print('shift: %d' % shifts[np.argmax(I)]) result = np.roll(tiltSeries, shifts[np.argmax(I)], axis=1) result = np.asfortranarray(result) # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(dataset): from tomviz import utils import numpy as np #----USER SPECIFIED VARIABLES-----# TILT_AXIS = [] #Specify Tilt Axis Dimensions x=0, y=1, z=2 SHIFT_EXP = 0.10 #Specify the Expected (mean) Random % Image Shift (0-1) SHIFT_STDDEV = 0.05 #Specify the Standard Deviation as % of Image (0-1) np.random.seed(12) #Set a new seed to get different random alignments #---------------------------------# data_py = utils.get_array(dataset) #get data as numpy array if data_py is None: #Check if data exists raise RuntimeError("No data array found!") if TILT_AXIS == []: #If tilt axis is not given, find it #Find smallest array dimension, assume it is the tilt angle axis if data_py.ndim == 3: TILT_AXIS = np.argmin( data_py.shape ) elif data_py.ndim == 2: raise RuntimeError("Data Array is 2 dimensions, it should be 3!") else: raise RuntimeError("Data Array is not 2 or 3 dimensions!") for i in range(0,np.size(data_py,TILT_AXIS)-1): if TILT_AXIS == 2: shift_mu = np.size(data_py,0)*SHIFT_EXP shift_sigma = np.size(data_py,0)*SHIFT_STDDEV shift0 = int( np.random.normal(shift_mu, shift_sigma) ) shift1 = int( np.random.normal(shift_mu, shift_sigma) ) data_py[:,:,i] = np.roll( data_py[:,:,i], shift0, axis = 0) data_py[:,:,i] = np.roll( data_py[:,:,i], shift1, axis = 1) elif TILT_AXIS == 1: shift_mu = np.size(data_py,0)*SHIFT_EXP shift_sigma = np.size(data_py,0)*SHIFT_STDDEV shift0 = int( np.random.normal(shift_mu, shift_sigma) ) shift1 = int( np.random.normal(shift_mu, shift_sigma) ) data_py[:,i,:] = np.roll( data_py[:,i,:], shift0, axis = 0) data_py[:,i,:] = np.roll( data_py[:,i,:], shift2, axis = 2) elif TILT_AXIS == 0: shift_mu = np.size(data_py,1)*SHIFT_EXP shift_sigma = np.size(data_py,1)*SHIFT_STDDEV shift0 = int( np.random.normal(shift_mu, shift_sigma) ) shift1 = int( np.random.normal(shift_mu, shift_sigma) ) data_py[i,:,:] = np.roll( data_py[i,:,:], shift1, axis = 1) data_py[i,:,:] = np.roll( data_py[i,:,:], shift2, axis = 2) else: raise RuntimeError("Python Transform Error: Unknown TILT_AXIS.") utils.set_array(dataset, data_py) print('Misalign Images Complete')
def transform_scalars(dataset): """Apply a Laplace filter to dataset.""" from tomviz import utils import numpy as np import scipy.ndimage array = utils.get_array(dataset) # Transform the dataset result = scipy.ndimage.filters.laplace(array) # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(dataset): """Downsample dataset by a factor of 2""" from tomviz import utils import numpy as np import scipy.ndimage array = utils.get_array(dataset) # transform the dataset result = scipy.ndimage.interpolation.zoom(array, (0.5, 0.5, 0.5)) # set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(dataset, shift=[0, 0, 0]): from tomviz import utils import numpy as np data_py = utils.get_array(dataset) # Get data as numpy array. if data_py is None: #Check if data exists raise RuntimeError("No data array found!") data_py[:] = np.roll(data_py, shift[0], axis=0) data_py[:] = np.roll(data_py, shift[1], axis=1) data_py[:] = np.roll(data_py, shift[2], axis=2) utils.set_array(dataset, data_py) print('Data has been shifted uniformly.')
def transform_scalars(dataset): """Calculate 3D gradient magnitude using Sobel operator""" from tomviz import utils import numpy as np import scipy.ndimage array = utils.get_array(dataset) array = array.astype(np.float32) # Transform the dataset result = scipy.ndimage.filters.generic_gradient_magnitude(array, scipy.ndimage.filters.sobel) # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(dataset): """Downsample dataset by a factor of 2""" from tomviz import utils import numpy as np import scipy.ndimage array = utils.get_array(dataset) # Downsample the dataset x2 using order 1 spline (linear) result = scipy.ndimage.interpolation.zoom(array, (0.5, 0.5, 0.5),output=None, order=1, mode='constant', cval=0.0, prefilter=False) # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(dataset, XRANGE=None, YRANGE=None, ZRANGE=None): """Define this method for Python operators that transform input scalars""" from tomviz import utils import numpy as np array = utils.get_array(dataset) if array is None: raise RuntimeError("No scalars found!") # Transform the dataset. result = np.copy(array) result[XRANGE[0]:XRANGE[1], YRANGE[0]:YRANGE[1], ZRANGE[0]:ZRANGE[1]] = 0 # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(self, dataset, Niter=10, Nupdates=0): """3D Reconstruct from a tilt series using simple TV minimzation""" self.progress.maximum = 1 # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) #remove zero tilt anlges if np.count_nonzero(tiltAngles) < tiltAngles.size: tiltAngles = tiltAngles + 0.001 # Get Tilt Series tiltSeries = utils.get_array(dataset) (Nslice, Nray, Nproj) = tiltSeries.shape # Determine the slices for live updates. Nupdates = calc_Nupdates(Nupdates, Niter) # Generate measurement matrix A = parallelRay(Nray, 1.0, tiltAngles, Nray, 1.0) #A is a sparse matrix recon = np.zeros([Nslice, Nray, Nray], dtype=np.float32, order='F') A = A.tocsr() (Nslice, Nray, Nproj) = tiltSeries.shape (Nrow, Ncol) = A.shape rowInnerProduct = np.zeros(Nrow, dtype=np.float32) row = np.zeros(Ncol, dtype=np.float32) f = np.zeros(Ncol, dtype=np.float32) # Placeholder for 2d image ng = 5 beta = 1.0 r_max = 1.0 gamma_red = 0.8 # Calculate row inner product, preparation for ART recon for j in range(Nrow): row[:] = A[j, :].toarray() rowInnerProduct[j] = np.dot(row, row) self.progress.maximum = Niter * Nslice t0 = time.time() counter = 1 etcMessage = 'Estimated time to complete: n/a' #Create child dataset for recon child = utils.make_child_dataset(dataset) utils.mark_as_volume(child) for i in range(Niter): #main loop recon_temp = recon.copy() #ART recon for s in range(Nslice): # if self.canceled: #In case canceled during ART. return self.progress.message = 'Slice No.%d/%d, Iteration No.%d/%d. '\ % (s + 1, Nslice, i + 1, Niter) + etcMessage if (i == 0): f[:] = 0 elif (i != 0): f[:] = recon[s, :, :].flatten() b = tiltSeries[s, :, :].transpose().flatten() for j in range(Nrow): row[:] = A[j, :].toarray() a = (b[j] - np.dot(row, f)) / rowInnerProduct[j] f = f + row * a * beta recon[s, :, :] = f.reshape((Nray, Nray)) self.progress.value = i * Nslice + s timeLeft = (time.time() - t0) / counter * \ (Nslice * Niter - counter) counter += 1 timeLeftMin, timeLeftSec = divmod(timeLeft, 60) timeLeftHour, timeLeftMin = divmod(timeLeftMin, 60) etcMessage = 'Estimated time to complete: %02d:%02d:%02d' % ( timeLeftHour, timeLeftMin, timeLeftSec) recon[recon < 0] = 0 #Positivity constraint #Update for XX iterations. if Nupdates != 0 and (i + 1) % Nupdates == 0: utils.set_array(child, recon) self.progress.data = child if i != (Niter - 1): self.progress.message = 'Minimizating the Objects TV' #calculate tomogram change due to POCS dPOCS = np.linalg.norm(recon_temp - recon) recon_temp = recon.copy() #3D TV minimization for j in range(ng): R_0 = tv(recon) v = tv_derivative(recon) recon_prime = recon - dPOCS * v recon_prime[recon_prime < 0] = 0 gamma = 1.0 R_f = tv(recon_prime) #Projected Line search while R_f > R_0: gamma = gamma * gamma_red recon_prime = recon - gamma * dPOCS * v recon_prime[recon_prime < 0] = 0 R_f = tv(recon_prime) recon = recon_prime dg = np.linalg.norm(recon - recon_temp) if dg > r_max * dPOCS: recon = r_max * dPOCS / dg * (recon - recon_temp) + recon_temp # One last update of the child data. utils.set_array(child, recon) #add recon to child self.progress.data = child returnValues = {} returnValues["reconstruction"] = child return returnValues
def transform_scalars(self, dataset): """ Automatic align the tilt axis to horizontal direction (x-axis) """ self.progress.maximum = 1 # Get Tilt Series tiltSeries = utils.get_array(dataset) if tiltSeries is None: #Check if data exists raise RuntimeError("No data array found!") (Nslice, Nray, Nproj) = tiltSeries.shape Intensity = np.zeros(tiltSeries.shape) self.progress.maximum = Nproj + 131 #coarse(90)+fine(41) step = 0 self.progress.message = 'Initialization' #take FFT of all projections for i in range(Nproj): self.progress.message = ('Taking Fourier transofrm of tilt image' 'No.%d/%d' % (i + 1, Nproj)) tiltImage = tiltSeries[:, :, i] tiltImage_F = np.abs(np.fft.fft2(tiltImage)) if (i == 0): temp = tiltImage_F[0, 0] Intensity[:, :, i] = np.fft.fftshift(tiltImage_F / temp) step += 1 self.progress.value = step #rescale intensity Intensity = np.power(Intensity, 0.2) #calculate variation itensity image Intensity_var = np.var(Intensity, axis=2) #search angles coarseStep = 2 fineStep = 0.1 coarseAngles = np.arange(-90, 90, coarseStep) Nx = Intensity_var.shape[0] Ny = Intensity_var.shape[1] N = np.round(np.min([Nx, Ny]) // 3) #coarse search I = np.zeros((coarseAngles.size, N)) for a in range(coarseAngles.size): if self.canceled: return self.progress.message = ('Calculating line intensity at angle %f' 'degree' % (coarseAngles[a])) I[a, :] = calculateLineIntensity(Intensity_var, coarseAngles[a], N) step += 1 self.progress.value = step I_sum = np.sum(I, axis=1) minIntensityIndex = np.argmin(I_sum) rot_ang = coarseAngles[minIntensityIndex] #now refine fineAngles = np.arange(rot_ang - coarseStep, rot_ang + coarseStep + fineStep, fineStep) #fine search I = np.zeros((fineAngles.size, N)) for a in range(fineAngles.size): if self.canceled: return self.progress.message = ('Calculating line intensity at angle %f' 'degree' % (fineAngles[a])) I[a, :] = calculateLineIntensity(Intensity_var, fineAngles[a], N) step += 1 self.progress.value = step I_sum = np.sum(I, axis=1) minIntensityIndex = np.argmin(I_sum) rot_ang = fineAngles[minIntensityIndex] self.progress.message = 'Rotating tilt series' axes = ((0, 1)) shape = utils.rotate_shape(tiltSeries, -rot_ang, axes=axes) result = np.empty(shape, tiltSeries.dtype, order='F') ndimage.interpolation.rotate( tiltSeries, -rot_ang, axes=axes, output=result) print("rotate tilt series by %f degrees" % -rot_ang) # Set the result as the new scalars. utils.set_array(dataset, result)
def transform_scalars(self, dataset, Nrecon=None, filter=None, interp=None): """ 3D Reconstruct from a tilt series using Weighted Back-projection Method """ self.progress.maximum = 1 from tomviz import utils interpolation_methods = ('linear', 'nearest', 'spline', 'cubic') filter_methods = ('none', 'ramp', 'shepp-logan', 'cosine', 'hamming', 'hann') # Get Tilt angles tilt_angles = utils.get_tilt_angles(dataset) tiltSeries = utils.get_array(dataset) if tiltSeries is None: raise RuntimeError("No scalars found!") Nslice = tiltSeries.shape[0] self.progress.maximum = Nslice step = 0 recon = np.empty([Nslice, Nrecon, Nrecon], dtype=float, order='F') t0 = time.time() counter = 1 etcMessage = 'Estimated time to complete: n/a' child = utils.make_child_dataset(dataset) #create child for recon utils.mark_as_volume(child) for i in range(Nslice): if self.canceled: return self.progress.message = 'Slice No.%d/%d. ' % (i + 1, Nslice) + etcMessage recon[i, :, :] = wbp2(tiltSeries[i, :, :], tilt_angles, Nrecon, filter_methods[filter], interpolation_methods[interp]) step += 1 self.progress.value = step timeLeft = (time.time() - t0) / counter * (Nslice - counter) counter += 1 timeLeftMin, timeLeftSec = divmod(timeLeft, 60) timeLeftHour, timeLeftMin = divmod(timeLeftMin, 60) etcMessage = 'Estimated time to complete: %02d:%02d:%02d' % ( timeLeftHour, timeLeftMin, timeLeftSec) # Update only once every so many steps if (i + 1) % 40 == 0: utils.set_array(child, recon) #add recon to child # This copies data to the main thread self.progress.data = child # One last update of the child data. utils.set_array(child, recon) #add recon to child self.progress.data = child returnValues = {} returnValues["reconstruction"] = child return returnValues
def transform_scalars(self, dataset, Niter=100, a=0.1, wedgeSize=5, kmin=5, theta=0): """ Remove Structured Artifacts with Total Variation Minimization""" #Import information from dataset array = utils.get_array(dataset) (nx, ny, nz) = array.shape # Convert angle from Degrees to Radians. theta = (theta + 90) * (np.pi / 180) dtheta = wedgeSize * (np.pi / 180) #Create coordinate grid in polar x = np.arange(-nx / 2, nx / 2 - 1, dtype=np.float64) y = np.arange(-ny / 2, ny / 2 - 1, dtype=np.float64) [x, y] = np.meshgrid(x, y, indexing='ij') rr = (np.square(x) + np.square(y)) phi = np.arctan2(x, y) #Create the Angular Mask mask = np.ones((nx, ny), dtype=np.int8) mask[np.where((phi >= (theta - dtheta / 2)) & (phi <= (theta + dtheta / 2)))] = 0 mask[np.where((phi >= (np.pi + theta - dtheta / 2)) & (phi <= (np.pi + theta + dtheta / 2)))] = 0 mask[np.where((phi >= (-np.pi + theta - dtheta / 2)) & (phi <= (-np.pi + theta + dtheta / 2)))] = 0 mask[np.where(rr < np.square(kmin))] = 1 # Keep values below rmin. mask = np.array(mask, dtype=bool) # Initialize Progress bar. self.progress.maximum = nz * Niter #Main Loop for i in range(nz): #FFT of the Original Image. FFT_image = fftshift(fftn(array[:, :, i])) # Reconstruction starts as random image. recon_init = np.random.rand(nx, ny) self.progress.message = 'Processing Image No.%d/%d ' % (i + 1, nz) #TV Artifact Removal Loop for j in range(Niter): # FFT of Reconstructed Image. FFT_recon = fftshift(fftn(recon_init)) # Impose the Data Constraint FFT_recon[mask] = FFT_image[mask] #Inverse FFT recon_constraint = np.real(ifftn(ifftshift(FFT_recon))) # Positivity Constraint recon_constraint[recon_constraint < 0] = 0 # TV Minimization Loop recon_minTV = recon_constraint d = np.linalg.norm(recon_minTV - recon_init) for k in range(20): vst = TVDerivative(recon_minTV, nx, ny) recon_minTV = recon_minTV - a * d * vst if self.canceled: return # Initializte the Next Loop. recon_init = recon_minTV # Update the Progress Bar. self.progress.value = i * Niter + j # Return reconstruction into stack. array[:, :, i] = recon_constraint #Set the result as the new scalars. utils.set_array(dataset, np.asfortranarray(array))
def transform_scalars(self, dataset): """Automatically align tilt images by cross-correlation""" self.progress.maximum = 1 tiltSeries = utils.get_array(dataset).astype(float) tiltAngles = utils.get_tilt_angles(dataset) # determine reference image index zeroDegreeTiltImage = None if tiltAngles is not None: zeroDegreeTiltImage = np.where(tiltAngles == 0)[0] if zeroDegreeTiltImage: referenceIndex = zeroDegreeTiltImage[0] else: referenceIndex = tiltSeries.shape[2] // 2 # create Fourier space filter filterCutoff = 4 (Ny, Nx, Nproj) = tiltSeries.shape ky = np.fft.fftfreq(Ny) kx = np.fft.fftfreq(Nx) [kX, kY] = np.meshgrid(kx, ky) kR = np.sqrt(kX**2 + kY**2) kFilter = (kR <= (0.5 / filterCutoff)) * \ np.sin(2 * filterCutoff * np.pi * kR)**2 # create real sapce filter to remove edge discontinuities y = np.linspace(1, Ny, Ny) x = np.linspace(1, Nx, Nx) [X, Y] = np.meshgrid(x, y) rFilter = (np.sin(np.pi * X / Nx) * np.sin(np.pi * Y / Ny)) ** 2 self.progress.maximum = tiltSeries.shape[2] - 1 step = 1 offsets = np.zeros((tiltSeries.shape[2], 2)) for i in range(referenceIndex, Nproj - 1): if self.canceled: return self.progress.message = 'Processing tilt image No.%d/%d' % ( step, Nproj) offsets[i + 1, :], tiltSeries[:, :, i + 1] = crossCorrelationAlign( tiltSeries[:, :, i + 1], tiltSeries[:, :, i], rFilter, kFilter) step += 1 self.progress.value = step for i in range(referenceIndex, 0, -1): if self.canceled: return self.progress.message = 'Processing tilt image No.%d/%d' % ( step, Nproj) offsets[i - 1, :], tiltSeries[:, :, i - 1] = crossCorrelationAlign( tiltSeries[:, :, i - 1], tiltSeries[:, :, i], rFilter, kFilter) step += 1 self.progress.value = step utils.set_array(dataset, tiltSeries) # Assign Negative Shifts when Shift > N/2. indices_X = np.where(offsets[:, 0] > tiltSeries.shape[0] / 2) offsets[indices_X, 0] -= tiltSeries.shape[0] indices_Y = np.where(offsets[:, 1] > tiltSeries.shape[1] / 2) offsets[indices_Y, 1] -= tiltSeries.shape[1] # Create a spreadsheet data set from table data column_names = ["X Offset", "Y Offset"] offsetsTable = utils.make_spreadsheet(column_names, offsets) # Set up dictionary to return operator results returnValues = {} returnValues["alignments"] = offsetsTable return returnValues
def transform_scalars(self, dataset, Niter=None, stepSize=None, updateMethodIndex=None): """ 3D Reconstruct from a tilt series using Simultaneous Iterative Reconstruction Techniques (SIRT)""" self.progress.maximum = 1 update_methods = ('landweber', 'cimmino', 'component averaging') #reference """L. Landweber, Amer. J. Math., 73 (1951), pp. 615–624""" """G. Cimmino, La Ric. Sci., XVI, Ser. II, Anno IX, 1 (1938), pp. 326–333 """ """Y. Censor et al, Parallel Comput., 27 (2001), pp. 777–808""" # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) #remove zero tilt anlges if np.count_nonzero(tiltAngles) < tiltAngles.size: tiltAngles = tiltAngles + 0.001 # Get Tilt Series tiltSeries = utils.get_array(dataset) (Nslice, Nray, Nproj) = tiltSeries.shape if tiltSeries is None: raise RuntimeError("No scalars found!") # Generate measurement matrix self.progress.message = 'Generating measurement matrix' A = parallelRay(Nray, 1.0, tiltAngles, Nray, 1.0) #A is a sparse matrix recon = np.empty([Nslice, Nray, Nray], dtype=float, order='F') self.progress.maximum = Nslice + 1 step = 0 #create a reconstruction object r = SIRT(A, update_methods[updateMethodIndex]) r.initialize() step += 1 self.progress.value = step for s in range(Nslice): if self.canceled: return b = tiltSeries[s, :, :].transpose().flatten() self.progress.message = 'Slice No.%d/%d' % (s + 1, Nslice) recon[s, :, :] = r.recon2(b, Niter, stepSize).reshape((Nray, Nray)) step += 1 self.progress.value = step from vtk import vtkImageData recon_dataset = vtkImageData() recon_dataset.CopyStructure(dataset) utils.set_array(recon_dataset, recon) utils.mark_as_volume(recon_dataset) returnValues = {} returnValues["reconstruction"] = recon_dataset return returnValues
def transform_scalars(self, dataset, Niter=None, Niter_update_support=None, supportSigma=None, supportThreshold=None): """ 3D Reconstruct from a tilt series using constraint-based Direct Fourier Method """ self.progress.maximum = 1 from tomviz import utils import numpy as np supportThreshold = supportThreshold / 100.0 nonnegativeVoxels = True tiltAngles = utils.get_tilt_angles(dataset) #Get Tilt angles tiltSeries = utils.get_array(dataset) if tiltSeries is None: raise RuntimeError("No scalars found!") self.progress.message = 'Initialization' #Direct Fourier recon without constraints (recon, recon_F) \ = dfm3(tiltSeries, tiltAngles, np.size(tiltSeries, 0) * 2) kr_cutoffs = np.linspace(0.05, 0.5, 10) #average Fourier magnitude of tilt series as a function of kr I_data = radial_average(tiltSeries, kr_cutoffs) (Nx, Ny, Nz) = recon_F.shape #Note: Nz = np.int(Ny/2+1) Ntot = Nx * Ny * Ny f = pyfftw.n_byte_align_empty((Nx, Ny, Nz), 16, dtype='complex128') r = pyfftw.n_byte_align_empty((Nx, Ny, Ny), 16, dtype='float64') fft_forward = pyfftw.FFTW(r, f, axes=(0, 1, 2)) fft_inverse = pyfftw.FFTW(f, r, direction='FFTW_BACKWARD', axes=(0, 1, 2)) kx = np.fft.fftfreq(Nx) ky = np.fft.fftfreq(Ny) kz = ky[0:Nz] kX, kY, kZ = np.meshgrid(ky, kx, kz) kR = np.sqrt(kY**2 + kX**2 + kZ**2) sigma = 0.5 * supportSigma G = np.exp(-kR**2 / (2 * sigma**2)) #create initial support using sw f = recon_F * G fft_inverse.update_arrays(f, r) fft_inverse.execute() cutoff = np.amax(r) * supportThreshold support = r >= cutoff recon_F[kR > kr_cutoffs[-1]] = 0 x = np.random.rand(Nx, Ny, Ny) #initial solution self.progress.maximum = Niter step = 0 for i in range(Niter): if self.canceled: return self.progress.message = 'Iteration No.%d/%d' % (i + 1, Niter) #image space projection y1 = x.copy() if nonnegativeVoxels: y1[y1 < 0] = 0 #non-negative constraint y1[np.logical_not(support)] = 0 #support constraint #Fourier space projection y2 = 2 * y1 - x r = y2.copy() fft_forward.update_arrays(r, f) fft_forward.execute() f[kR > kr_cutoffs[-1]] = 0 #apply low pass filter f[recon_F != 0] = recon_F[recon_F != 0] #data constraint #Fourier magnitude constraint #leave the inner shell unchanged for j in range(1, kr_cutoffs.size): shell = np.logical_and(kR > kr_cutoffs[j - 1], kR <= kr_cutoffs[j]) shell[recon_F != 0] = False I = np.sum(np.absolute(f[shell])) if I != 0: I = I / np.sum(shell) # lower magnitude for high frequency information to reduce # artifacts f[shell] = f[shell] / I * I_data[j] * 0.5 fft_inverse.update_arrays(f, r) fft_inverse.execute() y2 = r.copy() / Ntot #update x = x + y2 - y1 #update support if (i < Niter and np.mod(i, Niter_update_support) == 0): print("updating support") recon = (y2 + y1) / 2 r = recon.copy() fft_forward.update_arrays(r, f) fft_forward.execute() f = f * G fft_inverse.update_arrays(f, r) fft_inverse.execute() cutoff = np.amax(r) * supportThreshold support = r >= cutoff step += 1 self.progress.value = step recon = (y2 + y1) / 2 recon = np.fft.fftshift(recon) print('Reconsruction Complete') # Set the result as the new scalars. utils.set_array(dataset, recon) # Mark dataset as volume utils.mark_as_volume(dataset)
def transform_scalars(self, dataset, Niter=1): """3D Reconstruct from a tilt series using simple TV minimzation""" self.progress.maximum = 1 # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) #remove zero tilt anlges if np.count_nonzero(tiltAngles) < tiltAngles.size: tiltAngles = tiltAngles + 0.001 # Get Tilt Series tiltSeries = utils.get_array(dataset) (Nslice, Nray, Nproj) = tiltSeries.shape if tiltSeries is None: raise RuntimeError("No scalars found!") # Generate measurement matrix A = parallelRay(Nray, 1.0, tiltAngles, Nray, 1.0) #A is a sparse matrix recon = np.zeros((Nslice, Nray, Nray)) #allocate reconstruction matrix A = A.todense() (Nslice, Nray, Nproj) = tiltSeries.shape (Nrow, Ncol) = A.shape rowInnerProduct = np.zeros(Nrow) row = np.zeros(Ncol) f = np.zeros(Ncol) # Placeholder for 2d image alpha = 0.2 ng = 30 beta_red = 0.995 beta = 1.0 # Calculate row inner product, preparation for ART recon for j in range(Nrow): row[:] = A[j, ].copy() rowInnerProduct[j] = np.dot(row, row) self.progress.maximum = Niter step = 0 for i in range(Niter): #main loop if self.canceled: return self.progress.message = 'Iteration No.%d/%d' % (i + 1, Niter) recon_temp = recon.copy() #ART recon for s in range(Nslice): # f[:] = 0 b = tiltSeries[s, :, :].transpose().flatten() for j in range(Nrow): row[:] = A[j, ].copy() row_f_product = np.dot(row, f) a = (b[j] - row_f_product) / rowInnerProduct[j] f = f + row * a * beta recon[s, :, :] = f.reshape((Nray, Nray)) recon[recon < 0] = 0 #Positivity constraint #calculate tomogram change due to POCS dPOCS = np.linalg.norm(recon_temp - recon) #3D TV minimization for j in range(ng): r = np.lib.pad(recon, ((1, 1), (1, 1), (1, 1)), 'edge') v1n = 3 * r - np.roll(r, 1, axis=0) - \ np.roll(r, 1, axis=1) - np.roll(r, 1, axis=2) # noqa TODO reformat this v1d = np.sqrt( 1e-8 + (r - np.roll(r, 1, axis=0))**2 + (r - np.roll(r, 1, axis=1))**2 + (r - np.roll(r, 1, axis=2))**2) # noqa TODO reformat this v2n = r - np.roll(r, -1, axis=0) v2d = np.sqrt(1e-8 + (np.roll(r, -1, axis=0) - r)**2 + ( np.roll(r, -1, axis=0) - # noqa TODO reformat this np.roll(np.roll(r, -1, axis=0), 1, axis=1))**2 + (np.roll(r, -1, axis=0) - np.roll(np.roll(r, -1, axis=0), 1, axis=2))** 2) # noqa TODO reformat this v3n = r - np.roll(r, -1, axis=1) v3d = np.sqrt(1e-8 + (np.roll(r, -1, axis=1) - np.roll(np.roll(r, -1, axis=1), 1, axis=0))**2 + # noqa TODO reformat this (np.roll(r, -1, axis=1) - r)**2 + # noqa TODO reformat this (np.roll(r, -1, axis=1) - np.roll(np.roll(r, -1, axis=1), 1, axis=2))** 2) # noqa TODO reformat this v4n = r - np.roll(r, -1, axis=2) v4d = np.sqrt( 1e-8 + (np.roll(r, -1, axis=2) - np.roll(np.roll(r, -1, axis=2), 1, axis=0))**2 + # noqa TODO reformat this ( np.roll(r, -1, axis=2) - # noqa TODO reformat this np.roll(np.roll(r, -1, axis=1), 1, axis=1))**2 + (np.roll(r, -1, axis=2) - r)**2) # noqa TODO reformat this v = v1n / v1d + v2n / v2d + v3n / v3d + v4n / v4d v = v[1:-1, 1:-1, 1:-1] v = v / np.linalg.norm(v) recon = recon - alpha * dPOCS * v #adjust parameters beta = beta * beta_red step += 1 self.progress.value = step # Set the result as the new scalars. utils.set_array(dataset, recon) # Mark dataset as volume utils.mark_as_volume(dataset)
def transform_scalars(self, dataset, start_angle=-90.0, angle_increment=3.0, num_tilts=60): """Generate Tilt Series from Volume""" self.progress.maximum = 1 self.progress.message = 'Initialization' # Generate Tilt Angles. angles = np.linspace(start_angle, start_angle + (num_tilts - 1) * angle_increment, num_tilts) volume = utils.get_array(dataset) Ny = volume.shape[1] Nz = volume.shape[2] # calculate the size s.t. it contains the entire volume N = np.round(np.sqrt(Ny**2 + Nz**2)) N = int(np.floor(N / 2.0) * 2 + 1) # make the size an odd integer # pad volume pad_y_pre = int(np.ceil((N - Ny) / 2.0)) pad_y_post = int(np.floor((N - Ny) / 2.0)) pad_z_pre = int(np.ceil((N - Nz) / 2.0)) pad_z_post = int(np.floor((N - Nz) / 2.0)) volume_pad = np.lib.pad(volume, ((0, 0), (pad_y_pre, pad_y_post), (pad_z_pre, pad_z_post)), 'constant') Nslice = volume.shape[0] # Number of slices along rotation axis. tiltSeries = np.zeros((Nslice, N, num_tilts)) self.progress.maximum = num_tilts step = 0 for i in range(num_tilts): if self.canceled: return self.progress.message = 'Generating tilt image No.%d/%d' % ( i + 1, num_tilts) # Rotate volume about x-axis rotatedVolume = np.empty_like(volume_pad) scipy.ndimage.interpolation.rotate(volume_pad, angles[i], axes=(1, 2), reshape=False, order=1, output=rotatedVolume) # Calculate projection tiltSeries[:, :, i] = np.sum(rotatedVolume, axis=2) step += 1 self.progress.value = step # Set the result as the new scalars. utils.set_array(dataset, tiltSeries) # Mark dataset as tilt series. utils.mark_as_tiltseries(dataset) # Save tilt angles. utils.set_tilt_angles(dataset, angles)
def convert_vtk_to_itk_image(vtk_image_data, itk_pixel_type=None): """Get an ITK image from the provided vtkImageData object. This image can be passed to ITK filters.""" # Save the VTKGlue optimization for later #------------------------------------------ #itk_import = itk.VTKImageToImageFilter[image_type].New() #itk_import.SetInput(vtk_image_data) #itk_import.Update() #itk_image = itk_import.GetOutput() #itk_image.DisconnectPipeline() #------------------------------------------ import itk import itkTypes from vtkmodules.util import vtkConstants from vtkmodules.vtkImagingCore import vtkImageCast from tomviz import utils itk_to_vtk_type_map = { itkTypes.F: vtkConstants.VTK_FLOAT, itkTypes.D: vtkConstants.VTK_DOUBLE, itkTypes.LD: vtkConstants.VTK_DOUBLE, itkTypes.UC: vtkConstants.VTK_UNSIGNED_CHAR, itkTypes.US: vtkConstants.VTK_UNSIGNED_SHORT, itkTypes.UI: vtkConstants.VTK_UNSIGNED_INT, itkTypes.UL: vtkConstants.VTK_UNSIGNED_LONG, itkTypes.SC: vtkConstants.VTK_CHAR, itkTypes.SS: vtkConstants.VTK_SHORT, itkTypes.SI: vtkConstants.VTK_INT, itkTypes.SL: vtkConstants.VTK_LONG, itkTypes.B: vtkConstants.VTK_INT } # See if we need to cast to a wrapped type in ITK. src_type = vtk_image_data.GetScalarType() if itk_pixel_type is None: dst_type = vtk_cast_map()[src_type] else: dst_type = vtk_cast_map()[itk_to_vtk_type_map[itk_pixel_type]] if src_type != dst_type: caster = vtkImageCast() caster.SetOutputScalarType(dst_type) caster.ClampOverflowOn() caster.SetInputData(vtk_image_data) caster.Update() vtk_image_data = caster.GetOutput() array = utils.get_array(vtk_image_data, order='C') image_type = _get_itk_image_type(vtk_image_data) itk_converter = itk.PyBuffer[image_type] itk_image = itk_converter.GetImageFromArray(array) spacing = vtk_image_data.GetSpacing() origin = vtk_image_data.GetOrigin() itk_image.SetSpacing(spacing) itk_image.SetOrigin(origin) # Persist a reference to the source vtk_image_data, which is necessary since # VTK and ITK are using Python Buffer-Protocol NumPy array views itk_image.vtk_image_data = vtk_image_data return itk_image
def transform_scalars(self, dataset, Niter=1): """ 3D Reconstruction using Algebraic Reconstruction Technique (ART) """ self.progress.maximum = 1 # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) # Get Tilt Series tiltSeries = utils.get_array(dataset) (Nslice, Nray, Nproj) = tiltSeries.shape if tiltSeries is None: raise RuntimeError("No scalars found!") # Generate measurement matrix self.progress.message = 'Generating measurement matrix' A = parallelRay(Nray, 1.0, tiltAngles, Nray, 1.0) #A is a sparse matrix recon = np.empty([Nslice, Nray, Nray], dtype=float, order='F') A = A.todense() (Nslice, Nray, Nproj) = tiltSeries.shape (Nrow, Ncol) = A.shape rowInnerProduct = np.zeros(Nrow) row = np.zeros(Ncol) f = np.zeros(Ncol) # Placeholder for 2d image beta = 1.0 # Calculate row inner product for j in range(Nrow): row[:] = A[j, ].copy() rowInnerProduct[j] = np.dot(row, row) self.progress.maximum = Nslice step = 0 for s in range(Nslice): if self.canceled: return f[:] = 0 b = tiltSeries[s, :, :].transpose().flatten() for i in range(Niter): self.progress.message = 'Slice No.%d/%d, iteration No.%d/%d' % ( s + 1, Nslice, i + 1, Niter) for j in range(Nrow): row[:] = A[j, ].copy() row_f_product = np.dot(row, f) a = (b[j] - row_f_product) / rowInnerProduct[j] f = f + row * a * beta recon[s, :, :] = f.reshape((Nray, Nray)) step += 1 self.progress.value = step from vtk import vtkImageData # Set up the output dataset recon_dataset = vtkImageData() recon_dataset.CopyStructure(dataset) utils.set_array(recon_dataset, recon) utils.mark_as_volume(recon_dataset) returnValues = {} returnValues["reconstruction"] = recon_dataset return returnValues
def transform_scalars(self, dataset): """3D Reconstruct from a tilt series using Direct Fourier Method""" self.progress.maximum = 1 from tomviz import utils import numpy as np # Get Tilt angles tiltAngles = utils.get_tilt_angles(dataset) tiltSeries = utils.get_array(dataset) if tiltSeries is None: raise RuntimeError("No scalars found!") tiltSeries = np.double(tiltSeries) (Nx, Ny, Nproj) = tiltSeries.shape Npad = Ny * 2 tiltAngles = np.double(tiltAngles) pad_pre = int(np.ceil((Npad - Ny) / 2.0)) pad_post = int(np.floor((Npad - Ny) / 2.0)) # Initialization self.progress.message = 'Initialization' Nz = Ny w = np.zeros((Nx, Ny, Nz // 2 + 1)) #store weighting factors v = pyfftw.n_byte_align_empty((Nx, Ny, Nz // 2 + 1), 16, dtype='complex128') v = np.zeros(v.shape) + 1j * np.zeros(v.shape) recon = pyfftw.n_byte_align_empty((Nx, Ny, Nz), 16, dtype='float64', order='F') recon_fftw_object = pyfftw.FFTW(v, recon, direction='FFTW_BACKWARD', axes=(0, 1, 2)) p = pyfftw.n_byte_align_empty((Nx, Npad), 16, dtype='float64') pF = pyfftw.n_byte_align_empty((Nx, Npad // 2 + 1), 16, dtype='complex128') p_fftw_object = pyfftw.FFTW(p, pF, axes=(0, 1)) dk = np.double(Ny) / np.double(Npad) self.progress.maximum = Nproj + 1 step = 0 t0 = time.time() etcMessage = 'Estimated time to complete: n/a' counter = 1 for a in range(Nproj): if self.canceled: return self.progress.message = 'Tilt image No.%d/%d. ' % ( a + 1, Nproj) + etcMessage ang = tiltAngles[a] * np.pi / 180 projection = tiltSeries[:, :, a] #2D projection image p = np.lib.pad(projection, ((0, 0), (pad_pre, pad_post)), 'constant', constant_values=(0, 0)) #pad zeros p = np.fft.ifftshift(p) p_fftw_object.update_arrays(p, pF) p_fftw_object() probjection_f = pF.copy() if ang < 0: probjection_f = np.conj(pF.copy()) probjection_f[1:, :] = np.flipud(probjection_f[1:, :]) ang = np.pi + ang # Bilinear extrapolation for i in range(0, np.int(np.ceil(Npad / 2)) + 1): ky = i * dk #kz = 0 ky_new = np.cos(ang) * ky #new coord. after rotation kz_new = np.sin(ang) * ky sy = abs(np.floor(ky_new) - ky_new) #calculate weights sz = abs(np.floor(kz_new) - kz_new) for b in range(1, 5): #bilinear extrapolation pz, py, weight = bilinear(kz_new, ky_new, sz, sy, Ny, b) if (py >= 0 and py < Ny and pz >= 0 and pz < Nz / 2 + 1): w[:, py, pz] = w[:, py, pz] + weight v[:, py, pz] = v[:, py, pz] + \ weight * probjection_f[:, i] step += 1 self.progress.value = step timeLeft = (time.time() - t0) / counter * (Nproj - counter) counter += 1 timeLeftMin, timeLeftSec = divmod(timeLeft, 60) timeLeftHour, timeLeftMin = divmod(timeLeftMin, 60) etcMessage = 'Estimated time to complete: %02d:%02d:%02d' % ( timeLeftHour, timeLeftMin, timeLeftSec) self.progress.message = 'Inverse Fourier transform' v[w != 0] = v[w != 0] / w[w != 0] recon_fftw_object.update_arrays(v, recon) recon_fftw_object() recon[:] = np.fft.fftshift(recon) step += 1 self.progress.value = step from vtk import vtkImageData recon_dataset = vtkImageData() recon_dataset.CopyStructure(dataset) utils.set_array(recon_dataset, recon) utils.mark_as_volume(recon_dataset) returnValues = {} returnValues["reconstruction"] = recon_dataset return returnValues