source: sans/SANSReduction/branches/kline_29MAR07/Put in User Procedures/SANS_Reduction_v5.00/MaskUtils.ipf @ 82

Last change on this file since 82 was 76, checked in by srkline, 16 years ago

2nd pass of pulling out NCNR calls. Also cleared a lot of deadwood from the code, removing depricated functions that were mostly already commented out.

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