def subPixelPeak(inp, k=1, ignore_border=1): from pytom.voltools import transform is2d = len(inp.shape.squeeze()) == 2 if is2d: inp2 = inp.squeeze()[ignore_border:-ignore_border, ignore_border:-ignore_border] scale = (k, k, 1) out = xp.array(inp.squeeze(), dtype=xp.float32) x, y = xp.array(xp.unravel_index(inp2.argmax(), inp2.shape)) + ignore_border out = xp.expand_dims(out, 2) translation = [inp.shape[0] // 2 - x, inp.shape[1] // 2 - y, 0] else: inp2 = inp[ignore_border:-ignore_border, ignore_border:-ignore_border, ignore_border:-ignore_border] scale = (k, k, k) out = xp.array(inp, dtype=xp.float32) x, y, z = xp.array(xp.unravel_index(inp2.argmax(), inp2.shape)) + ignore_border translation = [ inp.shape[0] // 2 - x, inp.shape[1] // 2 - y, inp.shape[2] // 2 - z ] zoomed = xp.zeros_like(out, dtype=xp.float32) transform(out, output=zoomed, scale=scale, translation=translation, device='gpu:0', interpolation='filt_bspline') shifts = [x2, y2, z2] = xp.unravel_index(zoomed.argmax(), zoomed.shape) return [zoomed[x2, y2, z2], shifts[3 - is2d]]
def find_sub_pixel_max_value_voltools(inp, k=.1, ignore_border=50): """ To find the highest point in a 2D array, with subpixel accuracy based on 1D spline interpolation. The algorithm is based on a matlab script "tom_peak.m" @param inp: A 2D numpy array containing the data points. @type inp: numpy array 2D @param k: The smoothing factor used in the spline interpolation, must be 1 <= k <= 5. @type k: int @return: A list of all points of maximal value in the structure of tuples with the x position, the y position and the value. @returntype: list """ # assert len(ixp.shape) == 2 # assert isinstance(k, int) and 1 <= k <= 5 import cupy import numpy as xp from scipy.interpolate import InterpolatedUnivariateSpline from pytom.voltools import transform inp2 = inp[ignore_border:-ignore_border, ignore_border:-ignore_border] out = cupy.array(inp, dtype=cupy.float32) x, y = xp.array(xp.unravel_index(inp2.argmax(), inp2.shape)) + ignore_border out = cupy.expand_dims(out, 2) zoomed = cupy.zeros_like(out, dtype=cupy.float32) transform(out, output=zoomed, scale=(k, k, 1), translation=[inp.shape[0] // 2 - x, inp.shape[1] // 2 - y, 0], device='gpu:0', interpolation='filt_bspline') z = zoomed.get().squeeze() x2, y2 = xp.unravel_index(z.argmax(), z.shape) return [ x + (x2 - z.shape[0] // 2) * k - z.shape[0] // 2, y + (y2 - z.shape[1] // 2) * k - z.shape[0] // 2, z, x, y, x2, y2 ]
def maxIndex(volume, num_threads=1024): nblocks = int(xp.ceil(volume.size / num_threads / 2)) fast_sum = -1000000 * xp.ones((nblocks), dtype=xp.float32) max_id = xp.zeros((nblocks), dtype=xp.int32) argmax(( nblocks, 1, ), (num_threads, 1, 1), (volume, fast_sum, max_id, volume.size), shared_mem=16 * num_threads) mm = min(max_id[fast_sum.argmax()], volume.size - 1) indices = xp.unravel_index(mm, volume.shape) return indices
def find_sub_pixel_voltools(inp, k=0.1, border=75, max_shift=15): import pytom.voltools as vt inp = xp.ascontiguousarray(inp) # find the position of the initial maximum dimx, dimy = inp.squeeze().shape initial_max = xp.unravel_index( inp[border:-border, border:-border].argmax(), (dimx - border * 2, dimy - border * 2)) ix, iy = [v + border for v in initial_max] # Create an array with specific size so the zoom fits in (size = max_shift * 2 /k) # Center of array is initial max out = int(xp.around(max_shift * 2 / k)) model = xp.zeros((out, out), dtype=xp.float32) model[out // 2 - max_shift:out // 2 + max_shift, out // 2 - max_shift:out // 2 + max_shift] = inp[ix - max_shift:ix + max_shift, iy - max_shift:iy + max_shift] zoomedVol = xp.expand_dims(model, 2) # Scale image vt.transform(zoomedVol, scale=(k, k, 1), interpolation='filt_bspline', device=device, output=zoomedVol) # fig, ax = subplots(1, 2, figsize=(10, 5)) # ax[0].imshow(inp.get().squeeze()) # ax[1].imshow(zoomedVol.squeeze().get()) # show() # Find new max and update the initial max according to the shift transformed_max = xp.unravel_index(zoomedVol.argmax(), zoomedVol.shape) interpolX, interpolY = ix + (transformed_max[0] - out // 2) * k, iy + ( transformed_max[1] - out // 2) * k return interpolX, interpolY, zoomedVol.squeeze()
def subPixelMax3D(volume, k=.01, ignore_border=50, interpolation='filt_bspline', plan=None, profile=True, num_threads=1024, zoomed=None, fast_sum=None, max_id=None): """ Function to find the highest point in a 3D array, with subpixel accuracy using cubic spline interpolation. @param inp: A 3D numpy/cupy array containing the data points. @type inp: numpy/cupy array 3D @param k: The interpolation factor used in the spline interpolation, k < 1 is zoomed in, k>1 zoom out. @type k: float @return: A list of maximal value in the interpolated volume and a list of x position, the y position and the value. @returntype: list """ from pytom.voltools import transform from pytom.tompy.io import write ox, oy, oz = volume.shape ib = ignore_border cropped_volume = volume[ib:ox - ib, ib:oy - ib, ib:oz - ib].astype(xp.float32) if profile: stream = xp.cuda.Stream.null t_start = stream.record() # x,y,z = xp.array(maxIndex(cropped_volume)) + ignore_border x, y, z = xp.array( xp.unravel_index(cropped_volume.argmax(), cropped_volume.shape)) + ignore_border dx, dy, dz = volume.shape translation = [dx // 2 - x, dy // 2 - y, dz // 2 - z] if profile: t_end = stream.record() t_end.synchronize() time_took = xp.cuda.get_elapsed_time(t_start, t_end) print(f'initial find max time: \t{time_took:.3f}ms') t_start = stream.record() b = border = max(0, int(volume.shape[0] // 2 - 4 / k)) zx, zy, zz = volume.shape out = volume[b:zx - b, b:zy - b, b:zz - b] transform(out, output=zoomed, scale=(k, k, k), device=device, translation=translation, interpolation=interpolation) if profile: t_end = stream.record() t_end.synchronize() time_took = xp.cuda.get_elapsed_time(t_start, t_end) print(f'transform finished in \t{time_took:.3f}ms') t_start = stream.record() nblocks = int(xp.ceil(zoomed.size / num_threads / 2)) argmax(( nblocks, 1, ), (num_threads, 1, 1), (zoomed, fast_sum, max_id, zoomed.size), shared_mem=8 * num_threads) x2, y2, z2 = xp.unravel_index(max_id[fast_sum.argmax()], zoomed.shape) peakValue = zoomed[x2][y2][z2] peakShift = [ x + (x2 - zoomed.shape[0] // 2) * k - volume.shape[0] // 2, y + (y2 - zoomed.shape[1] // 2) * k - volume.shape[1] // 2, z + (z2 - zoomed.shape[2] // 2) * k - volume.shape[2] // 2 ] if profile: t_end = stream.record() t_end.synchronize() time_took = xp.cuda.get_elapsed_time(t_start, t_end) print(f'argmax finished in \t{time_took:.3f}ms') t_start = stream.record() print() return [peakValue, peakShift]
def find_sub_pixel_max_value_2d(inp, interpolate_factor=100, smoothing=0, dim=10, border_size=5, ignore_border=37): #ignore_border for 200: 75 """ To find the highest point in a given numpy array based on 2d spline interpolation, returns the maximum with subpixel precision. @param inp: The input data array (numpy 2D) @type inp: numpy array 2D @param interpolate_factor: The amount of interpolation to be done @type interpolate_factor: int @param smoothing: The amount of smoothing in the spline interpolation @type smoothing: int @param dim: The dimensions of the peak cutout, which is interpolated to find the subpixel maximum (initial pixels) @type dim: int @param border_size: The amount of pixels (initial pixels) to disregard in the peak cutout @type border_size: int @param ignore_border: The amount of pixels (initial pixels) to disregard in the initial finding of the initial maximum, to force the found maximum to be more in the center @type ignore_border: int @return: The subpixel maximum (x, y, the interpolated peak (excluding the border area)) @returntype: tuple <-------- Vol_Size -------> | ignore_border | | | <------ a ------> | | -> | | <- | | | Here the max is | | | | found | | | | d> <c> <d | | | | |.. max ..| | | | | |... * ...| | | | | |.........| | | | | <-- b --> | | | ------------------- | |___________________________| a: vol_size - 2 * ignore_border (original pixels) b: dim * 2 (original pixels) c: b * interpolate_factor - 2 * d (interpolated pixels) d: border_size * interpolate_factor (interpolated pixels) ...: interpolated values *: peak found """ # assert len(ixp.shape) == 2 # assert isinstance(interpolate_factor, int) and interpolate_factor > 0 # assert isinstance(smoothing, float) and smoothing >= 0 # assert isinstance(dim, int) and dim > 0 # assert isinstance(border_size, int) and border_size > 0 # assert isinstance(ignore_border, int) and ignore_border > 0 import numpy as xp from scipy import interpolate import warnings border_size = border_size * interpolate_factor # Get the position of the initial maximum inp_without_border = inp[ignore_border:-ignore_border, ignore_border:-ignore_border] initial_max = xp.unravel_index(inp_without_border.argmax(), inp_without_border.shape) # Reset the coordinates to be relative to the original inp(ut) initial_max = (initial_max[0] + ignore_border, initial_max[1] + ignore_border) # imshow(inp[initial_max[0]-10: initial_max[0]+10, initial_max[1]-10: initial_max[1]+10]) # show() # Get the starting points of the peak cutout x_dim = inp.shape[0] y_dim = inp.shape[1] x_start = max([0, initial_max[0] - dim]) x_end = min([x_dim, initial_max[0] + dim]) y_start = max([0, initial_max[1] - dim]) y_end = min([y_dim, initial_max[1] + dim]) # Create a grid to save the original points and one to save the interpolated points x, y = xp.mgrid[0:x_end - x_start, 0:y_end - y_start] xnew, ynew = xp.mgrid[0:x_end - x_start:1 / interpolate_factor, 0:y_end - y_start:1 / interpolate_factor] #print(x_start, x_end, y_start, y_end) # Interpolate the points # While catching warnings from the pessimistic algorithm of interpolate, # which always thinks it needs too much memory with warnings.catch_warnings(): warnings.simplefilter("ignore") tck = interpolate.bisplrep(x, y, inp[x_start:x_end, y_start:y_end], s=smoothing) interpolated_grid = interpolate.bisplev(xnew[:, 0], ynew[0, :], tck) cropped_inter_grid = interpolated_grid[border_size:-border_size, border_size:-border_size] result = xp.unravel_index(cropped_inter_grid.argmax(), cropped_inter_grid.shape) rx, ry = result ix, iy = interpolated_grid.shape # imshow(interpolated_grid) # show() # Reset the coordinates to point to a place in the original data array result = [ x_start + (border_size + rx) / interpolate_factor, y_start + (border_size + ry) / interpolate_factor ] return result[0], result[1], cropped_inter_grid
def run_single_tilt_angle(subtomogram, ang, offset, vol_size, particle_position, particle_rotation, particle_filename, particle_number, binning, img, create_graphics, fsc_path, dimz, peak_border): """ To run a single tilt angle to allow for parallel computing @param ang: the tilt angle @type ang: int @param subtomogram: the filename of the subtomogram @type subtomogram: str @param offset: the offset used (x,y,z) @type offset: list(int, int, int) @param vol_size: the size of the volume to be reconstructed (in pixels) @type vol_size: int @param particle_position: the position of the particle in vector format, as given by particle.pickPosition().toVector() @type particle_position: tuple @param particle_rotation: the rotation of the particle (Z1/phi, X/the, Z2/psi) @type particle_rotation: tuple @param particle_filename: the filename of the particle, as given by particle.getfilename() @type particle_filename: str @param particle_number: the number of the particle, to allow for unique mapping @type particle_number: int @param binning: the binning factor used @type binning: int @param img: the filename of the projection to be used @type img: str @param create_graphics: to flag if images should be created for human inspection of the work done @type create_graphics: bool @return: the newly found positions of the particle, as a list in the LOCAL_ALIGNMENT_RESULTS format @returntype: list """ from pytom.reconstruction.reconstructionFunctions import alignImageUsingAlignmentResultFile from pytom.tompy.transform import rotate3d, rotate_axis from pytom.gui.guiFunctions import datatypeAR, loadstar import numpy as np from math import cos, sin, pi, sqrt from pytom.tompy.tools import create_circle from pytom.tompy.transform import cut_from_projection from pytom.tompy.filter import applyFourierFilterFull, bandpass_circle from pytom.tompy.io import read, write from pytom.tompy.correlation import meanUnderMask, stdUnderMask import os import time t = time.time() # print(particle_filename, ang) # Filter using FSC fsc_mask = None k = 0.01 subtomogram = read(subtomogram) * read( '/data/gijsvds/ctem/05_Subtomogram_Analysis/Alignment/GLocal/mask_200_75_5.mrc' ) import os from pytom.tompy.filter import filter_volume_by_profile, profile2FourierVol fsc_path = '' if os.path.isfile(fsc_path): profile = [line.split()[0] for line in open(fsc_path, 'r').readlines()] fsc_mask3d = profile2FourierVol(profile, subtomogram.shape) subtomogram = applyFourierFilterFull(subtomogram, fsc_mask3d) # Cross correlate the templat # e and patch, this should give the pixel shift it is after from pytom.tompy.correlation import nXcf # Get template # First rotate the template towards orientation of the particle, then to the tilt angle img = read(img) rotated1 = rotate3d(subtomogram, phi=particle_rotation[0], the=particle_rotation[1], psi=particle_rotation[2]) rotated2 = rotate_axis( rotated1, -ang, 'y') # SWITCHED TO ROTATE AXIS AND ANGLE *-1 THIS IS AN ATTEMPT template = rotated2.sum(axis=2) # write('pp1_template.mrc', template) # img = read(img) try: patch, xx, yy = cut_patch(img, ang, particle_position, dimz=dimz, vol_size=vol_size, binning=binning) mask2d = create_circle(patch.shape, radius=75, sigma=5, num_sigma=2) patch *= mask2d # write('pp1_patch.mrc', patch) if os.path.isfile(fsc_path): profile = [ line.split()[0] for line in open(fsc_path, 'r').readlines() ] fsc_mask2d = profile2FourierVol(profile, patch.shape) patch = applyFourierFilterFull(patch, fsc_mask2d) template = normalize_image(template, mask2d, mask2d.sum()) patch = normalize_image(patch, mask2d, mask2d.sum()) if 1: ff = xp.ones_like(patch) else: ff = bandpass_circle(patch.squeeze(), 6, 25, 3) ccf = normalised_cross_correlation(template, patch, ff) points2d1 = find_sub_pixel_max_value_2d(ccf.copy(), ignore_border=peak_border) points2d2 = find_sub_pixel_max_value(ccf.copy(), ignore_border=peak_border) points2d = list(points2d2[:2]) + [points2d1[-1]] x_diff = points2d[0] - vol_size / 2 y_diff = points2d[1] - vol_size / 2 dist = sqrt(x_diff**2 + y_diff**2) #rx, ry, ii, oox, ooy, x2, y2 = find_sub_pixel_max_value_voltools(ccf.copy()) #print(rx,ry, x_diff, y_diff, x2, y2, oox, ooy, ii.shape) #print(f'{particle_number:3d} {ang:5.1f}, {dist:5.2f} {x_diff} {y_diff} {ccf.max()}') if create_graphics: rx, ry, ii, oox, ooy, x2, y2 = find_sub_pixel_max_value_voltools( ccf.copy(), k=k) print(rx, ry) from scipy.ndimage.filters import gaussian_filter # Create an image to display and/or test the inner workings of the algorithm points = find_sub_pixel_max_value(ccf, ignore_border=peak_border) nx, ny, nz = particle_position nx += x_diff ny += y_diff npatch = cut_from_projection( img.squeeze(), [xx + x_diff, yy + y_diff], [vol_size, vol_size] ) # img.sum(axis=2)[int(xx+x_diff-v):int(xx+x_diff+v), int(yy+y_diff-v):int(yy+y_diff+v)] # npatch = normalize_image(npatch, mask2d, mask2d.sum()) nccf = normalised_cross_correlation(template, npatch.squeeze(), ff) npoints = find_sub_pixel_max_value(nccf, ignore_border=peak_border) npoints2d = find_sub_pixel_max_value_2d(nccf, ignore_border=peak_border) #rx, ry = abs(xp.array(npoints2d[:2]) - 100) from scipy.ndimage.filters import gaussian_filter # Create an image to display and/or test the inner workings of the algorithm points = find_sub_pixel_max_value(ccf, ignore_border=peak_border) nx, ny, nz = particle_position nx += x_diff ny += y_diff npatch = cut_from_projection( img.squeeze(), [xx + x_diff, yy + y_diff], [vol_size, vol_size] ) # img.sum(axis=2)[int(xx+x_diff-v):int(xx+x_diff+v), int(yy+y_diff-v):int(yy+y_diff+v)] # npatch = normalize_image(npatch, mask2d, mask2d.sum()) nccf = normalised_cross_correlation(template, npatch.squeeze(), ff) npoints = find_sub_pixel_max_value(nccf, ignore_border=peak_border) npoints2d = find_sub_pixel_max_value_2d(nccf, ignore_border=peak_border) #rx, ry = abs(xp.array(npoints2d[:2]) - 100) m_style = dict(color='tab:blue', linestyle=':', marker='o', markersize=5, markerfacecoloralt='tab:red') m_style_alt = dict(color='tab:red', linestyle=':', marker='o', markersize=5, markerfacecoloralt='tab:orange') grid = pp.GridSpec(3, 3, wspace=0, hspace=0.35, left=0.05, right=0.95, top=0.90, bottom=0.05) ax_0_0 = pp.subplot(grid[0, 0]) ax_0_1 = pp.subplot(grid[0, 1]) ax_0_2 = pp.subplot(grid[0, 2]) ax_1_0 = pp.subplot(grid[1, 0]) ax_1_1 = pp.subplot(grid[1, 1]) ax_1_2 = pp.subplot(grid[1, 2]) ax_2_0 = pp.subplot(grid[2, 0]) ax_2_1 = pp.subplot(grid[2, 1]) ax_2_2 = pp.subplot(grid[2, 2]) ax_0_0.axis('off') ax_0_1.axis('off') ax_0_2.axis('off') ax_1_0.axis('off') ax_1_1.axis('off') ax_1_2.axis('off') ax_2_0.axis('off') ax_2_1.axis('off') ax_2_2.axis('off') axis_title(ax_0_0, "Cutout") ax_0_0.imshow(applyFourierFilterFull(patch, xp.fft.fftshift(ff))) axis_title(ax_0_1, "Template") ax_0_1.imshow(template) axis_title(ax_0_2, "Shifted Cutout\n(based on cross correlation)") ax_0_2.imshow(npatch.squeeze()) axis_title(ax_1_0, u"Cross correlation\ncutout × template") ax_1_0.imshow(ccf) ax_1_0.plot([points[1]], [points[0]], fillstyle='none', **m_style) ax_1_0.plot([points2d[1]], [points2d[0]], fillstyle='none', **m_style_alt) ax_1_0.plot([vol_size / 2], [vol_size / 2], ",k") ax_1_1.text( 0.5, 0.8, "Red: 2D spline interpolation\nx: {:f}\ny: {:f}\nBlue: 1D spline interpolation\nx: {:f}\ny: {:f}" "\nBlack: center".format(x_diff, y_diff, points[0] - vol_size / 2, points[1] - vol_size / 2), fontsize=8, horizontalalignment='center', verticalalignment='center', transform=ax_1_1.transAxes) axis_title(ax_1_2, u"Cross correlation\nshifted cutout × template") ax_1_2.imshow(nccf) ax_1_2.plot([npoints[0]], [npoints[1]], fillstyle='none', **m_style) ax_1_2.plot([npoints2d[0]], [npoints2d[1]], fillstyle='none', **m_style_alt) ax_1_2.plot([vol_size / 2], [vol_size / 2], ",k") axis_title(ax_2_0, u"Zoom into red peak\nin CC cutout × template") d = 10 points2d = list(xp.unravel_index(ccf.argmax(), ccf.shape)) + [points2d[-1]] peak = ccf[int(points2d[0]) - d:int(points2d[0]) + d, int(points2d[1]) - d:int(points2d[1] + d)] ax_2_0.imshow(peak) axis_title( ax_2_1, u"Zoom into red peak\nin CC cutout × template\ninterpolated") ax_2_1.imshow(ii) ax_2_1.plot([y2 + (y_diff - ry) / k], [x2 + (x_diff - rx) / k], fillstyle='none', **m_style) ax_2_1.plot([y2], [x2], fillstyle='none', **m_style_alt) axis_title(ax_2_2, u"Cutout\nGaussian filter σ3") import scipy ax_2_2.imshow(scipy.ndimage.gaussian_filter(patch, 3)) pp.savefig( "../Images/test/polish_particle_{:04d}_tiltimage_{:05.2f}_shift_{:.1f}.png" .format(particle_number, ang, dist)) del img except Exception as e: print(e) x_diff = y_diff = 0 print( f'{particle_number:3d} {ang:4d} {x_diff:5.2f} {y_diff:5.2f} {points2d1[0]-patch.shape[0]//2:.2f} {points2d1[1]-patch.shape[0]//2:.2f} {time.time()-t:5.3f}' ) return particle_number, x_diff, y_diff, ang, 0, 0, particle_filename
def find_coords_max_ccmap(volume): return xp.unravel_index(volume.argmax(), volume.shape)