#pragma rtGlobals=1 // Use modern global access method. //Please see accompaning manual for operation and caveats //Copyright (C) 2004-5 Jeremy Bergsman //jeremy@bergsman.org // //These programs are free software; you can redistribute them and/or modify //them under the terms of the GNU General Public License as published by //the Free Software Foundation; either version 2 of the License, or any later version. // //These programs are distributed in the hope that they will be useful, //but WITHOUT ANY WARRANTY; without even the implied warranty of //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //GNU General Public License for more details: //http://www.gnu.org/licenses/gpl.html //or write to the Free Software Foundation, Inc. //59 Temple Place, Suite 330 //Boston, MA 02111-1307 //USA Menu "Macros" "BatchImageProcess" "OneLayerMovie" "LoadOneImage" "LoadAllImagesInFolder" End Menu "Graph" "AppendStimProtocol" End //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////// Batch Image Analysis Panel and associated functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //Designed to batch process any number of sets of any number of image files //Subtracts background, aligns images, segments images //Allows user editing of segment areas and then analysis of these areas against time //Automatic output of analyzed data with facility to map info about output (e.g. "quality") onto input, may animate input //Various parameters depending on your desired processing: Static Constant kThreshSeg=0 //0=Segmentation by iterative thresholding, good for small spots of local maxima with noisier backgrounds //1=Segmentation by single threshold followed by erosion and dilation, good for larger segments which are more clearly seperate from background Static StrConstant ksUserMode="" //"Learn" for quality components output, "" for normal operation, "NoQual" for no quality analysis, "JBB" for JBB-specific output //Version History: //0.1 The beginning! //0.2 Added prefix to experiment names beginning with a digit, various refinements //0.3 Fixed bug in AnalyzeResultWave(s) which mistakenly assumed that result waves were delta=2 //0.4 Ability to define file number range //0.5 Added multiple start sites, global analysis weights, "Auto" keyword for MaxSegLevel, and ColorScale and safer naming scheme on quality segment output //0.6 Reset Experiment List //0.7 Added Wasabi support and generalized a few things to work better with different image intensity ranges //0.71 Generalized number of digits in filenames with constants //0.8 Added Segmentation by threshold and erosion/dilation, fixed various bugs related to processing non JBB images //0.9 Added Max total segs feature //1.0 Ready for publication! Added TIFF support, easier file type control, SD and SEM on averages //1.1 Align steps ("RecLim")=0 now possible for no alignment, analysis can now handle 1 point "baselines", fixed RBF parsing bug and allowed for RBF file format version 1.2, which may be experimental //1.2 Fixed bugs where AnalyzeResultWaves and some other features didn't consider that the first image might not =0, also fixed bug probably introduced in 0.8 where JBB mode didn't use the IPLab timing file Static Constant kImageAnalVersion=1.2 //Only specify 0.1 accuracy here. Smaller version increments don't demand updates. //Features to add: //Possibly the ability to choose which routines are applied and in which order //Better check for saturation //Automated MinLevel determination (based on background?) //Output to quicktime movie //Bleaching correction //Documentation of all output waves //Bugs to fix: //Final Blended wave doesn't contain fluorescence sometimes--unless you adjust intensity by hand during editing? Due to undefined fluomax? //Should turn off reset during manual segment editing (it's already off the first time, but could be a problem if activated during re-runs) Function BatchImageProcess() //Main panel and global variable setup //Version check: if (wintype("ImageAnal")==7) //If window already exists (7=it's a panel) NVAR ImageAnalVersion if (ImageAnalVersion==kImageAnalVersion) //correct version # Dowindow/F ImageAnal //Bring to front and quit return 0 else //different version ImageAnalVersion=kImageAnalVersion //Update value and panel DoWindow/K ImageAnal endif else //Must make panel Variable/G ImageAnalVersion=kImageAnalVersion endif Variable Temp1, Temp2, PanelPos, Top, Right String TempStr Variable/G DoSubFold=0, BGBS=64, BGPoly=3, RecLim=20, AlignThresh=1.001, AlignSteps=1, MasterNumFolders=0 Variable/G MinSegLevel=220, SegMaxPixels=9, SegMinPixels=5, SegmStepSize=0.99, MaxTotalSegs=0//, SegCircularity=0.3 Variable/G ErosIterations=2, DilIterations=1, ErosShape=5, DilShape=1, GaussianWidths=3 Variable/G ESDispSize=3, ESOL=1.03, SaveBgsAl=0, MaxParticleNum=150, MinQuality=0.1, EndOfDestain=32, EarlyDestain=24 Variable/G FirstFileNumber=0, LastFileNumber=-1, Zeros=4, BaseLineStart=0, BaseLineEnd=9, SlopeWeight=5, CVWeight=25, DestainWeight=1 String/G ParentFolderName="D:", SaveFolderName=SpecialDirPath("Temporary", 0, 0, 0), BaseFileName="destain", WaveNamePrefix="", PhaseWaveName="Phase" String/G TimeWaveName="Times.txt", LastFileNumberString="Last", MaxSegLevelString="Auto", MasterExperimentNameList="", ImageType="IPLab", FileExtension="" Make /O/N=0 MasterFirstImageInExperiment, MasterImagesInExperiment TempStr=StringByKey("SCREEN1", IgorInfo(0)) Temp1=StrSearch(TempStr,"RECT",0) Temp1=StrSearch(TempStr,",",Temp1) Temp2=StrSearch(TempStr,",",Temp1+1) Top=Str2Num(TempStr[Temp1+1,Temp2-1]) Temp1=StrSearch(TempStr,",",Temp2+1) Right=Str2Num(TempStr[Temp2+1,Temp1-1]) NewPanel /W=(Right-402,Top+20,Right-20,Top+565) as "Batch Image Loading and Analysis" Dowindow/C ImageAnal PanelPos=10 //Keeps track of Y position to add next control. To shuffle controls just move the whole paragraph to where you want it. GroupBox FILE size={350,220}, pos={5,PanelPos-5}, disable=0, frame=0, title="File Loading and Saving", win=ImageAnal PanelPos+=15 Button SetAP size={100,20}, pos={10,PanelPos-3}, disable=0, proc=SetAnalPath, title="Set Load Location", win=ImageAnal CheckBox SubFold size={80,20}, pos={120,PanelPos}, disable=0, mode=0, noproc, variable=DoSubFold, title="Do Subfolders", win=ImageAnal Button DoMIA Picture=ProcGlobal#ActionArrow, Title="", pos={360,PanelPos}, disable=0, proc=MasterImageAnal, win=ImageAnal PanelPos+=30 TitleBox PFName size={340,20}, pos={10,PanelPos}, disable=0, fsize=8, variable=ParentFolderName, win=ImageAnal PanelPos+=27 SetVariable BaseFN size={140,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=BaseFileName, title="Base Filename", win=ImageAnal PopupMenu Zeros size={100,20}, pos={160,PanelPos-3}, disable=0, noproc, noedit=0, popvalue="# of Incr. Digits", mode=4, value="0;00;000;0000;00000;000000", win=ImageAnal SetVariable Extens size={80,20}, pos={270,PanelPos}, disable=0, noproc, noedit=0, value=FileExtension, title="Extension", win=ImageAnal PanelPos+=30 SetVariable FFN size={90,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=FirstFileNumber, limits={0,500,0}, title="First File", win=ImageAnal SetVariable LFN size={90,20}, pos={110,PanelPos}, disable=0, noproc, noedit=0, value=LastFileNumberString, title="Last File", win=ImageAnal PopupMenu ImgType size={140,20}, pos={210,PanelPos-3}, disable=0, noproc, noedit=0, title="File Type", mode=1, value="IPLab;RBF;TIFF", win=ImageAnal PanelPos+=30 SetVariable TimeN size={166,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=TimeWaveName, title="Time Name", win=ImageAnal SetVariable PhaseN size={166,20}, pos={185,PanelPos}, disable=0, noproc, noedit=0, value=PhaseWaveName, title="Phase Name", win=ImageAnal PanelPos+=30 Button SetSP size={100,20}, pos={10,PanelPos-3}, disable=0, proc=SetSavePath, title="Set Save Location", win=ImageAnal CheckBox SaveBA size={150,20}, pos={200,PanelPos}, disable=0, mode=0, noproc, variable=SaveBgsAl, title="Save Processed Images", win=ImageAnal //SetVariable WNPre size={230,20}, pos={120,PanelPos}, disable=0, noproc, noedit=0, value=WaveNamePrefix, title="Wave/Folder Name Prefix", win=ImageAnal PanelPos+=30 TitleBox SFName size={340,20}, pos={10,PanelPos}, disable=0, fsize=8, variable=SaveFolderName, win=ImageAnal Button ResetList Picture=ProcGlobal#ResetButton, pos={360,PanelPos-20}, disable=1, proc=ResetExperimentList, title="", win=ImageAnal PanelPos+=30 GroupBox BGSub size={350,40}, pos={5,PanelPos-5}, disable=0, frame=0, title="Background Subtraction", win=ImageAnal PanelPos+=15 SetVariable BlkSize size={110,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=BGBS, limits={16,100,20}, title="Block Size", win=ImageAnal SetVariable PolyDeg size={130,20}, pos={160,PanelPos}, disable=0, noproc, noedit=0, value=BGPoly, limits={1,5,1}, title="Polynomial Degree", win=ImageAnal PanelPos+=30 GroupBox ALIG size={350,40}, pos={5,PanelPos-5}, disable=0, frame=0, title="Alignment", win=ImageAnal PanelPos+=15 SetVariable RecLev size={100,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=RecLim, limits={0,50,1}, title="Max Steps", win=ImageAnal SetVariable AlThr size={100,20}, pos={120,PanelPos}, disable=0, noproc, noedit=0, value=AlignThresh, limits={1,1.1,0}, title="Threshold", win=ImageAnal SetVariable AlStep size={100,20}, pos={240,PanelPos}, disable=0, noproc, noedit=0, value=AlignSteps, limits={1,10,1}, title="Step Size", win=ImageAnal PanelPos+=30 GroupBox SegMen size={350,100}, pos={5,PanelPos-5}, disable=0, frame=0, title="Segmentation", win=ImageAnal Button ReSeg Picture=ProcGlobal#ResegmentButton, pos={360,PanelPos+8}, disable=1, proc=ReSegment, title="", win=ImageAnal PanelPos+=15 //Iterative Threshold Mode SetVariable MinLev size={100,20}, pos={10,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=MinSegLevel, limits={0,4096,0}, title="Min Level", win=ImageAnal SetVariable MaxLev size={100,20}, pos={120,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=MaxSegLevelString, limits={0, 4096, 0}, title="Max Level", win=ImageAnal SetVariable SegStep size={100,20}, pos={240,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=SegmStepSize, limits={.9,.999,0}, title="Step Size", win=ImageAnal //Single Threshold Mode SetVariable GaussW size={100,20}, pos={10,PanelPos}, disable=!kThreshSeg, noproc, noedit=0, value=GaussianWidths, limits={1,5,0}, title="Gauss. Widths", win=ImageAnal SetVariable DilIter size={120,20}, pos={120,PanelPos}, disable=!kThreshSeg, noproc, noedit=0, value=DilIterations, limits={1,5,0}, title="Iterations: Dilation", win=ImageAnal SetVariable ErosIter size={80,20}, pos={255,PanelPos}, disable=!kThreshSeg, noproc, noedit=0, value=ErosIterations, limits={1,5,0}, title="Erosion", win=ImageAnal PanelPos+=30 SetVariable MinSiz size={100,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=SegMinPixels, limits={1,1000000,1}, title="Min Size", win=ImageAnal //Iterative Threshold Mode SetVariable MaxSiz size={100,20}, pos={120,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=SegMaxPixels, limits={2,1000000,1}, title="Max Size", win=ImageAnal SetVariable MxPNum size={100,20}, pos={240,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=MaxParticleNum, limits={0,10000,100}, title="Max/Step", win=ImageAnal //SetVariable Circu size={100,20}, pos={240,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=SegCircularity, limits={0,1,.1}, title="Circularity", win=ImageAnal //Single Threshold Mode SetVariable DilShp size={120,20}, pos={120,PanelPos}, disable=!kThreshSeg, noproc, noedit=0, value=DilShape, limits={1,6,1}, title="Shapes: Dilation", win=ImageAnal SetVariable ErosShp size={80,20}, pos={255,PanelPos}, disable=!kThreshSeg, noproc, noedit=0, value=ErosShape, limits={1,6,1}, title="Erosion", win=ImageAnal PanelPos+=30 SetVariable BLSt size={120,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=BaseLineStart, limits={0,100,1}, title="Baseline Start", win=ImageAnal SetVariable BLEn size={75,20}, pos={145,PanelPos}, disable=0, noproc, noedit=0, value=BaseLineEnd, limits={1,100,1}, title="End", win=ImageAnal //Iterative Threshold Mode SetVariable MxTotSeg size={100,20}, pos={240,PanelPos}, disable=kThreshSeg, noproc, noedit=0, value=MaxTotalSegs, limits={0,10000,100}, title="Max Segs", win=ImageAnal PanelPos+=30 GroupBox EdSeg size={350,40}, pos={5,PanelPos-5}, disable=0, frame=0, title="Edit Segments", win=ImageAnal Button DoSeg Picture=ProcGlobal#ActionArrow, Title="", pos={360,PanelPos-2}, disable=1, proc=EditSegmentSetup, win=ImageAnal PanelPos+=15 SetVariable DisSiz size={110,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=ESDispSize, limits={1,8,1}, title="N X N Display", win=ImageAnal SetVariable DisOvrl size={110,20}, pos={160,PanelPos}, disable=0, noproc, noedit=0, value=ESOL, limits={1,1.1,0}, title="Overlap Factor", win=ImageAnal PanelPos+=30 if (cmpstr(ksUserMode,"NoQual" )!=0) GroupBox QuAn size={350,70}, pos={5,PanelPos-5}, disable=0, frame=0, title="Analysis Parameters", win=ImageAnal PanelPos+=15 SetVariable CVWei size={120,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=CVWeight, limits={0,100,0}, title="Weights: CV", win=ImageAnal SetVariable SlpWei size={75,20}, pos={145,PanelPos}, disable=0, noproc, noedit=0, value=SlopeWeight, limits={0,100,0}, title="Slope", win=ImageAnal SetVariable DesWei size={85,20}, pos={235,PanelPos}, disable=0, noproc, noedit=0, value=DestainWeight, limits={0,100,0}, title="Destain", win=ImageAnal Button DoQA Picture=ProcGlobal#ActionArrow, Title="", pos={360,PanelPos-2}, disable=1, proc=NextSeg, win=ImageAnal //This is wrong. This button should call a proc that just recalculates quality for the existing result waves. The resegment button the panel should continue through to the end. And then the lower instance of this button is not required PanelPos+=30 SetVariable Des1 size={110,20}, pos={10,PanelPos}, disable=0, noproc, noedit=0, value=EarlyDestain, limits={0,200,1}, title="Destain Pt. 1", win=ImageAnal SetVariable Des2 size={110,20}, pos={130,PanelPos}, disable=0, noproc, noedit=0, value=EndofDestain, limits={0,200,1}, title="Destain Pt. 2", win=ImageAnal SetVariable MinQual size={100,20}, pos={250,PanelPos}, disable=0, noproc, noedit=0, value=MinQuality, limits={-1,1,0}, title="Min. Quality", win=ImageAnal PanelPos+=30 else GroupBox QuAn size={350,70}, pos={5,PanelPos-5}, disable=0, frame=0, title="Analysis", win=ImageAnal PanelPos+=30 Button DoQA Picture=ProcGlobal#ActionArrow, Title="", pos={360,PanelPos-17}, disable=1, proc=NextSeg, win=ImageAnal DrawText /W=ImageAnal 22, PanelPos, "Automatic Analysis in NoQual Mode" endif if (cmpstr(ksUserMode,"JBB" )==0) //JBB-specific stuff for analysis and display LoadWave/A/H/Q/W/O "C:Documents and Settings:Jeremy:My Documents:science:data:StimTimes.ibw" LoadWave/A/H/Q/W/O "C:Documents and Settings:Jeremy:My Documents:science:data:StimValue.ibw" LoadWave/A/H/Q/W/O "C:Documents and Settings:Jeremy:My Documents:science:data:ImageTimes.ibw" endif End Function SetAnalPath (ctrlName) : ButtonControl String ctrlName SVAR ParentFolderName NewPath/O/Q/M="Please find the folder containing your experiment(s)" ParentFolder if (V_flag==0) //No error, update path PathInfo /S ParentFolder ParentFolderName=S_path ControlUpdate /W=ImageAnal BaseFN endif return 0 End Function SetSavePath (ctrlName) : ButtonControl String ctrlName SVAR SaveFolderName NewPath /C/O/Q/M="Please select root folder for save" BaseSaveFolder if (V_flag==0) //No error, update path PathInfo /S BaseSaveFolder SaveFolderName=S_path ControlUpdate /W=ImageAnal SFName endif return 0 End Function ResetExperimentList(ctrlName) : ButtonControl String ctrlName //If user doesn't press done in segment editor and then loads more experiments there will be a problem. Should kill the panel there. //Need to think about wave name prefix Svar MasterExperimentNameList, ExperimentNameList Nvar MasterNumFolders, NumFolders Wave MasterFirstImageInExperiment, MasterImagesInExperiment Variable Loop1 if (cmpstr(ctrlName,"ELDone")==0) //Do Resetting ControlUpdate /A/W=ResetPanel Wave Checklist NumFolders=0 ExperimentNameList="" Make /O/N=(MasterNumFolders) FirstImageInExperiment, ImagesInExperiment //Note: N may be too large but shouldn't be a problem For (Loop1=0; Loop1< MasterNumFolders; Loop1+=1) if (Checklist[Loop1]&16) //Checked FirstImageInExperiment[NumFolders]=MasterFirstImageInExperiment[Loop1] ImagesInExperiment[NumFolders]=MasterImagesInExperiment[Loop1] NumFolders+=1 ExperimentNameList+=StringFromList(Loop1, MasterExperimentNameList)+";" endif Endfor KillWindow ResetPanel KillWaves /Z CheckList, ExNaWave elseif (cmpstr(ctrlName,"ELClr")==0) Wave Checklist Checklist=32 //Checkboxes, unchecked ControlUpdate /A/W=ResetPanel else //Set up panel Make /O/N=(MasterNumFolders) CheckList CheckList=48 //Checkboxes, checked Make /O/N=(MasterNumFolders)/T ExNaWave For (Loop1=0; Loop1< MasterNumFolders; Loop1+=1) ExNaWave[Loop1]=StringFromList(Loop1, MasterExperimentNameList) Endfor NewPanel /W=(50,50,250,350) as "Reset Experiment List" Dowindow/C ResetPanel ListBox ExpList size={180,250}, pos={10,10}, disable=0, listwave=ExNaWave, selwave=CheckList, mode=4, noproc, win=ResetPanel Button ELDone size={85,20}, pos={10,270}, disable=0, proc=ResetExperimentList, title="Done", win=ResetPanel Button ELClr size={85,20}, pos={105,270}, disable=0, proc=ResetExperimentList, title="Clear", win=ResetPanel endif End Function MasterImageAnal(ctrlName) : ButtonControl String ctrlName //NotUsed //This runs the actual analysis, looping through the right files and applying the right analysis routines Svar BaseFileName, ParentFolderName, WaveNamePrefix, PhaseWaveName, TimeWaveName, SaveFolderName, LastFileNumberString, MasterExperimentNameList, FileExtension Nvar DoSubFold, RecLim, FirstFileNumber, LastFileNumber, BaseLineStart, BaseLineEnd, MasterNumFolders Wave MasterFirstImageInExperiment, MasterImagesInExperiment String CurrentWaveName, ExperimentFolder, Dummy, SaveFolder String /G FolderList, ExperimentPrefix, CurrentFileName, Step, ExperimentName, ExperimentNameList="", ZeroString Variable FolderNum, FileNum, TestFile, TimeFile, Rows, Cols, SlashPos, PanelPos, Success, Loop1, TimeCols, TimeRows, Temp1, TimingLoaded Variable /G NumFolders, MaxLeft, MaxRight, MaxUp, MaxDown, Zeros ControlUpdate /A /W=ImageAnal //Update any field being edited ControlInfo /W=ImageAnal Zeros //Get # of incrementing digits in filename Zeros=V_Value //# of digits ZeroString=S_Value //String with 0's if ((cmpstr(ParentFolderName,"")==0)||(cmpstr(SaveFolderName,"")==0)) //Could check path validity.... DoAlert 0, "Invalid loading and/or saving locations" return -1 endif if ((cmpstr(FileExtension,"")!=0)&&(cmpstr(FileExtension[0],".")!=0)) //make sure any extension starts with a period FileExtension="."+FileExtension endif LastFileNumber=str2num(LastFileNumberString) if (numtype(LastFileNumber)!=0) LastFileNumber=-1 endif //List of folders(=experiments) to analyze if (DoSubFold) FolderList=IndexedDir(ParentFolder,-1,1) //convert to Mac version SlashPos=0 do SlashPos=strsearch(FolderList,"\\",SlashPos) if (SlashPos!=-1) if (CmpStr(FolderList[SlashPos-1],":")==0) FolderList[SlashPos-1,SlashPos]=":" //for :\\ else FolderList[SlashPos]=":" endif endif while (SlashPos!=-1) NumFolders=ItemsInList(FolderList) if (NumFolders==0) print "No subfolders present" return -1 endif else FolderList=ParentFolderName NumFolders=1 endif //Progress panel if (wintype("Progress")!=7) //If panel doesn't exist NewPanel /W=(20,20,200,120) as "Progress" Dowindow/C Progress PanelPos=10 SetVariable Exper size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=ExperimentName, title="Experiment", win=Progress PanelPos+=30 SetVariable FileNm size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=CurrentFileName, title="File", win=Progress PanelPos+=30 SetVariable CurStep size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=Step, title="Step", win=Progress PanelPos+=30 else Dowindow/F Progress endif Make /O /N=(NumFolders) FirstImageInExperiment, ImagesInExperiment //Do each Experiment for (FolderNum=0;FolderNum=0)&&(cmpstr(UpperStr(ExperimentName[0]),"Z")<=0))) ExperimentName="Exp_"+ExperimentName endif ExperimentName=ReplaceString(" ", ExperimentName, "") //Strip out spaces ExperimentPrefix=ExperimentName+"_" ExperimentNameList+=ExperimentName+";" if (CmpStr(WaveNamePrefix,"")!=0) ExperimentPrefix=WaveNamePrefix+"_"+ExperimentPrefix endif SaveFolder+=RemoveEnding(ExperimentPrefix,"_")+":" NewPath /O/Q/C BgsAlSavePath, SaveFolder MaxLeft=0 MaxRight=0 MaxUp=0 MaxDown=0 TimingLoaded=0 FileNum=0 Do //each file Step="Load" //Filename to open CurrentFileName=ZeroString+num2str(FileNum+FirstFileNumber) CurrentFileName=CurrentFileName[strlen(CurrentFileName)-Zeros,strlen(CurrentFileName)-1] CurrentFileName=BaseFileName+CurrentFileName ControlUpdate /A /W=Progress //Test for existence NewPath /O/Q TempPath, ExperimentFolder Open /R/P=TempPath/Z=1 TestFile as CurrentFileName+FileExtension KillPath /Z TempPath if (V_Flag==0) Close TestFile //Open and parse CurrentWaveName=ExperimentPrefix+CurrentFileName Success=LoadAnyImage(CurrentWaveName,ExperimentFolder,CurrentFileName+FileExtension) if (Success==1) Wave CurrentWave=$CurrentWaveName //Background Subtract Step="Subtract background" ControlUpdate /A /W=Progress SubtractBackground(CurrentWaveName) //Misc. stuff that must be done for each experiment: if (FileNum==0) //Find ROI to measure for comparison Rows=DimSize($CurrentWaveName,0)//Using Igor nomenclature,this is the X dimension Cols=DimSize($CurrentWaveName,1)//Y dimension if (RecLim>0) //Will be aligning successive images ImageThreshold /I/M=1/Q $CurrentWaveName Wave M_ImageThresh Duplicate /O M_ImageThresh, AlignROI //Use ROI to limit edges from analysis, currently buggy in not considering step size>1 AlignROI[0,RecLim-1][]=255 AlignROI[Rows-RecLim-1, Rows-1][]=255 AlignROI[][0,RecLim-1]=255 AlignROI[][Cols-RecLim-1, Cols-1]=255 Note CurrentWave, "Left:0;Right:0;Up:0;Down:0;" //Wave to record the alignment shifts: Make /O/N=1/T $("Shifts"+ExperimentName)="" Wave /T ShiftsWave=$("Shifts"+ExperimentName) ShiftsWave[0]="Left:0;Right:0;Up:0;Down:0;" endif //Avg of baseline images Make /N=(Rows,Cols)/O $("FirstImage"+ExperimentName) Wave FirstImage=$("FirstImage"+ExperimentName) FirstImage=0 //Load Phase image Step="Load phase image" ControlUpdate /A /W=Progress LoadAnyImage("Phase"+ExperimentName,ExperimentFolder,PhaseWaveName) else if (RecLim>0) //Alignment Step="Align" ControlUpdate /A /W=Progress //Preshift according to shift of last wave Duplicate /O CurrentWave, ShiftWave String NoteHold=Note(CurrentWave) //Shouldn't be anything there but.... Note /K CurrentWave Wave /T ShiftsWave=$("Shifts"+ExperimentName) String OldShift=ShiftsWave[FileNum-1] //Record of shift of last wave Variable Left=NumberByKey("Left", OldShift) Variable Right=NumberByKey("Right", OldShift) Variable Up=NumberByKey("Up", OldShift) Variable Down=NumberByKey("Down", OldShift) //if (FileNum==35) //For manual correction of giant shifts set this to the first shifted image number // right+=76 //And set the shift here // down+=16 //and here //endif if (Left>Right) Left-=Right Right=0 ShiftWave=CurrentWave[p+Left][q] //Shift Left ShiftWave[Rows-Left,Rows-1][]=NaN //Blank right cols elseif (Right>Left) Right-=Left Left=0 ShiftWave=CurrentWave[p-Right][q] ShiftWave[0,Right-1][]=NaN else Left=0 Right=0 endif CurrentWave=ShiftWave if (Up>Down) Up-=Down Down=0 ShiftWave=CurrentWave[p][q+Up] ShiftWave[][Cols-Up-1,Cols-1]=NaN elseif (Down>Up) Down-=Up Up=0 ShiftWave=CurrentWave[p][q-Down] ShiftWave[][0,Down-1]=NaN else Up=0 Down=0 endif CurrentWave=ShiftWave Note CurrentWave, NoteHold+"Left:"+Num2Str(Left)+";"+"Right:"+Num2Str(Right)+";"+"Up:"+Num2Str(Up)+";"+"Down:"+Num2Str(Down)+";"//must update these now so alignment proc can put correct totals in wave KillWaves ShiftWave //Measure preshifted for reference for further shifting ImageStats /M=1/R=AlignROI $CurrentWaveName AlignImage(CurrentWaveName,1,V_avg) Redimension /N=(FileNum+1) ShiftsWave OldShift=Note(CurrentWave) Left=NumberByKey("Left", OldShift) Right=NumberByKey("Right", OldShift) Up=NumberByKey("Up", OldShift) Down=NumberByKey("Down", OldShift) ShiftsWave[FileNum]="Left:"+Num2Str(Left)+";"+"Right:"+Num2Str(Right)+";"+"Up:"+Num2Str(Up)+";"+"Down:"+Num2Str(Down)+";" MaxLeft=max(Left, MaxLeft) //Save maxima for ROI cropping MaxRight=max(Right, MaxRight) MaxUp=max(Up, MaxUp) MaxDown=max(Down, MaxDown) endif endif //Average baseline images to increase S/N for segmentation if ((FileNum+FirstFileNumber>=BaseLineStart)&&(FileNum+FirstFileNumber<=BaseLineEnd)) MatrixOp /O FirstImage=FirstImage+CurrentWave endif Save/C/P=BgsAlSavePath/O CurrentWave //kill waves when possible to keep things from getting too big! KillWaves $CurrentWaveName //? elseif (Success==0) //File no good //check to see if it's an IPLab timing file NewPath /O/Q TempPath, ExperimentFolder Open /R/P=TempPath/Z=1 TimeFile as CurrentFileName FReadLine TimeFile, Dummy TimeCols=str2num(Dummy) FReadLine TimeFile, Dummy TimeRows=str2num(Dummy) FReadLine TimeFile, Dummy if ((cmpstr(Dummy,"F\r")==0)&&(TimeCols==1)) //I think time files should always be F and 1 //We'll say this is it TimingLoaded=1 make /O/N=(TimeRows) $("ImageTimes"+ExperimentName) Wave LoadedImageTimes=$("ImageTimes"+ExperimentName) FReadLine TimeFile, Dummy //column label, may wish to parse for other units? if (cmpstr(Dummy,"Seconds\t\r")==0) SetScale d 0,0,"s", LoadedImageTimes else SetScale d 0,0,Dummy[0,max(0,strlen(Dummy)-3)], LoadedImageTimes endif for (Loop1=0;Loop1TimeRows) Redimension /N=(FileNum) LoadedImageTimes LoadedImageTimes[TimeRows,FileNum-1]=LoadedImageTimes[TimeRows-1]+2+5*(p-TimeRows) endif Temp1=LoadedImageTimes[BaseLineEnd] LoadedImageTimes-=Temp1 else DeletePoints 0, FirstFileNumber, LoadedImageTimes endif else //No IPLab timing was found in the sequence of files, use x=p generic if (cmpstr(ksUserMode,"JBB" )==0) //unless JBB mode, in which case we've already loaded one Wave ImageTimes Duplicate /O ImageTimes $("ImageTimes"+ExperimentName) DeletePoints 0, FirstFileNumber, $("ImageTimes"+ExperimentName) else Make /O/N=(FileNum) $("ImageTimes"+ExperimentName) Wave ImageTimes=$("ImageTimes"+ExperimentName) ImageTimes=p//+FirstFileNumber //include this if it makes sense to you SetScale x, 0, 1, "s", ImageTimes endif endif //End of time wave stuff KillPath /Z TempPath //Segmentation Step="Segment" ControlUpdate /A /W=Progress Duplicate/o FirstImage $("Segment"+ExperimentName) Wave SegWave=$("Segment"+ExperimentName) Segmentation(SegWave) Duplicate /O SegWave, $("Segment"+ExperimentName+"_temp") //Duplicate segment wave to save for revert function //Other processing features? endif KillPath /Z BgsAlSavePath endfor //FolderNum //Clean up Dowindow/K Progress if (FolderNum>0) //Don't bother if none processed MasterNumFolders+=NumFolders MasterExperimentNameList+=ExperimentNameList KillWaves/Z AlignROI//, M_ImageThresh Button ReSeg disable=0, win=ImageAnal EditSegmentSetup("") endif End //Manual segment editing functions ========================================== //Also includes final analysis due to disorganized programming Function EditSegmentSetup(ctrlName) : ButtonControl String ctrlName//Not Used //Set up various global variables and strings for segment editing window String/G SegName, FIName, PhaseName Nvar MinSegLevel, ESOL Variable /G SegXPos, SegYPos, PhaseOn, FluoOn, SegsOn, FluorMin=MinSegLevel, FluorMax, SegWaveIndex=-1, FlLimitChanged, ESOverlap=ESOL make /O/N=(65536,3) GreenColorIndex GreenColorIndex=0 GreenColorIndex[][1]=74000-74000*exp(-3.3e-05*p) //arbitrarily determined exponential to emphasize lower range SetScale /I x FluorMin, FluorMax, GreenColorIndex//Note that FluorMax is undefined here but it still works NextSeg("EditSegments") Variable/G V_marquee=1+0x8000 //Causes marquee changes to be reflected in variables Variable/G DependencyTarget SetFormula DependencyTarget, "EraseSegment(root:S_marqueeWin)" //Dummy dependency variable to cause marquee updates to call EraseSegment End Function NextSeg(ctrlName) : ButtonControl String ctrlName //Set up window for manual segment editing, called for each experiment //When done, measure segments Svar SegName, FIName, PhaseName, BaseFileName, WaveNamePrefix, ExperimentNameList, SaveFolderName, ExperimentName, MaxSegLevelString, ZeroString Nvar SegXPos, SegYPos, PhaseOn, FluoOn, SegsOn, FluorMin, FluorMax, SegWaveIndex, FlLimitChanged Nvar ESDispSize, DoSubFold, NumFolders, SaveBgsAl, MinQuality, ESOverlap, Zeros Wave GreenColorIndex, ImagesInExperiment, FirstImageInExperiment Variable ButPos, Rows, Cols, XRange, YRange, FolderNum, FileNum, TestFile, ESPosX, ESPosY, PanelPos Variable Xmin, Xmax, Ymin, Ymax, Good, Quality Variable/G segloop=0 String ExperimentPrefix, SaveFolder, ExperimentFolder, CurrentFileName String /G CurrentWaveName, BlendName if (wintype("SegmentWindow")==1) MoveWindow /W=SegmentWindow 1, 1, 1, 1 //Restore window DoWindow /K SegmentWindow endif SegWaveIndex+=1 if ((SegWaveIndex1) Button Move pos={ButPos,5}, size={50, 20}, proc=ToggleDisplay, title="Move", win=SegmentWindow ButPos+=60 endif Button Undo pos={ButPos,5}, size={50, 20}, disable=2, proc=EraseSegment, title="Undo", win=SegmentWindow ButPos+=60 SetVariable FluMin size={100,15}, pos={ButPos,8}, disable=0, proc=FluScale, noedit=0, value=FluorMin, limits={0,65534,10}, title="Fl. Min", labelBack=(65535,65535,65535), win=SegmentWindow ButPos+=110 SetVariable FluMax size={100,15}, pos={ButPos,8}, disable=0, proc=FluScale, noedit=0, value=FluorMax, limits={1,65535,10}, title="Fl. Max", labelBack=(65535,65535,65535), win=SegmentWindow ButPos+=110 Button Done pos={ButPos,5}, size={50, 20}, disable=2*(ESDispSize>1), proc=NextSeg, title="Done", win=SegmentWindow ButPos+=60 Button Revert pos={ButPos,5}, size={50, 20}, disable=0, proc=ToggleDisplay, title="Revert", win=SegmentWindow ButPos+=60 Button SegAgain pos={ButPos,5}, size={50, 20}, disable=0, proc=ToggleDisplay, title="ReSeg", win=SegmentWindow ButPos+=60 else //Done editing segments if (cmpstr(ctrlName,"EditSegments")==0) Nvar DependencyTarget SetFormula DependencyTarget, "" //Kill dependency endif ControlUpdate /A /W=ImageAnal //Update any field being edited ControlInfo /W=ImageAnal Zeros //Get # of incrementing digits in filename Zeros=V_Value //# of digits ZeroString=S_Value //String with 0's //=================================Measure segments================================= //Progress panel if (wintype("Progress")!=7) //If panel doesn't exist NewPanel /W=(20,20,200,120) as "Progress" Dowindow/C Progress PanelPos=10 SetVariable Exper size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=ExperimentName, title="Experiment", win=Progress PanelPos+=30 SetVariable FileNm size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=CurrentWaveName, title="File", win=Progress PanelPos+=30 SetVariable SegNumDis size={140,20}, pos={20,PanelPos}, disable=0, noproc, noedit=1, value=segloop, limits={0,50000,0}, title="Segment #", win=Progress PanelPos+=30 else Dowindow/F Progress DoUpdate endif make /O/N=(256,3) QualityColorIndex //Red below MinQuality, blue above, white in the middle QualityColorIndex=65535 QualityColorIndex[0,127][1,2]=4*p^2 //Red is decreasing steeply towards X=0 QualityColorIndex[129,255][0,1]=4*(255-p)^2 //Blue is increasing steeply above 0 SetScale /I x (Max(MinQuality,-.63)-.5)*100, (Max(MinQuality,-.63)+.5)*100, QualityColorIndex //Range of 1 quality units (*100 scale factor in qualtiy map) centered on MinQuality, must not go below -128 //Also need to prevent values over +128 //May fail with weighting schemata that require MinQuality much different from 0 //Do each Experiment for (FolderNum=0;FolderNumMinQuality) Good+=1 GoodAvg+=ResWave/str2num(StringByKey("\rBaseLine",note(ResWave),"=",";")) GoodSD+=(ResWave/str2num(StringByKey("\rBaseLine",note(ResWave),"=",";")))^2 endif if (cmpstr(ksUserMode,"Learn" )==0) Display ResWave vs $("ImageTimes"+StringFromList(FolderNum, ExperimentNameList)) Nvar SaveCV, SaveISlope, SaveDest TextBox/C/N=QualComp/F=0/B=1 "CV="+num2str(SaveCV)+" Slope="+num2str(SaveISlope)+" Destain="+num2str(SaveDest)+" Quality="+num2str(Quality) endif else //No quality criterion, just average all waves Good+=1 GoodAvg+=ResWave/str2num(StringByKey("\rBaseLine",note(ResWave),"=",";")) GoodSD+=(ResWave/str2num(StringByKey("\rBaseLine",note(ResWave),"=",";")))^2 endif KillWaves SeedFilled endif endfor KillWaves CurrentWave else print "Missing file #", FileNum print "Tried to open as", CurrentFileName endif endfor GoodSD=sqrt((Good*GoodSD-GoodAvg^2)/(Good*(Good-1))) //Because at this moment GoodSD is the sum of the squares and GoodAvg is the sum GoodAvg/=Good GoodSEM/=GoodSD/sqrt(Good) if (cmpstr(ksUserMode,"NoQual" )!=0) Note GoodAvg, "MinQual="+num2str(MinQuality)+"; Kept="+num2str(Good)+"; Total="+num2str(V_NumParticles)+"; Percent="+num2str(Good/V_NumParticles*100)+";" //Display of segment quality PhaseName="Phase"+StringFromList(FolderNum, ExperimentNameList) //A blend of the phase and fluor are on the bottom: if ((!exists("Blended"+StringFromList(FolderNum, ExperimentNameList)))||FlLimitChanged) myblend($PhaseName, $FIName, "Blended"+StringFromList(FolderNum, ExperimentNameList), FluorMin, FluorMax, 2, 1) endif if (cmpstr(RemoveEnding(WinList("QualityMap"+RemoveEnding(ExperimentPrefix,"_"),";",""),";"),"")==0) //Check to see if this quality map doesn't already exist NewImage /N=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $("Blended"+StringFromList(FolderNum, ExperimentNameList)) //This stuff is useless unless buttons are added: // //Next comes the phase image which will obscure the blend when it's on: // AppendImage/L/T /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(PhaseName) // ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(PhaseName) explicit=1 //Make phase invisible // ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(PhaseName) eval={255,-1,0,0}, eval={0,-1,0,0} //Defeat default explicit settings so it's invisible in explicit=1 // //Then comes the fluor. which will obscure the blend, doesn't need to obscure the phase because they are not on together, that's what the blend is for // AppendImage/L/T /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(FIName) // ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(FIName) cindex=GreenColorIndex //Map fluor to green when explicit=0 // ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(FIName) explicit=1 //Make fluor invisible // ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $(FIName) eval={255,-1,0,0}, eval={0,-1,0,0} //Defeat default explicit settings so it's invisible in explicit=1 //Finally QualSeg. This layer is transparent outside of the segments so it is a true overlay AppendImage/L/T /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $("QualitySegment"+StringFromList(FolderNum, ExperimentNameList)) ModifyImage /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) $("QualitySegment"+StringFromList(FolderNum, ExperimentNameList)) cindex= QualityColorIndex, minRGB=NaN, maxRGB=0 // ColorScale /C/N=ColorSc /F=0 /A=RT /X=100.00 /Y=0.00 /B=1 /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) width=6, height=80, fsize=8, image=$("QualitySegment"+StringFromList(FolderNum, ExperimentNameList)) //Would be better to draw boxes: //SetDrawEnv xcoord= top,ycoord= left, fillpat= 0 //For each segment: //SetDrawEnv linefgc= ( 65535*min(normalized_quality,0)*-1, 0, 65535*max(normalized_quality,0) ) //Or something--check RedWhiteBlue color table //For each segment pixel pixel: //DrawRect PixelX-.5,PixelY-.5,PixelX+.5,PixelY+.5 //Could make button procs work on top window on faith to easily activate the following: // ModifyGraph /W=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) margin(top)=33 // ButPos=10 // Button Phase pos={ButPos,5}, size={50, 20}, proc=ToggleDisplay, title="Phase", win=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) // ButPos+=60 // Button Fluo pos={ButPos,5}, size={50, 20}, proc=ToggleDisplay, title="Fluor.", win=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) // ButPos+=60 // Button Segs pos={ButPos,5}, size={50, 20}, proc=ToggleDisplay, title="Segs", win=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) // ButPos+=60 // SetVariable FluMin size={100,15}, pos={ButPos,8}, disable=0, proc=FluScale, noedit=0, value=FluorMin, limits={0,65534,10}, title="Fl. Min", labelBack=(65535,65535,65535), win=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) // ButPos+=110 // SetVariable FluMax size={100,15}, pos={ButPos,8}, disable=0, proc=FluScale, noedit=0, value=FluorMax, limits={1,65535,10}, title="Fl. Max", labelBack=(65535,65535,65535), win=$("QualityMap"+RemoveEnding(ExperimentPrefix,"_")) // ButPos+=110 endif else Note GoodAvg, "NumAveraged="+num2str(Good) endif Display $("GoodAvg"+RemoveEnding(ExperimentPrefix,"_")) vs $("ImageTimes"+StringFromList(FolderNum, ExperimentNameList)) as "Average"+RemoveEnding(ExperimentPrefix,"_") if (cmpstr(ksUserMode,"JBB" )==0) AppendToGraph/R StimValue vs StimTimes ModifyGraph axisEnab(left)={0,0.87}, axisEnab(right)={0.9,1}, tick(right)=3, axThick(right)=0, noLabel(right)=2 ModifyGraph mode(StimValue)=6 endif ModifyGraph rgb=(0,0,0),mode($("GoodAvg"+RemoveEnding(ExperimentPrefix,"_")))=4,marker($("GoodAvg"+RemoveEnding(ExperimentPrefix,"_")))=19 ErrorBars $("GoodAvg"+RemoveEnding(ExperimentPrefix,"_")),Y Wave=($("GoodSD"+RemoveEnding(ExperimentPrefix,"_")),$("GoodSD"+RemoveEnding(ExperimentPrefix,"_"))) if (!SaveBgsAl) DeleteFolder /P=BgsAlSavePath /Z=1 if ((V_flag==1088)&&(FolderNum==0)) print "Can't delete subtracted, aligned images" print "You must enable DeleteFolder (in Misc|Miscellaneous Settings|Miscellaneous)" endif endif KillPath /Z BgsAlSavePath endfor DoUpdate //Must erase old windows to allow wave deletion? KillWaves /Z M_Particle, W_ImageObjArea, W_ImageObjPerimeter, W_circularity, W_rectangularity, W_SpotX, W_SpotY, W_xmin, W_xmax, W_ymin, W_ymax KillWaves /Z ESPosTracker, M_SeedFill, M_ImageThresh, M_rawmoments, M_moments, OneSeg, InvSegWave, SegZoom, Blended, GreenColorIndex, UndoWave KillVariables /Z SegLoop, V_marquee, DependencyTarget, SegXPos, SegYPos, PhaseOn, FluoOn, SegsOn, FluorMin, FluorMax, SegWaveIndex, FlLimitChanged, GoodSquared KillStrings /Z CurrentWaveName, BlendName, LAIImageName Dowindow/K Progress Button DoSeg disable=0, win=ImageAnal Button ResetList disable=0, win=ImageAnal Button ReSeg disable=0, win=ImageAnal Button DoQA disable=0, win=ImageAnal if (cmpstr(ksUserMode,"JBB" )==0) QualVsIntensity() endif endif End Function FluScale(ctrlName,varNum,varStr,varName) : SetVariableControl //Adjust x scale of GreenColorIndex String ctrlName Variable varNum // value of variable as number String varStr // value of variable as string String varName // name of variable Nvar FluorMin, FluorMax, FlLimitChanged Svar FIName if (FluorMin>=FluorMax) if (cmpstr(ctrlName,"FluMin")==0) FluorMin=FluorMax-1 else FluorMax=FluorMin+1 endif endif SetScale /I x FluorMin, FluorMax, GreenColorIndex FlLimitChanged=1 //keeps track of when you need to reblend End Function ToggleDisplay(ctrlName) : ButtonControl //Respond to various buttons in the segment editing window String ctrlName //which button called Variable Rows, Cols, XRange, YRange, DisTop, DisLeft Svar SegName, FIName, PhaseName, BlendName Nvar FluorMin, FluorMax, PhaseOn, FluoOn, SegsOn, FlLimitChanged Nvar SegXPos, SegYPos, ESDispSize, ESOverlap strswitch(ctrlName) case "Segs": //Toggle the segment image in segment editing window if (SegsOn==1) SegsOn=0 ModifyImage /W=SegmentWindow $(SegName) eval={1,-1,0,0} //Make Segments clear else SegsOn=1 ModifyImage /W=SegmentWindow $(SegName) eval={1,65535,0,0} //Make Segments Red endif return 0 case "Move": //Move to next region if (SegXPos1.1) Destain=0 endif Quality=Destain+InitSlope-CV if (cmpstr(ksUserMode,"Learn" )==0) Variable/G SaveCV=CV/CVWeight, SaveISlope=InitSlope/SlopeWeight, SaveDest=Destain/DestainWeight endif Note ResWave, "Quality="+num2str(Quality)+";" endif Note ResWave, "BaseLine="+num2str(Normalizer)+";" KillWaves /Z W_coef, W_sigma Return Quality End /////////////////////////////////////////////////// END of Batch Image Analysis Panel and associated functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////// Individual Image Processing Routines \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //These are written with an attempt to enable standalone use as well as calls by the Image Analysis routines above Function SubtractBackground(SBWaveName) String SBWaveName Variable Rows, Cols, RowCnt, ColCnt, Xsteps, Ysteps, XInt, YInt, BGBlockSize=NumVarOrDefault("BGBS",32), PolyLevel=NumVarOrDefault("BGPoly",3) Wave SBWave=$SBWaveName Rows=DimSize(SBWave,0) //Using Igor nomenclature, this is the X dimension Cols=DimSize(SBWave,1) //Y dimension Make /b/u/O/N=(Rows,Cols) SubWave=0 //background ROIs for BG subtraction Xsteps=Trunc(Rows/BGBlockSize) Ysteps=Trunc(Cols/BGBlockSize) for (RowCnt=0;RowCntInten) Direction=1 Inten=V_avg BestStep=Step endif //Right ShiftWave=AlignWave[p-Step][q] ShiftWave[0,Step-1][]=NaN ImageStats /M=1/R=AlignROI ShiftWave if (V_avg>Inten) Direction=2 Inten=V_avg BestStep=Step endif //Up ShiftWave=AlignWave[p][q+Step] ShiftWave[][Cols-Step-1,Cols-1]=NaN ImageStats /M=1/R=AlignROI ShiftWave if (V_avg>Inten) Direction=3 Inten=V_avg BestStep=Step endif //Down ShiftWave=AlignWave[p][q-Step] ShiftWave[][0,Step-1]=NaN ImageStats /M=1/R=AlignROI ShiftWave if (V_avg>Inten) Direction=4 Inten=V_avg BestStep=Step endif Endfor //Shift according to Direction and BestStep: //Retrieve existing shift info String NoteHold=Note(AlignWave) Note /K AlignWave Variable Left, Right, Up, Down Left=NumberByKey("Left", NoteHold) Right=NumberByKey("Right", NoteHold) Up=NumberByKey("Up", NoteHold) Down=NumberByKey("Down", NoteHold) NoteHold=NoteHold[0,StrSearch(NoteHold, "Left:", 0)-1] switch (Direction) case 0: //Already at the best position Note AlignWave, NoteHold+"Left:"+Num2Str(Left)+";"+"Right:"+Num2Str(Right)+";"+"Up:"+Num2Str(Up)+";"+"Down:"+Num2Str(Down)+";" KillWaves ShiftWave Return 1 case 1: ShiftWave=AlignWave[p+BestStep][q] //Shift Left ShiftWave[Rows-BestStep,Rows-1][]=NaN //Blank right cols Left+=BestStep break case 2: ShiftWave=AlignWave[p-BestStep][q] ShiftWave[0,BestStep-1][]=NaN Right+=BestStep break case 3: ShiftWave=AlignWave[p][q+BestStep] ShiftWave[][Cols-BestStep-1,Cols-1]=NaN Up+=BestStep break case 4: ShiftWave=AlignWave[p][q-BestStep] ShiftWave[][0,BestStep-1]=NaN Down+=BestStep break endswitch AlignWave=ShiftWave Note AlignWave, NoteHold+"Left:"+Num2Str(Left)+";"+"Right:"+Num2Str(Right)+";"+"Up:"+Num2Str(Up)+";"+"Down:"+Num2Str(Down)+";" KillWaves ShiftWave //See if neighbor of neighbor might be better if (RecLevelMaxParticleNum) print "Maximum segments per step limit reached. Segmentation stopped at", CurrentThreshold break endif Wave M_Particle //16 for object area, 18 for the object boundaries and 64(=NaN) for all other points MatrixOp /O AllSegs=AllSegs+(SixtyFour-M_Particle) //AllSegs will be 0 where no segments, and some number >0 where there are segments, doing it this way for speed if (MaxTotalSegs>0) ImageThreshold /I/M=0/T=1/Q AllSegs // /I means over threshold=0, under=255, needed for ImageAnalyzeParticles ImageAnalyzeParticles /A=(SegMinPixels) /M=3 /MAXA=(SegMaxPixels) /R=NoEdges /Q stats M_Imagethresh if (V_NumParticles>MaxTotalSegs) print "Maximum total segments limit reached. Segmentation stopped at", CurrentThreshold break endif endif if (CurrentThreshold*(1-SegmStepSize)<1) CurrentThreshold-=1 else CurrentThreshold*=SegmStepSize endif Step="Segment @ "+ num2str(CurrentThreshold) ControlUpdate /A /W=Progress while (CurrentThreshold>MinSegLevel) ImageThreshold /I/M=0/T=1/Q AllSegs // /I means over threshold=0, under=255, needed for ImageAnalyzeParticles ImageAnalyzeParticles /A=(SegMinPixels) /M=3 /MAXA=(SegMaxPixels) /R=NoEdges /Q stats M_Imagethresh // /F still not working //Retest for max, as well as min, size //Circularity test would be nice. Perhaps mean squared distance of pixels from center? This might allow use of larger area limits SegmWave=0 MatrixOp /O SegmWave=(SegmWave||(SixtyFour-M_Particle)) //The OR converts the 16s and 18s to 1. The 0s stay 0. endif KillWaves/Z M_ImageThresh, M_Particle, AllSegs, SixtyFour, NoEdges, SegmHistogram, fit_SegmHistogram, W_Coef End function myblend(BottomImage, TopImage, BlendedWaveName, TILL, TIHL,TIScale, TIColor) wave BottomImage, TopImage //Waves to overlay string BlendedWaveName //Name of output wave //The variables below are not used in the special purpose version since the color map takes care of that variable TILL, TIHL //Low and High limit of values to use in top image (good to use a LL to reduce background) variable TIScale //Adjusts the relative intensity of top image. Bottom image will be /B/U, i.e. 0-255, so if top image has a greater range this factor should be increased variable TIColor //Top image color, 0=Red, 1=Green, 2=Blue //Make RGB copy of BottomImage in gray ColorTab2Wave Grays Wave M_colors ImageStats /M=1/Q BottomImage SetScale /I x V_min, V_max, M_colors //Might wish to parameterize these limits to control BottomImage display, or use colormaps as parameters imagetransform /C=M_colors cmap2rgb BottomImage //Move it to output wave Wave M_RGBOut Duplicate /O M_RGBOut $BlendedWaveName Wave Blended=$BlendedWaveName //Make RGB copy of TopImage and combine imagetransform /C=GreenColorIndex cmap2rgb TopImage //This command relies on a given color map; remove it and the one below for general purpose use Blended=min(Blended+M_RGBOut,255) // Blended[][][TIColor]=min((Blended[p][q][TIColor]+min(max(((TopImage[p][q])-TILL),0),TIHL-TILL)/TIScale),255) //Clean up KillWaves M_colors, M_RGBOut End ////////////////////////////////////////////// END of Individual Image Processing Routines \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////// Generic image loading functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ Macro LoadOneImage(ImageWaveName) //For allowing user to load an image without supplying all the arguments in the command line String ImageWaveName Prompt ImageWaveName, "Name for image" LoadAnyImage(ImageWaveName,"","") End Function LoadAllImagesInFolder() //For allowing user to find the folder //Just call LAIIF directly when path is known in advance LAIIF("") End Function LAIIF(PathString) //Load all images in a disk folder using LoadAnyImage //Uses file names for wave names String PathString Variable NumImages, Loop1 String ImageList if (cmpstr(PathString,"")==0)//Get path from user NewPath /O/Q LAILoadPath PathInfo LAILoadPath PathString=S_path endif ImageList=IndexedFile(LAILoadPath, -1,"????") KillPath /Z LAILoadPath NumImages=ItemsInList(ImageList) for (Loop1=0;Loop1X9[kl:\`)0A;LFAm*iFE_ /6AH5#,Ddm9#8SqmKAQ!)JA9i1:ANTqm!+8Vs<(/)Z-1LEnmHs<'k2t"9cfs]YrVc]ioCMbPq#>kps #`CT&.nlth4UF6E,]bm:f+C#Ykn4m?smCBUnlr,i/j%^rtcLO=BPU=^jprcj5]/b5X<-#_#FB7!!!$ !s8U"`i?\I(!$HA]:/h2ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr?;/)smV*"=-Q,5u`*_@Z Zr>B95IbdZX1lo$Z=76JU#[+>FRAh#-a6!!1"\0?5`,!r0:eq;d3*KQuV?p_^O::rGc`jl?FDLk,S? ,(ksWZFHEp]WVm)j1cI1dD$qa8sNh3f!f:+f@F=:d79;"t7J>cRL4eO3fL.%hLukc!\ ==a+p`6$tR>1dD_KKQk:Z;!sB0/ZTLIhT.nMTgG',$B9qP-fdmRD5]Ft5Gs8`))7XQmFNsC#E4_qI! XM@R^Dqtp\D8o2@a(o-RfNSH!H&:lh[C?jj^lCc`M=?E2?O'n`+E>$8[&P.%#*]HR$q0GTqMo,5[_i ujMWRp^jo60/g`)!L9MRI`ZuiV`=0+S$>M@^!.cuEOs2Sk_#k+E'a2$sL;5Z>5lf9`9FsDj";"D9W1 9A'fQn]dQtE",A];0hJ0k8uL'8DJM(l9AJoie7XHj%r+J<=<3FKF2!F%'%$.TFnAMKjQAJ*#t)UXKT G>$'\";&Z-^pFEr&&\n)E6XpD+?'BWO9O7[$Im$%dk!-]&3rM*!l1$0e0kPo,RDY(+NqUHL1t7c@Kk Kne-Sl]P0s=2"L8o0T7NHAJU1anjWU2I@O)S3%]IVP!&OX)IYE6,)JSn+K3Nb!Q9 MORQrb=+f-MoBF&;sDl+2l\ X@SDjhPEZ:X+I(5bJ5ir?R`/.))mIkc30OOP+OkW?k:G-"J.$1u4M#-D49G]tMIp1N&ep%i=>[?NC2 %C4!(+.46_QWPdQnP1!`tW7!!.bQ),a8)Bbn`lL&hDgWb-_(_G4DG]m`GHD1DUqO:slr+CUM+i`HVB e?RF%!Q;e"+HH_[^]c/:OCjU76Pj7j#7)FV@,sqT!,cbPM^eod%bM6o'ljR7#'k_!!rtsp)LH;X*/s pu!!#SZ:.26O@"J ASCII85End End // PNG: width= 60, height= 43 Picture ResetButton ASCII85Begin M,6r;%14!\!!!!.8Ou6I!!!!]!!!!L#Qk&,!#+lA@fQK/"D:"p5l^nga>X9[kl:\`)0A;LFAm*iFE_ /6AH5#,Ddm9#8SqmKAQ!)JA9i1:ANTqm!0C#N<(5'Vc2U$o&.fEQJ:RY2&CAeNi8EP]mdAWUeY&S.Y ct@RaiRpu?m$R7hVR,hnF07N:sm\<0JG3\d*V:OnGg;>qtp9/`5M\;ORr)8k2tgcio9t\+SYX)s.H$ HOHBM#i;ZVME,]dr0JNN7@/mI8lK[Zfg"HCEE.EIh]Y(mB5X<-#_#FB7!!!$!s8Ulm5KNm*!&/Lm:/ h2ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr?N)d!,Nj"0b?b5u`*_ @aN^Ci711!gA4(-c%IXd";9257T%/NTW\k;5RdL8!r=<1M+LoCNsA+0;dW>'_jU01D:+Fk:O[K(l?T"_WSRf@n!+e!Nb@R-Jf&=,4>!$MD ;%nSS,5\7H;KRl0,bn-AP!W#8#I1J"hrRV!S5AoS$BT)f!!)IUAI%Z;`'<.TG!L`0Z)n;%/!$kP\.6 itTe9PAu%!S"30-3f?=6+ENf!XOoNFYKSJ5T\M]#U#LH?o2Yo.9$:>9/1e$Peq)SW`=7_T9mqNlK%R0"VpDE!'NJNCQ1]_%U.(>.0Y @SJnI,soLggXW7+%M6b`.Q:BIOARBQsm5"pc>>IR`B-W+KU/b(bi=!)kc\gs5s$6rD>>&4!HN.Bfk5 &^MASMATJ/Ss_l&!sB1:oE8_s*jica<:7o&MLioU*Oq^B!XKQL]\:"bVu\6=b:(9LJf8$K=r^^2%'p foJDaQC,?KG*M&AIV5Zr^?*mXfeKIF`kGYmF'!gG!r=jV!9fA_E1Hu4B6Jd.U(!3dRY6Luu]95:-q) (A3nC'+SM;P>ao&M8qmkb0T1Y9f27D1DV\.%UG@#a$DjH-l[e:7mqW=,%Sm1ES<-_UCD.!23Gu4BSU coX(_(Y;*Bb!XP)K&3 rVfQk%\&$m:'K$>k:n@Ls);(Z`tRik_jPX9[kl:\`)0A;LFAm*iFE_ /6AH5#,Ddm9#8SqmKAQ!)JA9i1:ANTqm!+8Vs<(6jq2s,`?&j5[qj_#FB7!!!$ !s8S/AeKb+p!$HA]:/h2ms8W-!s8W-!s8W-!s8W-!s8W-!s8W-!s8W-!rr?;/)smV*#5h%\5u`*_@Z Y6\O[B/.r:9C[k[J"'`+7p0!f0.6O\ndV)$nEB1%:ooM9*epnhS@\MX_#R":t[MS>\P"&7OYZAO$ph i=TZi(Ln-[#Ts5L17WEN)IQ;oY@_`\BQ]i*#+sqpp,Us$15R\2i==EY].?oMf4sV js-t!(6!<`s&RK3HqWgSWtLJa(o&OeJt+!6[t',-78(*J\C+g;eK!&;:f+tUb\K;'4h,\=MH;)A@UK /_)*qRb@,'"P*Er4bg%\tcjUIN:sE7X5S*I\3h'=bk[?bVB/?am4j4+O2F%6c!Xu0&$T5` 8qRKH*%'1P@@,q:h#c=#V?Xdfl#j,q-)&WXc"Ml\.aXMli`k ]mDbRPEk#U$'X!Cf)2jX:Ie[Xp&#&Hg_oZ5b=u&3s(:]\k%ZMPAWgSePa+QN"3(p'$`c,6C,peEJnaB,ifTA`6Ij<)c,U+sCP6:("r:fbB^!M<";!u--nl G='.6#M66TJtDIDIg5SdjrAn(ff:709+!k-\<8_o"]>k.u>1jo"]>k%8"P>!F.4"]_n%";1b-!)Z]4!!Ej%K `OF=;,eA4";""U!C-WN2)F/=%/B<-"on\BJ6CoBCB\)^!sg$RAf4u^,Jk[a@P]C9Y2SD./V]XDFU^% 3iALc@&4j-pS;8#.4A3af8ta3\1E/$DOlI<%J3]PljLBHq(jU@gUP_j5Rno?,:CoOd=JZm#blTeJ;u m+582H;HY\IeS3^=Zf1U(U1!]g<1Og%@YX*/YoAAb,K+FkT'`PprWAV:p]O>T[&a\$PF1,1"hk264T 6`_gmB*/8J82D'`/L5sFa:2nm+_=4L=Bc&C+@#pX1p\rHC)19qeBH3iVAUM,TP5>H:f8,X"JDPEAdE oI)^'Z=/H[[lc'$jiJ=8S<^]:5L+Fm9lJ2/M[0q8\k!Q(?9&4"=*)$M]O1L\\T!n.Ph5Y,Tn">*]+F -[pRL);F'a&0QLb2=l]7C.9]^^j=tb"pc= sB/;:u?oXX48I35e/F_^,&3rbe-B),_6/0TrQiREc1I(q;jC`uCU*u-(";#VE'U?^4SjN"8aV.]XaT 2MUbg4^B>VbMsSId_=-b:-V!s:>a$m:(^l=W+c6<'N`R1E\E&!.nlrJG<7I[Dp#S1HVV/ !rZiL46VHK:E7gr\0,WD=u(#^&&3Yn)"5QJWp8qrs.S,k3F3$n?q37,U23ES9!nI,so'NK5T! CTfU":---1]mjl;VL7JB#$slJs)Ki0,lDm56D$"P+T;3C^(i/Ai$4n%'pfoJ.S8ie1)6^q*qJqTq-* i'akR<.":=!ib&QKIYO+5!!.a`1QT%.L-hQK]6gDOUcXsJ,k2qDNKGYhRc&\13i6l.ELQM!XN*L J=S8:J5R57S^#95P+TS9AqkC@!!3FpT6W[r3Rl2W#h3tW7'57t6+&4!]Q+5_+9k:f@Kr,8YiI873Ih *=&A^,t`@-[*UkLhQ`Qno'5RdRp1(uB]`[K,j5/>1Z_o9fNjqpQrJ,j&?BB8/E+0oBaA4."Cj5C_\j [Bhmj:qh(+9m)q@:"o/63\%/_*Xg\"OP);c#\C8!rs_a&Wku/lsp(r!!#SZ:.26O@"J ASCII85End End /////////////////////////////////////////////////////////////// END of Associated Functions \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////