;+ ; NAME: RYTRACK ; ; PURPOSE: ; rytrack provides a front-end GUI for popular particle tracking routines. ; It provides a simple slider-bar interface to set and preview image filters ; prior to launching full batch processing for particle id and frame-to-frame tracking. ; ; CATEGORY: ; Features (id and tracking) ; ; CALLING SEQUENCE: ; rytrack ; ; INPUTS: (Once the GUI has been called ...) ; ; 1) Image directory: The path to the image sequence files of interest. ; Windows example: C:/myfolder/*.tif ; UNIX example: ~/myfolder/*.tif ; (Note: The program can accept tif, jpg, or bmp formats, among others.) ; ; start: begins a frame-by-frame display. The original image is shown in the top display ; and the filtered image in the bottom display. Once started, the image processing ; can be changed on the fly, and the results of these changes will become evident ; in the bottom image. ; ; ; 2) Image PROCESSING parameters: ; (For "Sliders", use either the mouse OR the keyboard arrow keys to modify values) ; ; bandpass1: Specifies the low-end limit of a bandpass filter to be applied to the image ; (i.e., this is the lengthscale, in pixels, of "noise" in the image) ; ; bandpass2: Specifies the high-end of the bandpass filter to be applied to the image ; -> Must be an *_ODD-valued_* integer, ; and should be set to a length, in pixels, somewhat larger than ; a typical particle. ; ; Sobel Smoothing: applies to the image an edge-enhancing operation, namely: ; sobel(smooth(sobel(image))) ; ; Invert image: reverses the grayscale from black to white ; ; ; 3) Particle IDENTIFICATION parameters (to be applied in finding candidate particles ; within each PROCESSED, or "filtered," image) ; ; Threshold: applies a threshold and discards pixels that do not meet the criteria ; ; Particle Radius: the approximate size of the particle you wish to observe ; ; Particle Spacing: how far apart particles are. Default should be particle radius + 1 ; ; Eccentricity: this filters the output from feature.pro, based upon particle shape ; ***NOTE: Here, the slider values are a percentage, and therefore range from ; zero (for circularly symmetric features) to 100 (for very elongated images). ; ***Note: If the ">" button is checked, the only features retained will be those ; with an eccentricity greater than or equal to the slider value. ; ; Radius of Gyration: this filters the output from feature.pro based upon the ; SQUARE of the radius of gyration (in pixels). Think about this one! ; ; Overlay Original: this overlays the original image (top display) with marks indicating ; the centroids of the "candidate" particles, allowing the user to assess the ; accuracy of the particle identifications, and to adjust the i.d. parameters ; "on the fly" until an acceptable match is found. ; ; Overlay Filtered: this overlays the filtered image (bottom display) with the ; "candidate" particles. ; ; 4) Frame-to-Frame TRACKING Sliders: (Parameters that will later be applied in associating ; identified particles with their unique trajectories) ; ; Maximum: the maximum step, in pixels, that can be made in a given trajectory ; from one frame to the next. ; ; Good enough: the minimum number of frames that a trajectory must contain in order to be ; considered valid. ; (This eliminates false tracks due to blinking noise in the images.) ; ; steps Memory: the number of contiguous frames in which a particle can be unrecognized ; and still be considered the same particle. This ensures if a particle moves ; slightly out of focus and does not generate a feature for a few frames, ; it may still be tracked. ; ; ; 5) Finishing up: Once all of the above parameters have been set to acceptable values, ; there are three ways to finish: ; ; ID and Track: clicking this option immediately closes the GUI, and ; begins making individual .gdf files which store the feature data for each image, then ; makes a COMBINED .gdf file, called 'pretrackoutput.gdf' which adds a "framenumber" to ; the feature data for each frame and contains the aggregate feature data for ALL frames, ; and, finally, uses the frame-to-frame tracking parameters set above to create ; trackoutput.gdf ; ; Just Track: this bypasses the step of writing to disk each individual .gdf file to store ; the feature data for each image. This can be used if you have already generated these ; files and you would like to simply change the tracking parameters without changing the ; filtering or particle identification parameters. ; ; Close: this simply closes the GUI, without output. ; ; OPTIONAL INPUTS (KEYWORD PARAMETERS, which can be abbreviated ; filesin: a string array of filepaths to the image files to be evaluated. This keyword ; replaces the input from the filesdirectory textbox and eliminates the need to search ; an entire directory for files. This allows the end user to track specific image files. ; OUTPUTS; ; imagename.gdf for each individual image containing features data from that image ; ; pretrackoutput.gdf which is the organized array from rspretrack ; This can be used directly as input for track.pro, should there be a need to ; change the tracking parameters without changing the filtering or particle id ; parameters. ; ; trackoutput.gdf which is the array output from track.pro ; This array has 7 columns: ; 1) x-position ; 2) y-position ; 3) integrated intensity ; 4) square of radius of gyration ; 5) eccentricity ; 6) frame number ; 7) trajectory number ; ; trackplusvels.gdf which is essentially trackoutput.gdf with 3 additional columns ; which show the x velocity, y velocity, and number of frames jumped. Note that some rows ; are dropped due to the fact that the velocity is calculated by the difference of the ; neighboring frame. ; 1) x-position ; 2) y-position ; 3) integrated intensity ; 4) square of radius of gyration ; 5) eccentricity ; 6) frame number ; 7) trajectory number ; 8) x velocity ; 9) y velocity ; 10) jumped frames ; ; params.txt which lists the filtering, i.d., and tracking parameters used. ; ; RESTRICTIONS: ; If you click the button "Just Track" then the program will overwrite the parameters for ; filtering, particle identification, and tracking that were stored in the params.txt file. ; Thus, it is a good idea to BACKUP the params.txt file! In this way, you can avoid having ; to spend time re-running your successful image filtering and particle identification ; routines whenever you need to make an adjustment to the parameters used for the final ; step, which is linking together the particle positions from each frame to form ; trajectories. ; ; OPTIONAL KEYWORDS: ; ; ; MODIFICATION HISTORY: ; Written by: Ryan Smith of Gabe Spalding's lab at Illinois Wesleyan University, June 1st 2005. ; (Based on code from John C. Crocker, Gabe Spalding and Wolfgang Losert) ; 07/05 RS modified source in order to offer user feedback inside the GUI making it possible ; to output as a .sav file for IDL VM use. In addition, the additional added keyword filesin ; allows users to specify a list of image files to evaluate as opposed to searching an entire ; directory ; 09/05 RS modified source code to fix a minor bug with single feature output ; 12/05 RS modified source code to fix yet another bug with single feature output ;- PRO rytrack_event, ev WIDGET_CONTROL, ev.ID, GET_UVALUE=uval widget_control, ev.top, get_uvalue=infoptr info= *infoptr IF (TAG_NAMES(ev, /STRUCTURE_NAME) EQ 'WIDGET_TIMER') THEN BEGIN widget_control, info.less_gyr, get_value=less_gyr widget_control, info.greater_gyr, get_value=greater_gyr i=info.imagenum widget_control, info.filesdirectory, get_value=filesdirectory ;cd, filesdirectory if (info.filesin[0] eq String(-1)) then begin files=file_search(filesdirectory,count=nf) endif else begin files = info.filesin sizeoffiles = size(files) nf = sizeoffiles[1] endelse if (nf eq 0) then begin message,'no image found' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No Images Found', /APPEND endif if (i Eq nf) then begin info.imagenum=0 i=0 end ;display original images a=read_image(files(i)) adims = size(a) if (adims[0] ne 2) then begin a = reform(a[0,*,*]) endif ;obtain filter information and apply filters widget_control, info.bpass1, get_value=bpass1 widget_control, info.bpass2, get_value=bpass2 widget_control, info.rysobel, get_value=rysobel widget_control, info.thresh, get_value=thresh if (info.shouldiinvert eq 'yes') then begin f = 255b - a ;print, 'you inverted' endif else begin f = a endelse if (rysobel eq 0) then b=f else begin b = smooth(sobel(smooth(f,3)),rysobel) ; print, 'you smoothed' end if (bpass1 eq 0 and bpass2 eq 0) then c=b else begin ;print, bpass1 ;print, bpass2 c = bpass(b,bpass1,bpass2) ; print, 'you bandpassed with:' ; print, bpass1 ; print, bpass2 end if (thresh eq 0) then d=c else begin d = (c gt thresh) * c ; print, 'you threshed' end if (info.firstimage eq 'yes' or info.secondimage eq 'yes') then begin widget_control, info.partrad, get_value=theradius widget_control, info.partspace, get_value=thespacing widget_control, info.masscut, get_value=masscut ;print, masscut ; print, info.use_field ; print, masscut if (info.use_field eq 'yes') then begin feat = feature(d,theradius,thespacing,masscut=masscut,/field) endif else begin feat = feature(d,theradius,thespacing, masscut=masscut) endelse featlength = n_elements(feat) featsize = size(feat, /Dimensions) if (n_elements(featsize) eq 1) then begin elementcount=1 endif else begin elementcount=featsize[1] endelse print, String(elementcount) + " elements found" WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount)+ ' elements found', /APPEND if (info.use_gyr eq 'greater') then begin widget_control, info.gyr, get_value=slid_gyr index = where(feat[3,*] ge slid_gyr) if index[0] eq -1 then begin print, 'No features would be retained. Decrease radius of gyration value. Keeping all features' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No features would be retained. Decrease radius of gyration value. Keeping all features', /APPEND endif else begin feat = feat[*,index] endelse endif if (info.use_gyr eq 'less') then begin widget_control, info.gyr, get_value=slid_gyr index = where(feat[3,*] le slid_gyr) if index[0] eq -1 then begin print, 'No features would be retained. Increase radius of gyration value. Keeping all features' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No features would be retained. Increase radius of gyration value. Keeping all features', /APPEND endif else begin feat = feat[*,index] endelse endif if (info.use_ecc eq 'greater') then begin widget_control, info.eccent, get_value=slid_ecc index = where(feat[4,*] ge float(slid_ecc)/100) if index[0] eq -1 then begin print, 'No features would be retained. Decrease eccentricity value. Keeping all features' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No features would be retained. Decrease eccentricity value. Keeping all features', /APPEND endif else begin feat = feat[*,index] endelse endif if (info.use_ecc eq 'less') then begin widget_control, info.eccent, get_value=slid_ecc index = where(feat[4,*] le float(slid_ecc)/100) if index[0] eq -1 then begin print, 'No features would be retained. Increase eccentricity value. Keeping all features' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No features would be retained. Increase eccentricity value. Keeping all features', /APPEND endif else begin feat = feat[*,index] endelse endif featlength = n_elements(feat) featsize = size(feat, /Dimensions) if (n_elements(featsize) eq 1) then begin elementcount=1 endif else begin elementcount=featsize[1] endelse print, String(elementcount) + " elements retained" WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount)+ ' elements retained', /APPEND ;write_tiff, 'C:\Documents and Settings\GRAHAM\Desktop\ryan\data\gabeimages\outputimage.tif', d ;print, theradius ;print, thespacing WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 if (featlength eq 0) then begin ;print, 'no features to overlay' end firstwindow = info.window1 wset, firstwindow if (info.firstimage eq 'yes' and featlength ne 0) then begin sendtofoverlay = bytscl(a) foverlay, sendtofoverlay, feat, psym=2 endif else begin tvimage, bytscl(a) ;print, 'you dont want to featureoverlay 1' endelse secondwindow = info.window2 wset, secondwindow if (info.secondimage eq 'yes' and featlength ne 0) then begin sendtofoverlay = bytscl(d) foverlay, sendtofoverlay, feat, psym=2 endif else begin ;print, 'you dont want to featureoverlay 2' tvimage, bytscl(d) endelse endif else begin firstwindow = info.window1 wset, firstwindow tvimage, bytscl(a) secondwindow = info.window2 wset, secondwindow tvimage, bytscl(d) ;print, 'you dont want to feature overlay either' endelse ;increment counter info.imagenum = info.imagenum + 1 ;print, info.status if (info.status ne 'stopdisplay') then begin WIDGET_CONTROL, ev.TOP, TIMER=2 endif ENDIF ;check and see if it is inputting the pointer and if not see what widget is being changed if (not ptr_valid(uval)) then begin CASE uval OF 'start' : BEGIN WIDGET_CONTROL, ev.TOP, TIMER=2 info.status='You be trackin' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'You have started displaying your images', /APPEND print, 'You have started displaying your image sequence' END 'ubertrack' : begin widget_control, info.filesdirectory, get_value=outfilesdirectory widget_control, info.bpass1, get_value=outbpass1 widget_control, info.bpass2, get_value=outbpass2 widget_control, info.rysobel, get_value=outrysobel widget_control, info.thresh, get_value=outthresh widget_control, info.partrad, get_value=outpartrad widget_control, info.partspace, get_value=outpartspace widget_control, info.invertim, get_value=outshouldiinvert widget_control, info.maxdisplace, get_value=outmaxdisplace widget_control, info.goodenough, get_value=outgoodenough widget_control, info.rymemory, get_value=ryvar widget_control, info.gyr, get_value=slid_gyr widget_control, info.eccent, get_value=slid_ecc widget_control, info.masscut, get_value=masscut use_field = info.use_field use_gyr = info.use_gyr use_ecc = info.use_ecc newarray = {filesdirectory:outfilesdirectory,bpass1:outbpass1,bpass2:outbpass2,$ rysobel:outrysobel,thresh:outthresh,partrad:outpartrad,partspace:outpartspace,$ shouldiinvert:info.shouldiinvert,wannatrack:'justuber',goodenough:outgoodenough,maxdisplace:outmaxdisplace, $ memorysteps:ryvar,use_gyr:use_gyr,use_ecc:use_ecc,slid_gyr:slid_gyr,slid_ecc:slid_ecc,use_field:use_field,$ masscut:masscut,status:'stopdisplay'} ;*infoptr = previewoutput ;info = previewoutput info.status = 'stopdisplay' *infoptr=info info.wannatrack ='uber' ;WIDGET_CONTROL, ev.TOP, /DESTROY ;xmanager, 'rytrack', tlb, /no_block WIDGET_CONTROL, info.textwindow, SET_VALUE = 'Tracking has started', /APPEND if (info.filesin[0] eq String(-1)) then begin splitfilename = str_sep(newarray.filesdirectory,'*') endif else begin files = info.filesin splitfilename = file_dirname(files[1], /mark) endelse istherepretrack = file_search(splitfilename[0]+'pretrackoutput.gdf', count=thereispretrack) isthereoutput = file_search(splitfilename[0]+'trackoutput.gdf', count=thereisoutput) istherevels = file_search(splitfilename[0]+'trackplusvels.gdf', count=therearevels) if (thereispretrack ne 0) then begin file_delete, splitfilename[0]+'pretrackoutput.gdf' end if (thereisoutput ne 0) then begin file_delete, splitfilename[0]+'trackoutput.gdf' end if (therearevels ne 0) then begin file_delete, splitfilename[0]+'trackplusvels.gdf' end if (info.filesin[0] eq String(-1)) then begin thefiles = file_search(splitfilename[0]+'*.gdf',count=nf) endif else begin tempfiles = info.filesin tempfilesdims = size(tempfiles) ;print, tempfilesdims cur_dir = file_dirname(files[0], /mark) cur_file = file_basename(tempfiles[0]) extension = str_sep(cur_file[0], '.') thefiles = cur_dir + extension[0] + extension[1] + '.gdf' ;print, thefiles ;print, cur_dir + extension[0] + extension[1] + '.gdf' for i=1, tempfilesdims[1]-1 do begin cur_dir = file_dirname(files[i], /mark) cur_file = file_basename(files[i]) extension = str_sep(cur_file[0], '.') tempadd = cur_dir + extension[0] + extension[1] + '.gdf' thefiles = [[thefiles], [tempadd]] endfor endelse ;print, thefiles filesdims = size(thefiles) ;print, filesdims if (filesdims[0] eq 0) then begin WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No tracking gdf files found. Ensure you have run Feature and Track prior to Just Track', /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 endif else begin posns = rspretrack(thefiles) if (newarray.use_gyr eq 'greater') then begin index = where(posns[3,*] ge newarray.slid_gyr) posns = posns[*,index] ;print, newarray.slid_gyr ;print, 'gyr greater' endif if (newarray.use_gyr eq 'less') then begin index = where(posns[3,*] le newarray.slid_gyr) posns = posns[*,index] ;print, newarray.slid_gyr ;print, 'gyr less' endif if (newarray.use_ecc eq 'greater') then begin index = where(posns[4,*] ge float(newarray.slid_ecc)/100) posns = posns[*,index] endif if (newarray.use_ecc eq'less') then begin index = where(posns[4,*] le float(newarray.slid_ecc)/100) posns = posns[*,index] endif write_gdf, posns, splitfilename[0]+'pretrackoutput.gdf' theresult = track(posns, newarray.maxdisplace, memory=newarray.memorysteps, $ goodenough=newarray.goodenough, verbose='yes') write_gdf,theresult,splitfilename[0]+'trackoutput.gdf' print, 'trackoutput.gdf has been written' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'trackoutput.gdf has been written', /APPEND write_text,theresult,splitfilename[0]+'trackoutput.dat' print, 'trackoutput.dat has been written' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'trackoutput.dat has been written', /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 ryaddvel2, splitfilename[0] paramsarray = [['Files Directory',String(newarray.filesdirectory)],['Bandpass 1',String(newarray.bpass1)], $ ['Bandpass2',String(newarray.bpass2)],['Sobel Smoothing',String(newarray.rysobel)],['Threshhold',String(newarray.thresh)],$ ['Particle Radius',String(newarray.partrad)],['Particle Spacing',String(newarray.partspace)],['Invert Image',String(newarray.shouldiinvert)],$ ['Good Enough', String(newarray.goodenough)],['Maximum Displacement', String(newarray.maxdisplace)],$ ['Steps Memory',String(newarray.memorysteps)],['Filter Gyration',String(newarray.use_gyr)],$ ['Gyration Value',String(newarray.slid_gyr)],['Filter Eccentricity',String(newarray.use_ecc)],['Eccentricity Value',String(newarray.slid_ecc)],$ ['Use Field',String(newarray.use_field)],['Mass Cut',String(newarray.masscut)]] ;print, paramsarray write_text, paramsarray, splitfilename[0]+'params.txt' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'params.txt has been written', /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 WIDGET_CONTROL, info.textwindow, SET_VALUE = 'Tracking is complete. If you are finished, click Close.', /APPEND ;print, 'trackplusvels.gdf has been written' WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 endelse end 'close' : WIDGET_CONTROL, ev.TOP, /DESTROY 'overlayoriginal': begin if (info.firstimage eq 'no') then info.firstimage='yes' else info.firstimage='no' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'Overlay Original has been toggled', /APPEND end 'overlayfiltered': begin if (info.secondimage eq 'no') then info.secondimage='yes' else info.secondimage='no' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'Overlay Filtered has been toggled', /APPEND end 'invertimage': begin if (info.shouldiinvert eq 'no') then info.shouldiinvert='yes' else info.shouldiinvert='no' end 'greater_gyr': begin info.use_gyr = 'greater' end 'less_gyr': begin info.use_gyr = 'less' end 'greater_ecc': begin info.use_ecc = 'greater' end 'less_ecc': begin info.use_ecc = 'less' end 'field': begin if (info.field eq 'no') then info.field='yes' else info.field='no' end 'track' : begin widget_control, info.filesdirectory, get_value=outfilesdirectory widget_control, info.bpass1, get_value=outbpass1 widget_control, info.bpass2, get_value=outbpass2 widget_control, info.rysobel, get_value=outrysobel widget_control, info.thresh, get_value=outthresh widget_control, info.partrad, get_value=outpartrad widget_control, info.partspace, get_value=outpartspace widget_control, info.invertim, get_value=outshouldiinvert widget_control, info.maxdisplace, get_value=outmaxdisplace widget_control, info.goodenough, get_value=outgoodenough widget_control, info.rymemory, get_value=ryvar widget_control, info.gyr, get_value=slid_gyr widget_control, info.eccent, get_value=slid_ecc widget_control, info.masscut, get_value=masscut use_field = info.use_field use_gyr = info.use_gyr use_ecc = info.use_ecc newarray = {filesdirectory:outfilesdirectory,bpass1:outbpass1,bpass2:outbpass2,$ rysobel:outrysobel,thresh:outthresh,partrad:outpartrad,partspace:outpartspace,$ shouldiinvert:info.shouldiinvert,wannatrack:'yes',goodenough:outgoodenough,maxdisplace:outmaxdisplace, $ memorysteps:ryvar,use_gyr:use_gyr,use_ecc:use_ecc,slid_gyr:slid_gyr,slid_ecc:slid_ecc,use_field:use_field,$ masscut:masscut} info.wannatrack = 'yes'; ; widget_control, info.filesdirectory, get_value=filesdirectory ; info.fileholder = filesdirectory ; *infoptr=previewoutput ; widget_control, ev.top, /destroy ;xmanager, 'rytrack', tlb, /no_block info.status = 'stopdisplay' *infoptr=info WIDGET_CONTROL, info.textwindow, SET_VALUE = 'Feature and Track has started', /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 if (info.filesin[0] eq String(-1)) then begin thefiles = file_search(newarray.filesdirectory,count=nf) splitfilename = str_sep(newarray.filesdirectory,'*') endif else begin thefiles = info.filesin splitfilename = file_dirname(thefiles[0], /mark) thefilessize = size(thefiles) nf = thefilessize[1] endelse if (nf eq 0) then begin message, 'no images found' WIDGET_CONTROL, info.textwindow, SET_VALUE = 'No images found', /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 end for i=0, nf-1 do begin o=read_image(thefiles(i)) odims = size(o) if (odims[0] ne 2) then begin o = reform(o[0,*,*]) endif if (newarray.shouldiinvert eq 'yes') then begin f = 255b - o ; print, 'you inverted' endif else begin f = o endelse if (newarray.rysobel eq 0) then b=f else begin b = smooth(sobel(smooth(f,3)),newarray.rysobel) ; print, 'you sobelled' endelse if (newarray.bpass1 eq 0 and newarray.bpass2 eq 0) then c=b else begin c = bpass(b,newarray.bpass1,newarray.bpass2) ; print, 'you bpassed with settings of: ' ;print, newarray.bpass1 ;print, newarray.bpass2 endelse if (newarray.thresh eq 0) then d=c else begin d = (c gt newarray.thresh) * c ;print, 'you threshed' endelse if (newarray.use_field eq 'yes') then begin feat = feature(d,newarray.partrad,newarray.partspace,masscut=newarray.masscut, /field) featlength = n_elements(feat) featsize = size(feat, /Dimensions) WIDGET_CONTROL, info.textwindow, SET_VALUE = thefiles(i), /APPEND WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount) + " features identified", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 endif else begin feat = feature(d,newarray.partrad,newarray.partspace,masscut=newarray.masscut) featlength = n_elements(feat) featsize = size(feat, /Dimensions) featsizedims = size(featsize, /Dimensions) if (n_elements(featsize) eq 1) then begin elementcount=1 endif else begin elementcount=featsize[1] endelse if (featsizedims ne 1) then begin WIDGET_CONTROL, info.textwindow, SET_VALUE = thefiles(i), /APPEND WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount) + " features identified", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 endif else begin WIDGET_CONTROL, info.textwindow, SET_VALUE = thefiles(i), /APPEND WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount) + " features identified", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 endelse endelse part=str_sep(thefiles(i),'.') ;splitdirectory=str_sep(thefiles(i),'*') write_gdf,feat,part[0]+part[1]+'.gdf' message,part[0]+part[1]+'.gdf',/inf end print, 'Combining and sending to track' WIDGET_CONTROL, info.textwindow, SET_VALUE = "Combining and sending to track", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 splitfilename = file_dirname(thefiles[0], /mark) istherepretrack = file_search(splitfilename[0]+'pretrackoutput.gdf', count=thereispretrack) isthereoutput = file_search(splitfilename[0]+'trackoutput.gdf', count=thereisoutput) istherevels = file_search(splitfilename[0]+'trackplusvels.gdf', count=therearevels) if (thereispretrack ne 0) then begin file_delete, splitfilename[0]+'pretrackoutput.gdf' end if (thereisoutput ne 0) then begin file_delete, splitfilename[0]+'trackoutput.gdf' end if (therearevels ne 0) then begin file_delete, splitfilename[0]+'trackplusvels.gdf' end if (info.filesin[0] eq String(-1)) then begin thefiles = file_search(splitfilename[0]+'*.gdf',count=nf) endif else begin tempfiles = info.filesin tempfilesdims = size(tempfiles) ;print, tempfilesdims cur_dir = file_dirname(tempfiles[0], /mark) cur_file = file_basename(tempfiles[0]) extension = str_sep(cur_file[0], '.') thefiles = cur_dir + extension[0] + extension[1] + '.gdf' ;print, thefiles ;print, cur_dir + extension[0] + extension[1] + '.gdf' for i=1, tempfilesdims[1]-1 do begin cur_dir = file_dirname(tempfiles[i], /mark) cur_file = file_basename(tempfiles[i]) extension = str_sep(cur_file[0], '.') tempadd = cur_dir + extension[0] + extension[1] + '.gdf' thefiles = [[thefiles], [tempadd]] endfor endelse ;print, thefiles[0] posns = rspretrack(thefiles) if (newarray.use_gyr eq 'greater') then begin index = where(posns[3,*] ge newarray.slid_gyr) posns = posns[*,index] endif if (newarray.use_gyr eq 'less') then begin index = where(posns[3,*] le newarray.slid_gyr) posns = posns[*,index] endif if (newarray.use_ecc eq 'greater') then begin index = where(posns[4,*] ge float(newarray.slid_ecc)/100) posns = posns[*,index] endif if (newarray.use_ecc eq 'less') then begin index = where(posns[4,*] le float(newarray.slid_ecc)/100) posns = posns[*,index] endif write_gdf, posns, splitfilename[0]+'pretrackoutput.gdf' theresult = track(posns, newarray.maxdisplace, memory=newarray.memorysteps, $ goodenough=newarray.goodenough, verbose='yes') write_gdf,theresult,splitfilename[0]+'trackoutput.gdf' print, 'trackoutput.gdf has been written' WIDGET_CONTROL, info.textwindow, SET_VALUE = String(elementcount) + "trackoutput.gdf has been written", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 write_text,theresult,splitfilename[0]+'trackoutput.dat' WIDGET_CONTROL, info.textwindow, SET_VALUE = "trackoutput.dat has been written", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 print, 'trackoutput.dat has been written' ryaddvel2, splitfilename[0] ;print, 'trackplusvels.gdf has been written' paramsarray = [['Files Directory',String(newarray.filesdirectory)],['Bandpass 1',String(newarray.bpass1)], $ ['Bandpass2',String(newarray.bpass2)],['Sobel Smoothing',String(newarray.rysobel)],['Threshhold',String(newarray.thresh)],$ ['Particle Radius',String(newarray.partrad)],['Particle Spacing',String(newarray.partspace)],['Invert Image',String(newarray.shouldiinvert)],$ ['Good Enough', String(newarray.goodenough)],['Maximum Displacement', String(newarray.maxdisplace)],$ ['Steps Memory',String(newarray.memorysteps)],['Filter Gyration',String(newarray.use_gyr)],$ ['Gyration Value',String(newarray.slid_gyr)],['Filter Eccentricity',String(newarray.use_ecc)],['Eccentricity Value',String(newarray.slid_ecc)],$ ['Use Field',String(newarray.use_field)],['Mass Cut',String(newarray.masscut)]] ;print, paramsarray write_text, paramsarray, splitfilename[0]+'params.txt' WIDGET_CONTROL, info.textwindow, SET_VALUE = "params.txt has been written", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 WIDGET_CONTROL, info.textwindow, SET_VALUE = "Tracking Complete. If you are finished, press Close", /APPEND WIDGET_CONTROL, info.textwindow, SET_TEXT_TOP_LINE=999999 end ; if (shouldweoverlay = 'no') then widget_control, info.fover1, set_uvalue='yes' ; if (shouldweoverlay = 'yes') then widget_control, info.fover1, set_uvalue='no' ; print, 'deritbe' ELSE: ENDCASE endif if(info.wannatrack eq 'no') then begin *infoptr = info end END Pro rytrack, filesin=filesin IF NOT keyword_set(filesin) THEN BEGIN filesin = [-1] ENDIF ;- Create column-aligned non-resizeable top level base tlb = widget_base(row=1, title='RyTrack: Gui Tracking System Based on Track.Pro', $ tlb_frame_attr=1, xoffset=100, xsize=900) ; videobase= widget_base(column=1, title='Video Base', tlb_frame_attr=1) nonimages=widget_base(tlb, column=1, frame=1, scroll=true,y_scroll=650, xsize=350, x_scroll=360) ;Create text widgets filenamebase = widget_base(nonimages, row=1, frame=1) label1=widget_label(filenamebase, value="Image Directory") ryfilepath = widget_text(filenamebase, uvalue='thefilepath',/editable,xsize=30) ;- Create slider widgets sliderholder = widget_base(nonimages, column=2, frame=0) ;slidercheckbase = widget_base(sliderholder, column=1,frame=0, /nonexclusive) ; usebpass1 = widget_button(slidercheckbase, value='Use', uvalue='yes', xoffset=500) ;sliderbase = widget_base(sliderholder, column=1,frame=0) width = 200 image_proc_base = widget_base(nonimages, column=1,frame=1) label2=widget_label(image_proc_base, value="Image Processing") slid_bpass1 = widget_slider(image_proc_base, value=0, min=0, max=100, $ title='bandpass 1', xsize=width, uvalue='bpass1') slid_bpass2 = widget_slider(image_proc_base, value=0, min=0, max=100, $ title='bandpass 2', xsize=width, uvalue='bpass2') slid_sobel = widget_slider(image_proc_base, value=0, min=0, max=50, $ title='Sobel Smooth', xsize=width, uvalue='sobel') slid_thresh = widget_slider(image_proc_base, value=0, min=0, max=300, $ title='Threshold', xsize=width, uvalue='thresh') invertitbase = widget_base(image_proc_base, row=1, /nonexclusive) invertit = widget_button(invertitbase, value='Invert Image', uvalue='invertimage') feat_base = widget_base(nonimages, column=1,frame=1) label3=widget_label(feat_base, value="Particle Identification") slid_partrad = widget_slider(feat_base, value=5, min=0, max=100, $ title='Particle Radius', xsize=width, uvalue='radius') slid_partspace = widget_slider(feat_base, value=5, min=0, max=200, $ title='Particle Spacing', xsize=width, uvalue='spacing') slid_masscut = widget_slider(feat_base, value=0, min=0, max=10000, $ title='Mass Cut', xsize=width, uvalue='masscut') ecc_base = widget_base(feat_base, row=1,frame=0) ecc_butt = widget_base(ecc_base, row=1, /exclusive) greater_ecc = widget_button(ecc_butt, value='>', uvalue='greater_ecc') less_ecc = widget_button(ecc_butt, value='<', uvalue='less_ecc') slid_eccen = widget_slider(ecc_base, value=0, min=0, max=100, $ title='Eccentricity', xsize=width, uvalue='eccent') gyr_base = widget_base(feat_base, row=1,frame=0) gyr_butt = widget_base(gyr_base, row=1, /exclusive) greater_gyr = widget_button(gyr_butt, value='>', uvalue='greater_gyr') less_gyr = widget_button(gyr_butt, value='<', uvalue='less_gyr') slid_gyr = widget_slider(gyr_base, value=0, min=0, max=200, $ title='Radius of Gyration', xsize=width, uvalue='gyr') fieldbase = widget_base(feat_base, row=1, /nonexclusive, /ALIGN_CENTER) usefield = widget_button(fieldbase, value='Field', uvalue='field') tracker_base = widget_base(nonimages, column=1,frame=1) label3=widget_label(tracker_base, value="Tracking Parameters") slid_maxdisplace = widget_slider(tracker_base, value=5, min=0, max=100, $ title='Maximum Displacement', xsize=width, uvalue='maxdisp') slid_goodenough = widget_slider(tracker_base, value=5, min=0, max=200, $ title='Good Enough', xsize=width, uvalue='goodenough') slid_stepsmemory = widget_slider(tracker_base, value=5, min=0, max=200, $ title='Steps Memory', xsize=width, uvalue='stepsmemory') ;create button widgets buttbase = widget_base(nonimages, row=1, /nonexclusive) overlay1 = widget_button(buttbase, value='Overlay Original', uvalue='overlayoriginal') overlay2 = widget_button(buttbase, value='Overlay Filtered', uvalue='overlayfiltered') ;- Create text buttons buttbase3 = widget_base(nonimages, row=1) buttsize = 75 butt_start = widget_button(buttbase3, value='Start', $ xsize=buttsize, uvalue='start') butt_track = widget_button(buttbase3, value='ID and Track', $ xsize=90, uvalue='track') butt_ubertrack = widget_button(buttbase3, value='Just Track', $ xsize=buttsize, uvalue='ubertrack') butt_close = widget_button(buttbase3, value='Close', $ xsize=buttsize, uvalue='close') ;- Realize widgets widget_control, tlb, /realize ;;set the image holder widgets for our images imagebase = widget_base(tlb, column=1, xsize=501, ysize=650) originalimage = widget_draw(imagebase, xsize=500, ysize=300) filteredimage = widget_draw(imagebase, xsize=500, ysize=300) textWindow = WIDGET_TEXT(imagebase, XSIZE = 80, YSIZE = 3, value='Rytrack GUI Initialized', /SCROLL) widget_control, imagebase, /realize widget_control, originalimage, get_value=winid1 widget_control, filteredimage, get_value=winid2 widget_control, tlb, /realize ;setup event handler stuff info = {filesdirectory:ryfilepath,bpass1:slid_bpass1, bpass2:slid_bpass2, rysobel:slid_sobel,$ thresh:slid_thresh, partrad:slid_partrad, partspace:slid_partspace, status:'ITSALLGOODHOMEY', $ start:butt_start,imagenum:0, window1:winid1, $ window2:winid2,oorig:overlay1,firstimage:'no',ofilt:overlay2,secondimage:'no',invertim:invertit,$ shouldiinvert:'no',wannatrack:'no',fileholder:'blah',maxdisplace:slid_maxdisplace, $ goodenough:slid_goodenough, rymemory:slid_stepsmemory, greater_ecc:greater_ecc, less_ecc:less_ecc,$ use_ecc:'no',greater_gyr:greater_gyr,less_gyr:less_gyr, use_gyr:'no', gyr:slid_gyr, eccent:slid_eccen, $ use_field:'no',masscut:slid_masscut, textwindow:textWindow, filesin:filesin} infoptr = ptr_new(info) widget_control, tlb, set_uvalue=infoptr print, 'Widgets are initialized' xmanager, 'rytrack', tlb ;print, newarray.outfilesdirectory print, 'RyTrack, Shutting Down' ;print, newarray.maxdisplace ;print, (*infoptr).bpass1 END