source: sans/SANSReduction/trunk/Put in User Procedures/SANS_Reduction_v5.00/MaskUtils.ipf @ 41

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

change to UNIX line endings

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