source: sans/Dev/trunk/NCNR_User_Procedures/Reduction/SANS/MaskUtils.ipf @ 1016

Last change on this file since 1016 was 1016, checked in by srkline, 6 years ago

changes to the calls to GBLoadWave to now use a path and only the file name. Previously I use the full path:name to construct the execute statement.

this is being done to try to act as a workaround for network neighborhood paths in windows 10 (where drives can't be mapped)

File size: 16.5 KB
Line 
1#pragma rtGlobals=1             // Use modern global access method.
2#pragma version=5.0
3#pragma IgorVersion=6.1
4
5//*********************
6// Vers. 1.2 092101
7//
8//entry procedure for reading a mask file
9//mask files are currently only acceptable in MCID format, as written out by NIH
10//Image, available on the Macs (haven't tested the output of the Java version
11//(Image/J)
12//
13// also contains new drawing routines for drawing a mask within IGOR
14// and saving it in the required format
15// - uses simpler drawing tools (fill objects, no lines) for speed
16//
17//*************************
18
19
20
21//reads the data (1=mask, 0 = no mask)
22//and plots a quickie image to make sure it's ok
23//data is always read into root:Packages:NIST:MSK folder
24//
25Proc ReadMASK()
26       
27        //SetDataFolder root:Packages:NIST:MSK
28        String fname = PromptForPath("Select Mask file")
29        if(strlen(fname)==0)
30                return
31        endif
32        ReadMCID_MASK(fname)
33       
34        //SetDataFolder root:Packages:NIST:MSK
35////    SRK SEP06 disable plot of mask data, just show the overlay
36////    String waveStr = "root:Packages:NIST:MSK:data"
37////    NewImage/F/S=2/K=1 $waveStr
38////    ModifyImage '' ctab= {*,*,YellowHot,0}
39        maskButtonProc("maskButton")
40//      OverlayMask(1)
41
42        //back to root folder (redundant)
43        SetDataFolder root:
44End
45
46
47//reads the mask data into the root:Packages:NIST:MSK folder
48//setDataFolder is required here
49//y-values must be flipped to get proper array assignment of the mask
50//
51// SRK -SEP09 - removed hard-wired 16384 (128x128) from GBLoadWave cmd string
52// for general XY compatibility (192x192) = 36864
53//
54Function ReadMCID_MASK(fname)
55        String fname
56        // Reads MCID-format mask files written out by SANS IMAGE
57        // put data into MSK data folder
58        // flip the y-values to correspond to the work file
59        NVAR pixelsX = root:myGlobals:gNPixelsX
60        NVAR pixelsY = root:myGlobals:gNPixelsY
61        SetDataFolder root:Packages:NIST:MSK
62        Killwaves/Z data,data0          //kill the old data, if it exists
63       
64//      String cmd = "GBLoadWave/N=data/T={72,72}/O/S=4/W=1/U="
65//      cmd += num2istr(pixelsX*pixelsY) + " /Q  \"" + fname +"\""
66
67        String cmd = "GBLoadWave/N=data/T={72,72}/O/S=4/W=1/P=catPathName/U="
68        cmd += num2istr(pixelsX*pixelsY) + " /Q  \"" + ParseFilePath(0, fname, ":", 1, 0) +"\""
69                       
70        Execute cmd
71        SetDataFolder root:Packages:NIST:MSK                                            //make sure correct data folder is set
72        WAVE data0 = $"root:Packages:NIST:MSK:data0"
73        Redimension/N=(pixelsX,pixelsY) data0
74        Flip_Y(data0)
75       
76        SetDataFolder root:Packages:NIST:MSK
77        Rename data0,data
78       
79        Variable/G root:Packages:NIST:MSK:gIsLogScale = 0
80        String/G root:Packages:NIST:MSK:fileList = GetFileNameFromPathNoSemi(fname)
81        //back to root folder
82        SetDataFolder root:
83        return(0)
84End
85
86//
87//flips the y-data of the MCID format array that was read in
88//the input array (pixelsX x pixelsY) is overwritten as output
89//
90// AND MUST BE SQUARE!
91//
92Function Flip_Y(mat)
93        Wave mat
94       
95        //reverses the order of y-indices in an MCID-style matrix output from SANS IMAGE,
96        //so that a mask file will be displayed properly on screen -
97        //"IMAGE" format is (0,0) in top left
98        //the (WORK)_data matches the detector, with (0,0) in the bottom left corner
99        NVAR pixelsX = root:myGlobals:gNPixelsX
100        NVAR pixelsY = root:myGlobals:gNPixelsY
101       
102        Variable ii,jj,kk
103        Make/O/N=(pixelsX) temp_y
104       
105        ii=0
106        do
107                jj=0
108                do
109                        temp_y[jj]=mat[ii][jj]
110                        jj+=1
111                while(jj<pixelsY)
112                kk=0
113                do
114                        mat[ii][pixelsX-1-kk]=temp_y[kk]
115                        kk+=1
116                while(kk<pixelsX)
117                ii+=1
118        while(ii<pixelsX)
119       
120        KillWaves temp_y
121        Return (0)
122End
123
124
125//**********************
126// for drawing a mask, see GraphWaveDraw (and Edit)
127//and for Image progessing demo - look in the examples forder in the
128//IGOR Pro folder....possible slider bar, constrast adjustment
129//
130//the following are macros and functions to overlay a mask on an image
131//
132//ResetLoop sets all of the zeros in the mask to NaN's so that they are
133//not plotted
134Function ResetLoop(tempStr)
135        String tempstr
136       
137        NVAR pixelsX = root:myGlobals:gNPixelsX
138        NVAR pixelsY = root:myGlobals:gNPixelsY
139        Variable ii=0,jj=0
140        Wave junk = $tempStr
141       
142        do
143                jj=0
144                do
145                        if(junk[ii][jj] == 0)
146                                junk[ii][jj] = NaN
147                        else
148                                junk[ii][jj] = 1
149                        endif
150                        jj+=1
151                while(jj<pixelsY)
152                ii+=1
153        while(ii<pixelsX)
154End
155
156//
157//toggles a mask on/off of the SANS_Data window
158// points directly to window, doesn't need current display type
159//
160// if state==1, show the mask, if ==0, hide the mask
161Function OverlayMask(state)
162        Variable state
163       
164        String maskPath = "root:Packages:NIST:MSK:data"
165        if(WaveExists($maskPath) == 1)
166                //duplicate the mask, which is named "data"
167                Duplicate/O root:Packages:NIST:MSK:data root:Packages:NIST:MSK:overlay
168                Redimension/D root:Packages:NIST:MSK:overlay
169       
170                String tempStr = "root:Packages:NIST:MSK:overlay"
171                ResetLoop(tempStr)              //keeps 1's and sets 0's to NaN
172       
173                //check to see if mask overlay is currently displayed
174                DoWindow SANS_Data
175                if(V_flag==0)
176                        return(0)
177                endif
178               
179                CheckDisplayed/W=SANS_Data root:Packages:NIST:MSK:overlay
180                //Print "V_flag = ",V_flag
181       
182                If(V_Flag == 1)         //overlay is present
183                        if(state==0)
184                                RemoveImage overlay
185                        endif           //don't need to do anything if we want to keep the mask
186                Else            //overlay is not present
187                        if(state==1)
188                                //append the new overlay
189                                AppendImage/L=left/B=bottom root:Packages:NIST:MSK:overlay
190                                //set the color table to vary from 0 to * (=max data = 1), with blue maximum
191                                //Nan's will appear transparent (just a general feature of images)
192                                ModifyImage/W=SANS_Data overlay ctab={0,*,BlueRedGreen,0}
193                        endif           //don't do anything if we don't want the overlay
194                Endif
195        Endif
196End
197
198//checkbox control procedure to toggle to "erase" mode
199//where the filled regions will be set to 0=no mask
200//
201Function EraseCheckProc(ctrlName,checked) : CheckBoxControl
202        String ctrlName
203        Variable checked
204
205        //SetDrawEnv fillpat=-1         //set the fill to erase
206        SetDrawEnv fillpat=1                    //keep a solid fill, use DrawMode to decide y/n mask state
207        if(checked)
208                CheckBox DrawCheck value=0
209        Endif
210End
211
212//checkbox control procedure to toggle to "draw" mode
213//where the filled regions will be set to 1=yes mask
214//
215Function DrawCheckProc(ctrlName,checked) : CheckBoxControl
216        String ctrlName
217        Variable checked
218
219        SetDrawEnv fillPat=1            //solid fill
220        if(checked)
221                CheckBox EraseCheck value=0
222        Endif
223End
224
225//function that polls the checkboxes to determine whether to add the
226//fill regions to the mask or to erase the fill regions from the mask
227//
228Function DrawMode()             //returns 1 if in "Draw" mode, 0 if "Erase" mode
229        ControlInfo DrawCheck
230        Return(V_Value)
231End
232
233// function that works on an individual pixel (sel) that is either part of the fill region
234// or outside it (= not selected). returns either the on state (=1) or the off state (=0)
235// or the current mask state if no change
236//** note that the acual numeric values for the on/off state are passed in and back out - so
237// the calling routine must send the correct 0/1/curr state
238// **UNUSED******
239Function MakeMask(sel,off,on,mask)
240        Variable sel,off,on,mask
241       
242        variable isDrawMode
243        isDrawMode = drawmode()
244       
245        if( sel )
246                if(isDrawMode)
247                        return on               //add point
248                else
249                        return off              //erase
250                endif
251        else
252                return mask             //don't change it
253        endif
254end
255
256
257//tempMask is already a byte wave of 0/1 values
258//does the save of the tempMask, which is the current state of the mask
259//
260Function SaveMaskButtonProc(ctrlName) : ButtonControl
261        String ctrlName
262       
263        WriteMask(root:myGlobals:drawMask:tempMask)
264       
265End
266
267//closes the mask drawing window, first asking the user if they have saved their
268//mask creation. Although lying is a bad thing, you will have to lie and say that
269//you saved your mask if you ever want to close the window
270//
271Function DoneMaskButtonProc(ctrlName) : ButtonControl
272        String ctrlName
273
274        DoAlert 1,"Have you saved your mask?"
275        if(V_flag==1) //yes selected
276                DoWindow/K drawMaskWin
277                KillDataFolder root:myGlobals:drawMask
278                KillWaves/Z M_ROIMask
279        Endif
280End
281
282//clears the entire drawing by setting it to NaN, so there is nothing displayed
283//
284Function ClearMaskButtonProc(ctrlName) : ButtonControl
285        String ctrlName
286       
287        SetDrawLayer/K ProgFront
288        WAVE tempOverlay=root:myGlobals:drawMask:tempOverlay
289        KillWaves/Z M_ROIMask,root:myGlobals:drawMask:tempMask
290        if(WaveExists(tempOverlay))
291                tempOverlay=NaN
292        endif
293End
294
295//Macro DrawMaskMacro()
296//      DrawMask()
297//End
298
299//main entry procedure for drawing a mask
300//needs to have a dataset in curDispType folder to use as the background image
301// for the user to draw on top of. Does not need data in the RAW folder anymore
302// - initializes the necessary folder and globals, and draws the graph/control bar
303//
304Function DrawMask()             //main entry procedure
305        //there must be data in root:curDispType:data FIRST
306        SVAR curType=root:myGlobals:gDataDisplayType
307        if(WaveExists($("root:Packages:NIST:"+curType+":data") ))
308                DoWindow/F drawMaskWin
309                If(V_flag == 0)
310                        InitializeDrawMask(curType)
311                        //draw panel
312                        Execute "DrawMaskWin()"
313                Endif
314        else
315                //no data
316                DoAlert 0,"Please display a representative data file using the main control panel"
317        Endif
318End
319
320//initialization of the draw window, creating the necessary data folder and global
321//variables if necessary
322//
323Function InitializeDrawMask(type)
324        String type
325        //create the global variables needed to run the draw window
326        //all are kept in root:myGlobals:drawMask
327        If( ! (DataFolderExists("root:myGlobals:drawMask"))  )
328                //create the data folder and the globals
329                                NewDataFolder/O root:myGlobals:drawMask
330                                Duplicate/O $("root:Packages:NIST:"+type+":data") root:myGlobals:drawMask:data          //copy of the data
331                Endif
332                //if the data folder's there , then the globals must also be there so don't do anything
333End
334
335//the macro for the graph window and control bar
336//
337Proc DrawMaskWin()
338        PauseUpdate; Silent 1           // building window...
339        Display /W=(178,84,605,513) /K=2 as "Draw A Mask"
340        DoWindow/C drawMaskWin
341        AppendImage root:myGlobals:drawMask:data
342        ModifyImage data cindex= :myGlobals:NIHColors
343        ModifyGraph width={Aspect,1},height={Aspect,1},cbRGB=(32768,54615,65535)
344        ModifyGraph mirror=2
345        ShowTools rect
346        ControlBar 70
347        CheckBox drawCheck,pos={40,24},size={44,14},proc=DrawCheckProc,title="Draw"
348        CheckBox drawCheck,help={"Check to add drawn regions to the mask"}
349        CheckBox drawCheck,value= 1,mode=1
350        CheckBox EraseCheck,pos={40,43},size={45,14},proc=EraseCheckProc,title="Erase"
351        CheckBox EraseCheck,help={"Check to erase drawn regions from the mask"}
352        CheckBox EraseCheck,value= 0,mode=1
353        Button button1,pos={146,3},size={90,20},title="Load MASK",help={"Loads an old mask in to the draw layer"}
354        Button button1,proc=LoadOldMaskButtonProc
355        Button button4,pos={146,25},size={90,20},proc=ClearMaskButtonProc,title="Clear MASK"
356        Button button4,help={"Clears the entire mask"}
357        Button button5,pos={290,7},size={50,20},proc=SaveMaskButtonProc,title="Save"
358        Button button5,help={"Saves the currently drawn mask to disk. The new mask MUST be re-read into the experiment for it to apply to data"}
359        Button button6,pos={290,40},size={50,20},proc=DoneMaskButtonProc,title="Done"
360        Button button6,help={"Closes the window. Reminds you to save your mask before quitting"}
361        Button button0,pos={130,47},size={120,20},proc=toMASKButtonProc,title="Convert to MASK"
362        Button button0,help={"Converts drawing objects to the mask layer (green)\rDoes not save the mask"}
363        Button button7,pos={360,25},size={25,20},proc=ShowMaskHelp,title="?"
364        Button button7,help={"Show the help file for drawing a mask"}
365        GroupBox drMode,pos={26,5},size={85,61},title="Draw Mode"
366       
367        SetDrawLayer ProgFront
368        SetDrawEnv xcoord= bottom,ycoord= left,save     //be sure to use axis coordinate mode
369EndMacro
370
371Function ShowMaskHelp(ctrlName) : ButtonControl
372        String ctrlName
373        DisplayHelpTopic/Z/K=1 "SANS Data Reduction Tutorial[Draw a Mask]"
374        if(V_flag !=0)
375                DoAlert 0,"The SANS Data Reduction Tutorial Help file could not be found"
376        endif
377End
378
379//loads a previously saved mask in the the draw layer
380// - does not affect the state of the current mask used for data reduction
381//
382// SRK -SEP09 - removed hard-wired 16384 (128x128) from GBLoadWave cmd string
383// for general XY compatibility (192x192) = 36864
384//
385Function LoadOldMaskButtonProc(ctrlName) : ButtonControl
386        String ctrlName
387       
388        //load into temp--- root:myGlobals:drawMask:tempMask
389        String fname = PromptForPath("Select Mask file")
390//      ReadMCID_MASK(fname)
391
392        // Reads MCID-format mask files written out by SANS IMAGE
393        // put data into MSK data folder
394        // flip the y-values to correspond to the work file
395        NVAR pixelsX = root:myGlobals:gNPixelsX
396        NVAR pixelsY = root:myGlobals:gNPixelsY
397       
398        SetDataFolder root:myGlobals:DrawMask
399        Killwaves/Z data,data0,tempMask         //kill the old data, if it exists
400
401//      String cmd = "GBLoadWave/N=data/T={72,72}/O/S=4/W=1/U="
402//      cmd += num2istr(pixelsX*pixelsY) + " /Q  \"" + fname +"\""
403
404        String cmd = "GBLoadWave/N=data/T={72,72}/O/S=4/W=1/P=catPathName/U="
405        cmd += num2istr(pixelsX*pixelsY) + " /Q  \"" + ParseFilePath(0, fname, ":", 1, 0) +"\""
406               
407        Execute cmd
408        SetDataFolder root:myGlobals:DrawMask                                   //make sure correct data folder is set
409        WAVE data0 = $"root:myGlobals:DrawMask:data0"
410        Redimension/B/N=(pixelsX,pixelsY) data0
411        Flip_Y(data0)
412       
413        SetDataFolder root:myGlobals:DrawMask
414        Rename data0,tempMask           //tempMask can be killed and re-named, since it's not on a graph
415       
416        SetDataFolder root:
417       
418        OverlayTempMask()               //put the new mask on the image
419End
420
421//button control that commits the drawn objects to the current mask drawing
422// and refreshes the drawing
423//
424Function toMASKButtonProc(ctrlName) : ButtonControl
425        String ctrlName
426       
427        ImageGenerateROIMask data               //M_ROIMask is in the root: folder
428       
429        CumulativeMask()                        //update the new mask (cumulative)
430        OverlayTempMask()               //put the new mask on the image
431End
432
433//update the current mask - either adding to the drawing or erasing it
434//
435//current mask is "tempMask", and is byte
436//overlay is "tempOverlay" and is SP
437//
438Function CumulativeMask()
439
440        //if M_ROIMask does not exist, make a quick exit
441        if( ! (WaveExists(M_ROIMask)) )
442                return(0)
443        endif
444        if(!waveExists(root:myGlobals:drawMask:tempMask))
445                //make new waves
446                Duplicate/O M_ROIMask root:myGlobals:drawMask:tempMask
447                Wave tempM=root:myGlobals:drawMask:tempMask
448                tempM=0
449        else
450                Wave tempM=root:myGlobals:drawMask:tempMask
451        endif
452        //toggle(M_ROIMask,root:myGlobals:drawMask:tempMask)
453       
454        WAVE M_ROIMask=M_ROIMask
455        Variable isDrawMode
456        isDrawMode = drawmode()         //=1 if draw, 0 if erase
457        if(isDrawMode)
458                tempM = (tempM || M_ROIMask)            //0=0, any 1 =1
459        else
460                // set all 1's in ROI to 0's in temp
461                tempM = M_ROIMask ? 0 : tempM
462        endif
463End
464
465//overlays the current mask (as drawn) on the base image of the drawMaskWin
466// mask is drawn in the typical green, not part of the NIHColorIndex
467//
468// same overlay technique as for the SANS_Data window, NaN does not plot
469// on an image, and is "transparent"
470//
471Function OverlayTempMask()
472
473        //if tempMask does not exist, make a quick exit
474        if( ! (WaveExists(root:myGlobals:drawMask:tempMask)) )
475                return(0)
476        endif
477        //clear the draw layer
478        SetDrawLayer/K ProgFront
479        //append the overlay if necessary, otherwise the mask is already updated
480        Duplicate/O root:myGlobals:drawMask:tempMask root:myGlobals:drawMask:tempOverlay
481        WAVE tempOverlay=root:myGlobals:drawMask:tempOverlay
482        Redimension/S tempOverlay
483        tempOverlay=tempOverlay/tempOverlay*tempOverlay
484       
485        CheckDisplayed/W=DrawMaskWin tempOverlay
486        //Print "V_flag = ",V_flag
487        If(V_Flag == 1)
488                //do nothing, already on graph
489        else
490                //append the new overlay
491                AppendImage tempOverlay
492                ModifyImage tempOverlay ctab= {0,*,BlueRedGreen,0}
493        Endif
494End
495
496
497//********************
498//writes an MCID-style MASK file, exactly as it would be output from NIH Image
499//file is:
500//      4 bytes
501// 128x128=16384 bytes (mask)   (in the general case, pixelsX x pixelsX = SQUARE)
502// 508 bytes
503// = 16896 bytes
504// incoming data is a 2-D wave of any precision data, 0's and 1's
505//
506// tested with 192x192 data, and it works correctly (once the reader was corrected)
507// - should work with generic XY dimensions
508//
509Function WriteMask(data)
510        Wave data
511       
512        NVAR pixelsX = root:myGlobals:gNPixelsX
513        NVAR pixelsY = root:myGlobals:gNPixelsY
514       
515        Variable refnum,ii=0,jj=0,dummy,num=pixelsX
516        String fullpath=""
517       
518        PathInfo/S catPathName
519        fullPath = DoSaveFileDialog("Save Mask file as",fname="",suffix=".MASK")                //won't actually open the file
520        If(cmpstr(fullPath,"")==0)
521                //user cancel, don't write out a file
522                Close/A
523                Abort "no data file was written"
524        Endif
525       
526        Make /B/O/N=(pixelsX) byteWave
527       
528        //actually open the file
529        Open/C="SANS"/T="MASK" refNum as fullpath
530        FSetPos refNum, 0
531        //write 4 bytes (to be skipped when reading the file)
532        FBinWrite /F=1 refnum,ii
533        FBinWrite /F=1 refnum,ii
534        FBinWrite /F=1 refnum,ii
535        FBinWrite /F=1 refnum,ii
536       
537        ii=num-1
538        jj=0
539        do
540                byteWave=data[p][ii]
541                FBinWrite /F=1 refnum,byteWave
542                ii-=1
543        while(ii>=0)
544       
545        //pad the rest of the file
546        ii=0
547        jj=0
548        do
549                FBinWrite /F=1 refnum,jj
550                ii+=1
551        while(ii<508)
552       
553        //close the file
554        Close refnum
555        ReadMCID_MASK(fullpath)
556        Killwaves/Z byteWave
557End
Note: See TracBrowser for help on using the repository browser.