//This is useful to correct for z- and xy- drift across timepoints. //Uses turboreg plugin to align a hyperstack in z and/or in xy. //The alignment is based on a max projection of the xz reslice for //the z-alignment, and a regular xy max projection for xy alignment //Currently only can use one of the channels to align. //This will not align the slices of a particular individual time point, //for that use Align Z forEachTimePoint title=getTitle(); IID=getImageID(); getVoxelSize(px,py,pz,unit); getDimensions(w,h,chs,sls,frms); substack="1-"+sls; bits=bitDepth(); if(bits!=24)textLuts=getTextLUTs(); setPasteMode("Copy"); Zname=title + "-Zalign"; if(sls<2 && frms< 2) exit("Requires hyperstack with multi z and frames"); if(bits==24){ charray=newArray("all","red","green","blue"); }else{ charray=newArray(chs); for(i=0;i0 && nResults%frms==0) ptarray=true; mchoices=newArray("Use Results locations (pt array)","Auto"); mdefault=mchoices[1]; if(ptarray)mdefault=mchoices[0]; Dialog.create("Choices"); Dialog.addChoice("Mode", mchoices, mdefault); Dialog.addCheckbox("Z-align?",true); Dialog.addCheckbox("XY-align?",true); Dialog.addCheckbox("New stack?", false); Dialog.addMessage("Just for Auto:"); Dialog.addString("Substack (for xy z-proj):", substack); Dialog.addCheckbox("Set selections?",false); Dialog.addCheckbox("Check z-changes before accepting?",false); Dialog.addChoice("Ch:", charray, "2"); if(!ptarray)Dialog.addMessage("Pt array requires one or a set of points to be measured for each time point"); Dialog.show(); mode=Dialog.getChoice(); doz=Dialog.getCheckbox; doxy=Dialog.getCheckbox; newstack=Dialog.getCheckbox(); substack=Dialog.getString(); selec=Dialog.getCheckbox(); autoaccept=!Dialog.getCheckbox(); chchoice=Dialog.getChoice(); startsub=1; endsub=sls; if(substack!="") { if(indexOf(substack,"-")==-1){ startsub=round(substack); endsub=round(substack); } else { substa=split(substack,"-"); startsub=parseInt(substa[0]); endsub=parseInt(substa[1]); } if(startsub>endsub) {tempsub=startsub; startsub=endsub; endsub=tempsub;} } chcrgb=""; if(chs==1) {chcrgb=chchoice; chchoice="1"; if(chcrgb=="red") rgbc=3; else if(chcrgb=="green") rgbc=5; else if(chcrgb=="blue") rgbc=6;} chchoice=parseInt(chchoice); if(mode=="Use Results locations (pt array)" && !ptarray) exit("Pt array requires one or a set of points to be measured for each time point"); if(mode=="Auto") ptarray=false; else ptarray=true; //setBatchMode(true); //setBatchMode("exit and display"); z=newArray(frms); x=newArray(frms); y=newArray(frms); r=newArray(frms); accepted=true; if(ptarray){ rsn=nResults/frms; xinits=newArray(rsn); yinits=newArray(rsn); zinits=newArray(rsn); isxz=false; if(rsn==2){isxz=getBoolean("XZ then XY data?");} if(isxz){ for(i=0;i1) zinits[n]=parseFloat(getResult("Slice",n)); }else{ x[i]+=(parseFloat(getResult("X",i*rsn+n))/px)-xinits[n]; y[i]+=(parseFloat(getResult("Y",i*rsn+n))/py)-yinits[n]; if(sls>1) z[i]+=(parseFloat(getResult("Slice",i*rsn+n)))-zinits[n]; } } x[i]/=rsn; y[i]/=rsn; if(sls>1) z[i]/=rsn; r[i]=0; //not coded (yet) } } } zaccepted=false; if(doz){ if(!ptarray){ z[0]=0; ctot=0; dytot=0; dxtot=0; if(selec)waitForUser("Place selection for reslice now (currently only xz reslice)"); for(i=0; islicesmin+z[k]+noslices-1)){ setSlice(n+1+i+(j*chs)+(k*chs*sls)); run("Delete Slice"); n--; } } } } run("Stack to Hyperstack...", "order=xyczt(default) channels="+chs+" slices="+noslices+" frames="+frms+" display=Composite"); mdata=""+z[0]; for(i=1;i0){ selectWindow("frm"+(i+1)); makeRectangle(x[i],y[i],w,h); run("Crop"); torb="Bottom"; rorl="Right"; if(x[i]>0) rorl="Left"; if(y[i]>0) torb="Top"; run("Canvas Size...", "width="+w+" height="+h+" position="+torb+"-"+rorl+" zero"); if(abs(r[i])>0.5)run("Rotate... ", "angle="+r[i]+" grid=0 interpolation=None"); } concatstr=concatstr+" image"+(i+1)+"=frm"+(i+1); } concatstr=concatstr+" image"+(i+1)+"=[-- None --]"; run("Concatenate...", concatstr); selectWindow(XYname); run("Stack to Hyperstack...", "order=xyczt(default) channels="+chs+" slices="+sls+" frames="+frms+" display=Composite"); if(zaccepted){selectWindow(Zname); close;} else if(newstack){selectWindow(Zname); close;} if(bits!=24)setTextLuts(textLuts); } } //if(doxy && stilldo) print("XYZ Registration completed"); wait(100); showProgress(0.5); showProgress(1.0); function getRegData(){ sourceX0 = getResult("sourceX", 0); // First line of the table. sourceY0 = getResult("sourceY", 0); targetX0 = getResult("targetX", 0); targetY0 = getResult("targetY", 0); dx1 = sourceX0 - targetX0; dy1 = sourceY0 - targetY0; //print("\\Update:Translation [pixel]: " + dx1 +" in X and "+dy1+" in Y"); //translation = sqrt(dx1 * dx1 + dy1 * dy1); // Amount of translation, in pixel units. if(nResults>1){ sourceX1 = getResult("sourceX", 1); // Second line of the table. sourceY1 = getResult("sourceY", 1); targetX1 = getResult("targetX", 1); targetY1 = getResult("targetY", 1); sourceX2 = getResult("sourceX", 2); // Third line of the table. sourceY2 = getResult("sourceY", 2); targetX2 = getResult("targetX", 2); targetY2 = getResult("targetY", 2); dx = sourceX2 - sourceX1; dy = sourceY2 - sourceY1; sourceAngle = atan2(dy, dx); dx = targetX2 - targetX1; dy = targetY2 - targetY1; targetAngle = atan2(dy, dx); rotation = targetAngle - sourceAngle; // Amount of rotation, in radian units. //print("Amount of rotation [degree]: " + (rotation * 180.0 / PI)); rotangle=(rotation * 180.0 / PI); return newArray(dx1, dy1, rotangle); } else return newArray(dx1,dy1); } function addArray(item, array){ temparray=newArray(array.length+1); for(i=0; i