def main(): import sys import os import math import random import pyemtbx.options import time from random import random, seed, randint from optparse import OptionParser progname = os.path.basename(sys.argv[0]) usage = progname + """ [options] <inputfile> <outputfile> Forms chains of 2D images based on their similarities. Functionality: 4. Order a 2-D stack of image based on pair-wise similarity (computed as a cross-correlation coefficent). Options 1-3 require image stack to be aligned. The program will apply orientation parameters if present in headers. The ways to use the program: 4.1 Use option initial to specify which image will be used as an initial seed to form the chain. sxprocess.py input_stack.hdf output_stack.hdf --initial=23 --radius=25 4.2 If options initial is omitted, the program will determine which image best serves as initial seed to form the chain sxprocess.py input_stack.hdf output_stack.hdf --radius=25 4.3 Use option circular to form a circular chain. sxprocess.py input_stack.hdf output_stack.hdf --circular--radius=25 4.4 New circular code based on pairwise alignments sxprocess.py aclf.hdf chain.hdf circle.hdf --align --radius=25 --xr=2 --pairwiseccc=lcc.txt 4.5 Circular ordering based on pairwise alignments sxprocess.py vols.hdf chain.hdf mask.hdf --dd --radius=25 """ parser = OptionParser(usage,version=SPARXVERSION) parser.add_option("--dd", action="store_true", help="Circular ordering without adjustment of orientations", default=False) parser.add_option("--circular", action="store_true", help="Select circular ordering (first image has to be similar to the last)", default=False) parser.add_option("--align", action="store_true", help="Compute all pairwise alignments and for the table of their similarities find the best chain", default=False) parser.add_option("--initial", type="int", default=-1, help="Specifies which image will be used as an initial seed to form the chain. (default = 0, means the first image)") parser.add_option("--radius", type="int", default=-1, help="Radius of a circular mask for similarity based ordering") # import params for 2D alignment parser.add_option("--ou", type="int", default=-1, help="outer radius for 2D alignment < nx/2-1 (set to the radius of the particle)") parser.add_option("--xr", type="int", default=0, help="range for translation search in x direction, search is +/xr (0)") parser.add_option("--yr", type="int", default=0, help="range for translation search in y direction, search is +/yr (0)") #parser.add_option("--nomirror", action="store_true", default=False, help="Disable checking mirror orientations of images (default False)") parser.add_option("--pairwiseccc", type="string", default= None, help="Input/output pairwise ccc file") (options, args) = parser.parse_args() global_def.BATCH = True if options.dd: nargs = len(args) if nargs != 3: print "must provide name of input and two output files!" return stack = args[0] new_stack = args[1] from utilities import model_circle from statistics import ccc from statistics import mono lend = EMUtil.get_image_count(stack) lccc = [None]*(lend*(lend-1)/2) for i in xrange(lend-1): v1 = get_im( stack, i ) if( i == 0 and nargs == 2): nx = v1.get_xsize() ny = v1.get_ysize() nz = v1.get_ysize() if options.ou < 1 : radius = nx//2-2 else: radius = options.ou mask = model_circle(radius, nx, ny, nz) else: mask = get_im(args[2]) for j in xrange(i+1, lend): lccc[mono(i,j)] = [ccc(v1, get_im( stack, j ), mask), 0] order = tsp(lccc) if(len(order) != lend): print " problem with data length" from sys import exit exit() print "Total sum of cccs :",TotalDistance(order, lccc) print "ordering :",order for i in xrange(lend): get_im(stack, order[i]).write_image( new_stack, i ) elif options.align: nargs = len(args) if nargs != 3: print "must provide name of input and two output files!" return from utilities import get_params2D, model_circle from fundamentals import rot_shift2D from statistics import ccc from time import time from alignment import align2d, align2d_scf from multi_shc import mult_transform stack = args[0] new_stack = args[1] d = EMData.read_images(stack) """ # will align anyway try: ttt = d[0].get_attr('xform.params2d') for i in xrange(len(d)): alpha, sx, sy, mirror, scale = get_params2D(d[i]) d[i] = rot_shift2D(d[i], alpha, sx, sy, mirror) except: pass """ nx = d[0].get_xsize() ny = d[0].get_ysize() if options.ou < 1 : radius = nx//2-2 else: radius = options.ou mask = model_circle(radius, nx, ny) if(options.xr < 0): xrng = 0 else: xrng = options.xr if(options.yr < 0): yrng = xrng else: yrng = options.yr initial = max(options.initial, 0) from statistics import mono lend = len(d) lccc = [None]*(lend*(lend-1)/2) from utilities import read_text_row if options.pairwiseccc == None or not os.path.exists(options.pairwiseccc) : st = time() for i in xrange(lend-1): for j in xrange(i+1, lend): # j>i meaning mono entry (i,j) or (j,i) indicates T i->j (from smaller index to larger) #alpha, sx, sy, mir, peak = align2d(d[i],d[j], xrng, yrng, step=options.ts, first_ring=options.ir, last_ring=radius, mode = "F") alpha, sx, sy, mir, peak = align2d_scf(d[i],d[j], xrng, yrng, ou=radius) lccc[mono(i,j)] = [ccc(d[j], rot_shift2D(d[i], alpha, sx, sy, mir, 1.0), mask), alpha, sx, sy, mir] #print " %4d %10.1f"%(i,time()-st) if(not os.path.exists(options.pairwiseccc)): from utilities import write_text_row write_text_row([[initial,0,0,0,0]]+lccc,options.pairwiseccc) elif(os.path.exists(options.pairwiseccc)): lccc = read_text_row(options.pairwiseccc) initial = int(lccc[0][0] + 0.1) del lccc[0] for i in xrange(len(lccc)): T = Transform({"type":"2D","alpha":lccc[i][1],"tx":lccc[i][2],"ty":lccc[i][3],"mirror":int(lccc[i][4]+0.1)}) lccc[i] = [lccc[i][0],T] tdummy = Transform({"type":"2D"}) maxsum = -1.023 for m in xrange(0,lend):#initial, initial+1): indc = range( lend ) lsnake = [[m, tdummy, 0.0]] del indc[m] lsum = 0.0 while len(indc) > 1: maxcit = -111. for i in xrange(len(indc)): cuc = lccc[mono(indc[i], lsnake[-1][0])][0] if cuc > maxcit: maxcit = cuc qi = indc[i] # Here we need transformation from the current to the previous, # meaning indc[i] -> lsnake[-1][0] T = lccc[mono(indc[i], lsnake[-1][0])][1] # If direction is from larger to smaller index, the transformation has to be inverted if( indc[i] > lsnake[-1][0] ): T = T.inverse() lsnake.append([qi,T, maxcit]) lsum += maxcit del indc[indc.index(qi)] T = lccc[mono(indc[-1], lsnake[-1][0])][1] if( indc[-1] > lsnake[-1][0]): T = T.inverse() lsnake.append([indc[-1], T, lccc[mono(indc[-1], lsnake[-1][0])][0]]) print " initial image and lsum ",m,lsum #print lsnake if(lsum > maxsum): maxsum = lsum init = m snake = [lsnake[i] for i in xrange(lend)] print " Initial image selected : ",init,maxsum," ",TotalDistance([snake[m][0] for m in xrange(lend)], lccc) #for q in snake: print q from copy import deepcopy trans=deepcopy([snake[i][1] for i in xrange(len(snake))]) print [snake[i][0] for i in xrange(len(snake))] """ for m in xrange(lend): prms = trans[m].get_params("2D") print " %3d %7.1f %7.1f %7.1f %2d %6.2f"%(snake[m][0], prms["alpha"], prms["tx"], prms["ty"], prms["mirror"], snake[m][2]) """ for k in xrange(lend-2,0,-1): T = snake[k][1] for i in xrange(k+1, lend): trans[i] = T*trans[i] # To add - apply all transformations and do the overall centering. for m in xrange(lend): prms = trans[m].get_params("2D") #print " %3d %7.1f %7.1f %7.1f %2d %6.2f"%(snake[m][0], prms["alpha"], prms["tx"], prms["ty"], prms["mirror"], snake[m][2]) #rot_shift2D(d[snake[m][0]], prms["alpha"], prms["tx"], prms["ty"], prms["mirror"]).write_image(new_stack, m) rot_shift2D(d[snake[m][0]], prms["alpha"], 0.0,0.0, prms["mirror"]).write_image(new_stack, m) order = tsp(lccc) if(len(order) != lend): print " problem with data length" from sys import exit exit() print TotalDistance(order, lccc) print order ibeg = order.index(init) order = [order[(i+ibeg)%lend] for i in xrange(lend)] print TotalDistance(order, lccc) print order snake = [tdummy] for i in xrange(1,lend): # Here we need transformation from the current to the previous, # meaning order[i] -> order[i-1]] T = lccc[mono(order[i], order[i-1])][1] # If direction is from larger to smaller index, the transformation has to be inverted if( order[i] > order[i-1] ): T = T.inverse() snake.append(T) assert(len(snake) == lend) from copy import deepcopy trans = deepcopy(snake) for k in xrange(lend-2,0,-1): T = snake[k] for i in xrange(k+1, lend): trans[i] = T*trans[i] # Try to smooth the angles - complicated, I am afraid one would have to use angles forward and backwards # and find their average?? # In addition, one would have to recenter them """ trms = [] for m in xrange(lend): prms = trans[m].get_params("2D") trms.append([prms["alpha"], prms["mirror"]]) for i in xrange(3): for m in xrange(lend): mb = (m-1)%lend me = (m+1)%lend # angles order mb,m,me # calculate predicted angles mb->m """ for m in xrange(lend): prms = trans[m].get_params("2D") #rot_shift2D(d[order[m]], prms["alpha"], prms["tx"], prms["ty"], prms["mirror"]).write_image("metro.hdf", m) rot_shift2D(d[order[m]], prms["alpha"], 0.0,0.0, prms["mirror"]).write_image(args[2], m) """ # This was an effort to get number of loops, inconclusive, to say the least from numpy import outer, zeros, float32, sqrt lend = len(d) cor = zeros(lend,float32) cor = outer(cor, cor) for i in xrange(lend): cor[i][i] = 1.0 for i in xrange(lend-1): for j in xrange(i+1, lend): cor[i,j] = lccc[mono(i,j)][0] cor[j,i] = cor[i,j] lmbd, eigvec = pca(cor) from utilities import write_text_file nvec=20 print [lmbd[j] for j in xrange(nvec)] print " G" mm = [-1]*lend for i in xrange(lend): # row mi = -1.0e23 for j in xrange(nvec): qt = eigvec[j][i] if(abs(qt)>mi): mi = abs(qt) mm[i] = j for j in xrange(nvec): qt = eigvec[j][i] print round(qt,3), # eigenvector print mm[i] print for j in xrange(nvec): qt = [] for i in xrange(lend): if(mm[i] == j): qt.append(i) if(len(qt)>0): write_text_file(qt,"loop%02d.txt"%j) """ """ print [lmbd[j] for j in xrange(nvec)] print " B" mm = [-1]*lend for i in xrange(lend): # row mi = -1.0e23 for j in xrange(nvec): qt = eigvec[j][i]/sqrt(lmbd[j]) if(abs(qt)>mi): mi = abs(qt) mm[i] = j for j in xrange(nvec): qt = eigvec[j][i]/sqrt(lmbd[j]) print round(qt,3), # eigenvector print mm[i] print """ """ lend=3 cor = zeros(lend,float32) cor = outer(cor, cor) cor[0][0] =136.77 cor[0][1] = 79.15 cor[0][2] = 37.13 cor[1][0] = 79.15 cor[2][0] = 37.13 cor[1][1] = 50.04 cor[1][2] = 21.65 cor[2][1] = 21.65 cor[2][2] = 13.26 lmbd, eigvec = pca(cor) print lmbd print eigvec for i in xrange(lend): # row for j in xrange(lend): print eigvec[j][i], # eigenvector print print " B" for i in xrange(lend): # row for j in xrange(lend): print eigvec[j][i]/sqrt(lmbd[j]), # eigenvector print print " G" for i in xrange(lend): # row for j in xrange(lend): print eigvec[j][i]*sqrt(lmbd[j]), # eigenvector print """ else: nargs = len(args) if nargs != 2: print "must provide name of input and output file!" return from utilities import get_params2D, model_circle from fundamentals import rot_shift2D from statistics import ccc from time import time from alignment import align2d from multi_shc import mult_transform stack = args[0] new_stack = args[1] d = EMData.read_images(stack) try: ttt = d[0].get_attr('xform.params2d') for i in xrange(len(d)): alpha, sx, sy, mirror, scale = get_params2D(d[i]) d[i] = rot_shift2D(d[i], alpha, sx, sy, mirror) except: pass nx = d[0].get_xsize() ny = d[0].get_ysize() if options.radius < 1 : radius = nx//2-2 else: radius = options.radius mask = model_circle(radius, nx, ny) init = options.initial if init > -1 : print " initial image: %d" % init temp = d[init].copy() temp.write_image(new_stack, 0) del d[init] k = 1 lsum = 0.0 while len(d) > 1: maxcit = -111. for i in xrange(len(d)): cuc = ccc(d[i], temp, mask) if cuc > maxcit: maxcit = cuc qi = i # print k, maxcit lsum += maxcit temp = d[qi].copy() del d[qi] temp.write_image(new_stack, k) k += 1 print lsum d[0].write_image(new_stack, k) else: if options.circular : print "Using options.circular" # figure the "best circular" starting image maxsum = -1.023 for m in xrange(len(d)): indc = range(len(d) ) lsnake = [-1]*(len(d)+1) lsnake[0] = m lsnake[-1] = m del indc[m] temp = d[m].copy() lsum = 0.0 direction = +1 k = 1 while len(indc) > 1: maxcit = -111. for i in xrange(len(indc)): cuc = ccc(d[indc[i]], temp, mask) if cuc > maxcit: maxcit = cuc qi = indc[i] lsnake[k] = qi lsum += maxcit del indc[indc.index(qi)] direction = -direction for i in xrange( 1,len(d) ): if( direction > 0 ): if(lsnake[i] == -1): temp = d[lsnake[i-1]].copy() #print " forw ",lsnake[i-1] k = i break else: if(lsnake[len(d) - i] == -1): temp = d[lsnake[len(d) - i +1]].copy() #print " back ",lsnake[len(d) - i +1] k = len(d) - i break lsnake[lsnake.index(-1)] = indc[-1] #print " initial image and lsum ",m,lsum #print lsnake if(lsum > maxsum): maxsum = lsum init = m snake = [lsnake[i] for i in xrange(len(d))] print " Initial image selected : ",init,maxsum print lsnake for m in xrange(len(d)): d[snake[m]].write_image(new_stack, m) else: # figure the "best" starting image maxsum = -1.023 for m in xrange(len(d)): indc = range(len(d) ) lsnake = [m] del indc[m] temp = d[m].copy() lsum = 0.0 while len(indc) > 1: maxcit = -111. for i in xrange(len(indc)): cuc = ccc(d[indc[i]], temp, mask) if cuc > maxcit: maxcit = cuc qi = indc[i] lsnake.append(qi) lsum += maxcit temp = d[qi].copy() del indc[indc.index(qi)] lsnake.append(indc[-1]) #print " initial image and lsum ",m,lsum #print lsnake if(lsum > maxsum): maxsum = lsum init = m snake = [lsnake[i] for i in xrange(len(d))] print " Initial image selected : ",init,maxsum print lsnake for m in xrange(len(d)): d[snake[m]].write_image(new_stack, m)
def main(): import sys import os import math import random import pyemtbx.options import time from random import random, seed, randint from optparse import OptionParser progname = os.path.basename(sys.argv[0]) usage = progname + """ [options] <inputfile> <outputfile> Forms chains of 2D images based on their similarities. Functionality: 4. Order a 2-D stack of image based on pair-wise similarity (computed as a cross-correlation coefficent). Options 1-3 require image stack to be aligned. The program will apply orientation parameters if present in headers. The ways to use the program: 4.1 Use option initial to specify which image will be used as an initial seed to form the chain. sxprocess.py input_stack.hdf output_stack.hdf --initial=23 --radius=25 4.2 If options initial is omitted, the program will determine which image best serves as initial seed to form the chain sxprocess.py input_stack.hdf output_stack.hdf --radius=25 4.3 Use option circular to form a circular chain. sxprocess.py input_stack.hdf output_stack.hdf --circular--radius=25 4.4 New circular code based on pairwise alignments sxprocess.py aclf.hdf chain.hdf circle.hdf --align --radius=25 --xr=2 --pairwiseccc=lcc.txt 4.5 Circular ordering based on pairwise alignments sxprocess.py vols.hdf chain.hdf mask.hdf --dd --radius=25 """ parser = OptionParser(usage,version=SPARXVERSION) parser.add_option("--dd", action="store_true", help="Circular ordering without adjustment of orientations", default=False) parser.add_option("--circular", action="store_true", help="Select circular ordering (first image has to be similar to the last)", default=False) parser.add_option("--align", action="store_true", help="Compute all pairwise alignments and for the table of their similarities find the best chain", default=False) parser.add_option("--initial", type="int", default=-1, help="Specifies which image will be used as an initial seed to form the chain. (default = 0, means the first image)") parser.add_option("--radius", type="int", default=-1, help="Radius of a circular mask for similarity based ordering") # import params for 2D alignment parser.add_option("--ou", type="int", default=-1, help="outer radius for 2D alignment < nx/2-1 (set to the radius of the particle)") parser.add_option("--xr", type="int", default=0, help="range for translation search in x direction, search is +/xr (0)") parser.add_option("--yr", type="int", default=0, help="range for translation search in y direction, search is +/yr (0)") #parser.add_option("--nomirror", action="store_true", default=False, help="Disable checking mirror orientations of images (default False)") parser.add_option("--pairwiseccc", type="string", default= None, help="Input/output pairwise ccc file") (options, args) = parser.parse_args() global_def.BATCH = True if options.dd: nargs = len(args) if nargs != 3: print "must provide name of input and two output files!" return stack = args[0] new_stack = args[1] from utilities import model_circle from statistics import ccc from statistics import mono lend = EMUtil.get_image_count(stack) lccc = [None]*(lend*(lend-1)/2) for i in xrange(lend-1): v1 = get_im( stack, i ) if( i == 0 and nargs == 2): nx = v1.get_xsize() ny = v1.get_ysize() nz = v1.get_ysize() if options.ou < 1 : radius = nx//2-2 else: radius = options.ou mask = model_circle(radius, nx, ny, nz) else: mask = get_im(args[2]) for j in xrange(i+1, lend): lccc[mono(i,j)] = [ccc(v1, get_im( stack, j ), mask), 0] order = tsp(lccc) if(len(order) != lend): print " problem with data length" from sys import exit exit() print "Total sum of cccs :",TotalDistance(order, lccc) print "ordering :",order for i in xrange(lend): get_im(stack, order[i]).write_image( new_stack, i ) elif options.align: nargs = len(args) if nargs != 3: print "must provide name of input and two output files!" return from utilities import get_params2D, model_circle from fundamentals import rot_shift2D from statistics import ccc from time import time from alignment import align2d, align2d_scf from multi_shc import mult_transform stack = args[0] new_stack = args[1] d = EMData.read_images(stack) """ # will align anyway try: ttt = d[0].get_attr('xform.params2d') for i in xrange(len(d)): alpha, sx, sy, mirror, scale = get_params2D(d[i]) d[i] = rot_shift2D(d[i], alpha, sx, sy, mirror) except: pass """ nx = d[0].get_xsize() ny = d[0].get_ysize() if options.ou < 1 : radius = nx//2-2 else: radius = options.ou mask = model_circle(radius, nx, ny) if(options.xr < 0): xrng = 0 else: xrng = options.xr if(options.yr < 0): yrng = xrng else: yrng = options.yr initial = max(options.initial, 0) from statistics import mono lend = len(d) lccc = [None]*(lend*(lend-1)/2) from utilities import read_text_row if options.pairwiseccc == None or not os.path.exists(options.pairwiseccc) : st = time() for i in xrange(lend-1): for j in xrange(i+1, lend): # j>i meaning mono entry (i,j) or (j,i) indicates T i->j (from smaller index to larger) #alpha, sx, sy, mir, peak = align2d(d[i],d[j], xrng, yrng, step=options.ts, first_ring=options.ir, last_ring=radius, mode = "F") alpha, sx, sy, mir, peak = align2d_scf(d[i],d[j], xrng, yrng, ou=radius) lccc[mono(i,j)] = [ccc(d[j], rot_shift2D(d[i], alpha, sx, sy, mir, 1.0), mask), alpha, sx, sy, mir] #print " %4d %10.1f"%(i,time()-st) if(not os.path.exists(options.pairwiseccc)): from utilities import write_text_row write_text_row([[initial,0,0,0,0]]+lccc,options.pairwiseccc) elif(os.path.exists(options.pairwiseccc)): lccc = read_text_row(options.pairwiseccc) initial = int(lccc[0][0] + 0.1) del lccc[0] for i in xrange(len(lccc)): T = Transform({"type":"2D","alpha":lccc[i][1],"tx":lccc[i][2],"ty":lccc[i][3],"mirror":int(lccc[i][4]+0.1)}) lccc[i] = [lccc[i][0],T] tdummy = Transform({"type":"2D"}) maxsum = -1.023 for m in xrange(0,lend):#initial, initial+1): indc = range( lend ) lsnake = [[m, tdummy, 0.0]] del indc[m] lsum = 0.0 while len(indc) > 1: maxcit = -111. for i in xrange(len(indc)): cuc = lccc[mono(indc[i], lsnake[-1][0])][0] if cuc > maxcit: maxcit = cuc qi = indc[i] # Here we need transformation from the current to the previous, # meaning indc[i] -> lsnake[-1][0] T = lccc[mono(indc[i], lsnake[-1][0])][1] # If direction is from larger to smaller index, the transformation has to be inverted if( indc[i] > lsnake[-1][0] ): T = T.inverse() lsnake.append([qi,T, maxcit]) lsum += maxcit del indc[indc.index(qi)] T = lccc[mono(indc[-1], lsnake[-1][0])][1] if( indc[-1] > lsnake[-1][0]): T = T.inverse() lsnake.append([indc[-1], T, lccc[mono(indc[-1], lsnake[-1][0])][0]]) print " initial image and lsum ",m,lsum #print lsnake if(lsum > maxsum): maxsum = lsum init = m snake = [lsnake[i] for i in xrange(lend)] print " Initial image selected : ",init,maxsum," ",TotalDistance([snake[m][0] for m in xrange(lend)], lccc) #for q in snake: print q from copy import deepcopy trans=deepcopy([snake[i][1] for i in xrange(len(snake))]) print [snake[i][0] for i in xrange(len(snake))]