; $Id: defroi.pro,v 1.18 2004/01/21 15:54:51 scottm Exp $ ; ; Copyright (c) 1987-2004, Research Systems, Inc. All rights reserved. ; Unauthorized reproduction prohibited. ; ;Define an irregular Region of Interest. ;+ ; NAME: DEFROI ; ; PURPOSE: Define an irregular region of interest of an image ; using the image display system and the cursor/mouse. ; ; CATEGORY: Image processing. ; ; CALLING SEQUENCE: ; R = Defroi(Sx, Sy, X0, Y0) ; ; INPUTS: ; Sx, Sy = Size of image, in pixels. ; ; Optional Inputs: ; X0, Y0 = Coordinate of Lower left corner of image on display. ; If omitted, (0,0) is assumed. Screen device coordinates. ; ZOOM = zoom factor, if omitted, 1 is assumed. ; ; OUTPUTS: ; Function result = vector of subscripts of pixels inside the region. ; Side effect: The lowest bit in which the write mask is enabled ; is changed. ; ; OPTIONAL OUTPUTS: ; Xverts, Yverts = Optional output parameters which will contain ; the vertices enclosing the region. ; ; KEYWORD Parameters: ; NOREGION = Setting NOREGION inhibits the return of the ; pixel subscripts. ; NOFILL = if set, inhibits filling of irregular region on completion. ; RESTORE = if set, original image on display is restored to its ; original state on completion. ; ; COMMON BLOCKS: ; None. ; ; SIDE EFFECTS: ; Display is changed if RESTORE is not set. ; ; RESTRICTIONS: ; Only works for interactive, pixel oriented devices with a ; cursor and an exclusive or writing mode. ; ; PROCEDURE: ; The exclusive or drawing mode is used to allow drawing and ; erasing objects over the original object. ; ; The operator marks the vertices of the region, either by ; dragging the mouse with the left button depressed or by ; marking vertices of an irregular polygon by clicking the ; left mouse button, or with a combination of both. ; The center button removes the most recently drawn points. ; Press the right mouse button when finished. ; When the operator is finished, the region is filled using ; the polyfill function, and the polyfillv function is used ; to compute the subscripts within the region. ; ; MODIFICATION HISTORY: DMS, March, 1987. ; Revised for SunView, DMS, Nov, 1987. ; Added additional argument checking, SNG April, 1991 ; Modified for devices without write masks: DMS, March, 1992. ; Uses exclusive or mode rather than write masks. ; Modified to preserve device mode, RJF, Nov 1997. ; Modified: CT, RSI, Aug 2000: Replace !err with !mouse. ; Replace /WAIT with /DOWN in CURSOR calls. Prevents multiple ; points from being erased. ; Modified: CT, RSI, Aug 2002: Use /WAIT for left mouse button, ; and /DOWN for middle button. Now you can draw a smooth curve ; and erase single points. # of points is now unlimited. ; Also, if less than 3 vertices, it keeps them rather than ; forcing user to start over. ; Modified: CT, RSI, June 2003: Better handling for smooth curves ; on Windows, where it erased points that were just drawn. ;- ; Function Defroi, Sx, Sy, Xverts, Yverts, X0=x0, Y0=y0, ZOOM = ZOOM, $ NOREGION = Noregion, NOFILL = Nofill, RESTORE = restore COMPILE_OPT idl2 on_error,2 ;Return to caller if error nc1 = !d.table_size-1 ;# of colors available if sx lt 1 or sy lt 1 then $ ;Check some obvious things message, 'Dimensions of the region must be greater than zero.' if sx gt !d.x_size then $ message, 'The width of the region must be less than ' + $ strtrim(string(!d.x_size),2) sy = sy < !d.y_size device, get_graphics_function=oldGrphFunc ; Remember what to restore it to device, set_graphics_function=6 ; Set XOR mode n = 0 MESSAGE, /INFO, 'Left button to mark point' MESSAGE, /INFO, 'Middle button to erase previous point' MESSAGE, /INFO, 'Right button to close region' ninc = 100 ; initial max # of points. This can grow. xverts = intarr(ninc) ;arrays yverts = intarr(ninc) xprev = -1 yprev = -1 if n_elements(x0) le 0 then x0 = 0 if n_elements(y0) le 0 then y0 = 0 if n_elements(zoom) le 0 then zoom = 1 !MOUSE.button = 1 ; initialize to left mouse button while (1b) do begin ; infinite loop ; Get x,y in device coords. ; If the user presses the left button, use /WAIT, which returns ; again immediately if the button is still down. This allows the ; user to draw curves while holding the button down. ; If the user presses the middle or right button, use /DOWN, ; which doesn't return until the next button down. Otherwise, ; because our loop is so fast, we will get multiple middle ; button events, which will erase more than one point at a time. Cursor, xx, yy, WAIT=(!MOUSE.button eq 1), $ DOWN=(!MOUSE.button ne 1), /DEVICE switch !MOUSE.button of 1: begin ; Add a point. xx = (xx - x0) / zoom ;To image coords yy = (yy - y0) / zoom ; Out of range or same location? if (xx ge sx) || (yy ge sy) || $ ((xx eq xprev) && (yy eq yprev)) then $ break xprev = xx yprev = yy if (n ge N_ELEMENTS(xverts)) then begin xverts = [xverts, INTARR(ninc)] yverts = [yverts, INTARR(ninc)] endif xverts[n] = xx yverts[n] = yy addpoint = 1b ; needed for removing points PLOTS, xverts[n]*zoom + x0,yverts[n]*zoom + y0, $ /DEVICE, COLOR=nc1, /NOCLIP, PSYM=-3, $ CONTINUE=(n gt 0) n++ ; Next point break end ; We use 2 or 5 for the middle button because some Microsoft ; compatible mice use 5. 2: ; fall thru 5: begin ; Delete a point. if (n le 1) then $ break ; Back up a point. n-- ; If this is the first point to be removed (we just added a point), ; then we need to erase the last point as well. if (addpoint) then begin PLOTS, xverts[n]*zoom+x0,yverts[n]*zoom + y0, $ /DEVICE, COLOR=nc1, /NOCLIP, PSYM=-3 addpoint = 0b endif PLOTS, xverts[n-1]*zoom + x0,yverts[n-1]*zoom + y0, $ /DEVICE, COLOR=nc1, /NOCLIP, PSYM=-3, $ /CONTINUE break end 4: begin ; Finish ROI. if (n ge 3) then $ goto, done ; out of while loop ; If we have less than 3 points, print out a warning and ; make the user keep adding points. MESSAGE, /INFO, $ 'You must select at least 3 points. Please continue selection.' break end else: ; ignore endswitch endwhile done: xverts = xverts[0:n-1] ;truncate yverts = yverts[0:n-1] if keyword_set(restore) then begin ; Erase all points & lines. xv = xverts*zoom + x0 yv = yverts*zoom + y0 for i=n-1,0,-1 do begin plots, xv[i], yv[i], $ /dev, color=nc1, /noclip, psym=-3, $ CONTINUE=(i lt (n-1)) ; This innocuous wait,0 is needed to flush the graphics cache ; on certain systems (such as Windows). Otherwise it will store ; up the points and try to draw them all at once, which causes ; problems with xor trying to erase the points. ; This is also why we need to do this in a loop. wait, 0 endfor endif else if keyword_set(nofill) then begin plots, [xverts[0],xverts[n-1]]*zoom+x0, $ [yverts[0],yverts[n-1]]*zoom+y0,$ /dev,color = nc1,/noclip ;Complete polygon endif else begin polyfill, xverts*zoom+x0, yverts*zoom+y0,$ /dev,color = nc1,/noclip ;Complete polygon endelse if !order ne 0 then $ yverts = sy/zoom - 1 - yverts ;Invert Y? device,set_graphics=3 ;Re-enable normal copy write ; get subscripts inside area. a = keyword_set(noregion) ? 0 : polyfillv(xverts,yverts,sx,sy) device, set_graphics_function=oldGrphFunc ; Restore old grphx mode return,a end