; NAME: ; xqtv (Quick TV) ; ; PURPOSE: ; A basic image display tool. ; ; CATEGORY: ; Data visualization ; ; CALLING SEQUENCE: ; xqtv, image, WID=wid,GROUP_LEADER=group_leader,MIN=min,MAX=max,$ ; CANCEL=cancel ; xqtv ; ; INPUTS: ; image - A 2-D. ; ; OUTUTS: ; NA ; ; KEYWORD PARAMETERS: ; WID - The window ID number of the plot window. This allows the ; user to over plot lines and symbols. ; GROUP_LEADER - he widget ID of an existing widget that serves ; as "group leader" for the newly-created widget. ; MIN - The minimum value of the image ; MAX - The maximum value of the image ; ; PROCEDURE'S USED: ; Requires the Astronomy User's Library ; mkct ; coyote_field2 ; ; PROCEDURE: ; A 2-D, is required for this routine. After displaying ; the image, a plot command is executed to set up a coordinate ; system so the user can overplot lines and symbols. ; ; REVISION HISTORY: ; 2000-08-06 - Written by M. Cushing, Institute for Astronomy, UH ; ; The routine is based heavily on Aaron J. Barth's atv ; which is a much more robust image display tool. In fact, some ; code such as xqtv_color is taken directly from atv. To download ; atv, go to http://cfa-www.harvard.edu/~abarth/atv/atv.html. ; ; ;****************************************************************************** ; ; ----------------------------Support procedures------------------------------ ; ;****************************************************************************** ; pro xqtv_startup,WID=wid,GROUP_LEADER=group_leader mkct font='7x14' common xqtv_state, state,main_image ; Build the structures which will hold the important info. ; w - contains info pertaining to widget operations. w = {fix_bg:0,$ hdr_base:0L,$ hdr_text:0,$ keyboard:0L,$ max_fld:[0,0],$ min_fld:[0,0],$ plot_base:0,$ slider:0,$ xqtv_base:0L,$ xlabel:0,$ ylabel:0,$ ymax:0,$ ymin:0,$ zlabel:0} p = {blue:ptr_new(fltarr(2)),$ color:0L,$ colorwin_wid:0L,$ cursormode:'None',$ green:ptr_new(fltarr(2)),$ imagescaling:'Linear',$ maxbandc:1000L,$ offset:0L,$ pixmap_wid:0L,$ plotwin_wid:0L,$ plotxscale:[0.,0.],$ plotyscale:[0.,0.],$ red:ptr_new(fltarr(2)),$ reg:fltarr(2,2)+!values.f_nan,$ screen_size:get_screen_size( ),$ track:1L,$ trackwin_size:81L,$ trackwin_wid:0L} d = {bytesclimage:ptr_new(fltarr(2,2)),$ hdr:ptr_new(strarr(2)),$ image:ptr_new(fltarr(2)),$ imagemax:0.,$ imagemin:0.,$ ncols:0L,$ nrows:0L,$ path:''} state = {w:w,p:p,d:d} state.w.xqtv_base = widget_base(title='XQTV',$ /row,$ mbar=top_menu,$ group_leader=group_leader) ; Create top menu bar and set its event handler topmenu_desc = ['1\File','0\Read Fits','0\Image Math','2\Quit',$ '1\ColorMap','0\Grey','0\Heat','0\Rainbow','2\Blue-White',$ '1\Range','0\Full Range','2\Auto Range',$ '1\Scaling','0\Linear','2\Hist Eq',$ '1\Rotate','0\-Y to +Y','0\-X to +X','0\-90','0\-180',$ '2\-270',$ '1\ImageInfo','2\Header',$ '1\Help','2\Help XQTV'] top_menu = cw_pdmenu(top_menu, $ font=font,$ topmenu_desc, $ /mbar, $ /help, $ /return_name, $ uvalue='top_menu') widget_control, top_menu, event_pro = 'xtv_topmenuevent' ; state.w.keyboard = widget_text(state.w.xqtv_base, $ ; /all_events, $ ; scr_xsize = 1, $ ; scr_ysize = 1, $ ; uvalue = 'Keyboard', $ ; event_pro='xqtv_input',$ ; value = '') info_base = widget_base(state.w.xqtv_base,$ /column,$ frame=2,$ event_pro = 'xqtv_input') trackwin_base = widget_base(info_base,$ /column,$ /base_align_center,$ frame=2) trackwin = widget_draw(trackwin_base,$ xsize=151,$ ysize=151) state.w.slider = widget_slider(trackwin_base,$ uvalue='Slider',$ event_pro = 'xqtv_input',$ minimum=11,$ maximum=81,$ value=81) pos_base = widget_base(info_base,$ /column,$ frame=2,$ /base_align_center) tmp_string = string(1000,format = '("X:",i4)' ) state.w.xlabel = widget_label(pos_base,value=tmp_string,font=font,$ /align_left) tmp_string = string(1000,format = '("Y:",i4)' ) state.w.ylabel = widget_label(pos_base,value=tmp_string,font=font,$ /align_left) tmp_string = string(1.0e-10,format = '("Z:",g12.5)' ) state.w.zlabel = widget_label(pos_base,value=tmp_string,font=font,$ /align_left) buttons_base = widget_base(info_base,$ /column,$ frame=2,$ /base_align_center) min = coyote_field2(buttons_base,$ labelfont=font,$ fieldfont=font,$ title='Min:',$ uval = 'Min',$ xsize=12,$ event_pro = 'xqtv_input',$ /cr_only,$ textid=textid) state.w.min_fld = [min,textid] max = coyote_field2(buttons_base,$ labelfont=font,$ fieldfont=font,$ title='Max:',$ uval = 'Max',$ xsize=12,$ event_pro = 'xqtv_input',$ /cr_only,$ textid=textid) state.w.max_fld = [max,textid] plot_base = widget_base(state.w.xqtv_base,$ /column,$ frame=2) plotwin = widget_draw(plot_base,$ /align_center,$ xsize=512,$ ysize=512,$ event_pro = 'xqtv_plotwinevent',$ /motion_events,$ /button_events) ; Color Bar color_base = widget_base(state.w.xqtv_base,$ /column,$ frame=2) colorwin = widget_draw(color_base,$ /align_center,$ xsize=10,$ ysize=512) ; Load color table. mkct, 0, BOT=offset,RED=red,GREEN=green,BLUE=blue state.p.offset = offset *state.p.red = red *state.p.green = green *state.p.blue = blue ; Get things running. centertlb,state.w.xqtv_base widget_control, state.w.xqtv_base, /Realize ; Get plotwin ids widget_control, plotwin, get_value = x state.p.plotwin_wid = x wid = x widget_control, trackwin, get_value = x state.p.trackwin_wid = x widget_control, colorwin, get_value = x state.p.colorwin_wid = x ; Start the Event Loop. This will be a non-blocking program. XManager, 'xqtv', $ state.w.xqtv_base, $ /No_Block,$ cleanup = 'xqtv_cleanup' xqtv_colorbar end ; ;****************************************************************************** ; pro xqtv_autoscale common xqtv_state if n_elements(*state.d.image) gt 1000. then begin cols = randomn(0.5,state.d.ncols*.1,/UNIFORM)*state.d.ncols subimage = (*state.d.image)[cols,*] z = where(finite(subimage) eq 1) moments,subimage[z],mean,var,std endif else begin z = where(finite( (*state.d.image)) eq 1) moments,(*state.d.image)[z],mean,var,std endelse state.d.imagemax = ( mean + (3.*std) ) < max(*state.d.image,/NAN) state.d.imagemin = ( mean - (3.*std) ) > min(*state.d.image,/NAN) if state.d.imagemin ge state.d.imagemax then begin state.d.imagemin = state.d.imagemin-1 state.d.imagemax = state.d.imagemax+1 endif widget_control, state.w.min_fld[1], set_value=strcompress(state.d.imagemin,/re) widget_control, state.w.max_fld[1], set_value=strcompress(state.d.imagemax,/re) end ; ;***************************************************************************** ; pro xqtv_cleanup,event common xqtv_state ptr_free, state.p.blue ptr_free, state.p.green ptr_free, state.p.red ptr_free, state.d.bytesclimage ptr_free, state.d.image state = 0B end ; ;***************************************************************************** ; pro xqtv_color,event,BRIGHTNESS=brightness,CONTRAST=contrast common xqtv_state if n_elements(BRIGHTNESS) eq 0 then begin x = 1 > event.x < 512. y = 1 > event.y < 512. brightness = long ( (512-y) * (state.p.maxbandc)/512.) contrast = long ( x * (state.p.maxbandc)/512.) endif d = !d.table_size-state.p.offset-1 maxdp = 600 mindp = 4 if (contrast LT (state.p.maxbandc / 2)) then begin dp = ((d - maxdp) / float((state.p.maxbandc / 2) - 1)) * contrast + $ ((maxdp * state.p.maxbandc / 2) - d) / float(state.p.maxbandc / 2) endif else begin dp = ((mindp - d) / float(state.p.maxbandc / 2)) * contrast + $ ((d * state.p.maxbandc) - (mindp * state.p.maxbandc / 2)) / $ float(state.p.maxbandc / 2) endelse dp = fix(dp) r = replicate( (*state.p.red)[d-1] , 2*d + dp) g = replicate( (*state.p.green)[d-1], 2*d + dp) b = replicate( (*state.p.blue)[d-1] , 2*d + dp) r[0:d-1] = (*state.p.red)[0] g[0:d-1] = (*state.p.green)[0] b[0:d-1] = (*state.p.blue)[0] a = findgen(d) r[d] = congrid(*state.p.red, dp) g[d] = congrid(*state.p.green, dp) b[d] = congrid(*state.p.blue, dp) bshift = round(brightness * (d+dp) / float(state.p.maxbandc)) rr = r[a + bshift] gg = g[a + bshift] bb = b[a + bshift] tvlct, rr, gg, bb, state.p.offset end ; ;***************************************************************************** ; pro xqtv_colorbar common xqtv_state b = cmcongrid( findgen(!d.n_colors-state.p.offset-1), 512) + state.p.offset c = replicate(1,10) a = b ## c wset,state.p.colorwin_wid tv, a end ; ;***************************************************************************** ; pro xqtv_displayimage common xqtv_state size = state.d.ncols > state.d.nrows scale = 512./float(size) newcol = round( scale*float(state.d.ncols) ) newrow = round( scale*float(state.d.nrows) ) xoffset = abs( round( (newcol-512)/2.) ) yoffset = abs( round( (newrow-512)/2.) ) dimage = bytarr(512,512) dimage[xoffset,yoffset] = cmcongrid(*state.d.bytesclimage,newcol,newrow) wset, state.p.plotwin_wid erase tv, dimage delvarx,dimage plot,indgen(10),/nodata,/noerase,xsty=5,ysty=5,$ xrange=[-0.5,state.d.ncols-0.5],yrange=[-0.5,state.d.nrows-0.5],$ xmargin=[0,0],ymargin=[0,0],color=2,noclip=0,/device,$ position=[xoffset,yoffset,xoffset+newcol,yoffset+newrow] state.p.plotxscale = !x.s state.p.plotyscale = !y.s end ; ;****************************************************************************** ; pro xqtv_hdr common xqtv_state if not (xregistered('xqtv_hdrinfo')) then begin state.w.hdr_base = widget_base(group_leader = state.w.xqtv_base, $ /column, $ title='FITS Header',$ uvalue = 'headinfo_base') state.w.hdr_text = widget_text(state.w.hdr_base, $ /scroll, $ font='7x14',$ value = (*state.d.hdr), $ xsize = 85, $ ysize = 24) button = widget_button(state.w.hdr_base, $ value = 'Done',$ event_pro = 'xqtv_quit') widget_control, state.w.hdr_base, /realize XManager, 'xqtv_hdrinfo', $ state.w.hdr_base, $ /No_Block endif else begin widget_control, state.w.hdr_text, set_value=(*state.d.hdr) endelse end ; ;****************************************************************************** ; pro xqtv_minmax common xqtv_state min = cfld(state.w.min_fld,4,CANCEL=cancel) if cancel then return max = cfld(state.w.max_fld,4,CANCEL=cancel) if cancel then return if min ge max then begin widget_control, state.w.min_fld[0], set_value=state.d.imagemin widget_control, state.w.max_fld[0], set_value=state.d.imagemax endif state.d.imagemin = min state.d.imagemax = max xqtv_scaleimage xqtv_displayimage end ; ;***************************************************************************** ; pro xqtv_scaleimage common xqtv_state ncolors = !d.table_size-(state.p.offset+1) case state.p.imagescaling of 'Linear': *state.d.bytesclimage = bytscl(*state.d.image,$ /NAN,$ min = state.d.imagemin,$ max = state.d.imagemax,$ top = ncolors-1) + state.p.offset 'Hist Eq': *state.d.bytesclimage = bytscl(hist_equal(*state.d.image, $ minv=state.d.imagemin,$ maxv=state.d.imagemax),$ /NAN,top = ncolors-1) + state.p.offset endcase end ; ;****************************************************************************** ; pro xqtv_track,event common xqtv_state wset, state.p.plotwin_wid !x.s = state.p.plotxscale !y.s = state.p.plotyscale xy = round(convert_coord(event.x,event.y,/device, /to_data)) xpos = xy[0] ypos = xy[1] if xpos gt state.d.ncols-1 or xpos lt -1 or ypos gt state.d.nrows-1 or $ ypos lt -1 then begin tmp_string = string(xpos,format = '("X:",i4)' ) widget_control, state.w.xlabel, set_value=tmp_string,default_font='7x14' tmp_string = string(ypos,format = '("Y:",i4)' ) widget_control, state.w.ylabel, set_value=tmp_string,default_font='7x14' tmp_string = string('0', format = '("Z:",g12.5)' ) widget_control, state.w.zlabel, set_value=tmp_string,default_font='7x14' endif else begin if xpos eq -1 then xpos = 0 if ypos eq -1 then ypos = 0 tmp_string = string(xpos,format = '("X:",i4)' ) widget_control, state.w.xlabel, set_value=tmp_string,default_font='7x14' tmp_string = string(ypos,format = '("Y:",i4)' ) widget_control, state.w.ylabel, set_value=tmp_string,default_font='7x14' tmp_string = string((*state.d.image)[xpos,ypos],format = '("Z:",g12.5)' ) widget_control, state.w.zlabel, set_value=tmp_string,default_font='7x14' halfwin = fix(state.p.trackwin_size/2.) xbot = xpos-halfwin xtop = xpos+halfwin ybot = ypos-halfwin ytop = ypos+halfwin xoffset = (xbot lt 0) ? abs(xbot):0 yoffset = (ybot lt 0) ? abs(ybot):0 xbot = xbot > 0 xtop = xtop < (state.d.ncols-1) ybot = ybot > 0 ytop = ytop < (state.d.nrows-1) trackwin = fltarr(state.p.trackwin_size,state.p.trackwin_size) trackwin[xoffset,yoffset] = (*state.d.bytesclimage)[xbot:xtop,ybot:ytop] wset, state.p.trackwin_wid tv, cmcongrid(trackwin,151,151) plots, [0.46,0.49],[0.46,0.49], /normal,psym=0,color=3, thick=1.5 plots, [0.51,0.54],[0.51,0.54], /normal,psym=0,color=3, thick=1.5 plots, [0.46,0.49],[0.54,0.51], /normal,psym=0,color=3, thick=1.5 plots, [0.51,0.54],[0.49,0.46], /normal,psym=0,color=3, thick=1.5 endelse end ; ;****************************************************************************** ; ; ------------------------------Event Handlers-------------------------------- ; ;****************************************************************************** ; pro xqtv_input,event common xqtv_state widget_control, event.id, get_uvalue=uval widget_control, /hourglass case uval of 'Max': xqtv_minmax 'Min': xqtv_minmax 'Mouse Mode': 'Slider': begin state.p.trackwin_size = (event.value mod 2 eq 0) ? $ (event.value-1):event.value widget_control, state.w.slider, set_value=state.p.trackwin_size end endcase end ; ;***************************************************************************** ; pro xqtv_plotwinevent,event common xqtv_state if event.type eq 0 then begin state.p.color = 1 state.p.track = 0 endif if event.type eq 1 then begin state.p.color = 0 state.p.track = 1 endif if state.p.color then xqtv_color,event if state.p.track then xqtv_track,event cont: end ; ;****************************************************************************** ; pro xqtv_quit,event common xqtv_state widget_control, event.top, /destroy end ; ;***************************************************************************** ; pro xtv_topmenuevent, event common xqtv_state widget_control, event.id, get_uvalue = event_name widget_control, /hourglass case event_name of 'Auto Range': begin xqtv_autoscale xqtv_scaleimage xqtv_displayimage end 'Blue-White': begin mkct, 1,RED=red,GREEN=green,BLUE=blue *state.p.red = red *state.p.green = green *state.p.blue = blue end 'Full Range': begin state.d.imagemax = max(*state.d.image,/NAN) state.d.imagemin = min(*state.d.image,/NAN) widget_control, state.w.min_fld[1], $ set_value=strcompress(state.d.imagemin,/re) widget_control, state.w.max_fld[1], $ set_value=strcompress(state.d.imagemax,/re) xqtv_scaleimage xqtv_displayimage end 'Grey': begin mkct, 0,RED=red,GREEN=green,BLUE=blue *state.p.red = red *state.p.green = green *state.p.blue = blue end 'Heat': begin mkct, 3,RED=red,GREEN=green,BLUE=blue *state.p.red = red *state.p.green = green *state.p.blue = blue end 'Header': xqtv_hdr 'Help XQTV': 'Hist Eq': begin state.p.imagescaling = 'Hist Eq' xqtv_scaleimage xqtv_displayimage end 'Image Math': ximgmath,group_leader=state.w.xqtv_base 'Linear': begin state.p.imagescaling = 'Linear' xqtv_scaleimage xqtv_displayimage end 'Rainbow': begin mkct, 13,RED=red,GREEN=green,BLUE=blue *state.p.red = red *state.p.green = green *state.p.blue = blue end 'Read Fits': begin if state.d.path eq '' then begin fullpath = dialog_pickfile(dialog_parent=state.w.xqtv_base,$ filter='*.fits',get_path=newpath,$ /must_exist) state.d.path =newpath endif else begin fullpath = dialog_pickfile(dialog_parent=state.w.xqtv_base,$ filter='*.fits',path=state.d.path,$ get_path=newpath,/must_exist) state.d.path = newpath endelse if fullpath eq '' then goto, cont *state.d.image = readfits(fullpath,hdr) *state.d.hdr = hdr s = size(*state.d.image) state.d.ncols = s[1] state.d.nrows = s[2] xqtv_autoscale xqtv_scaleimage xqtv_displayimage str = 'XQTV - '+strmid(fullpath,strpos(fullpath,'/',/REVERSE_S)+1) widget_control, state.w.xqtv_base, tlb_set_title = str end 'Quit': begin widget_control, state.w.xqtv_base, /destroy print, 'DONE!!!!!' end '-X to +X': begin image = *state.d.image *state.d.image = rotate(image,5) xqtv_scaleimage xqtv_displayimage end '-Y to +Y': begin image = *state.d.image *state.d.image = rotate(image,7) xqtv_scaleimage xqtv_displayimage end '-90': begin *state.d.image = rotate(*state.d.image,1) xqtv_scaleimage xqtv_displayimage end '-180': begin *state.d.image = rotate(*state.d.image,2) xqtv_scaleimage xqtv_displayimage end '-270': begin *state.d.image = rotate(*state.d.image,3) xqtv_scaleimage xqtv_displayimage end endcase cont: end ; ;****************************************************************************** ; ; ------------------------------Main Program-------------------------------- ; ;****************************************************************************** ; pro xqtv,image,GROUP_LEADER=group_leader,WID=wid,MIN=min,MAX=max common xqtv_state if n_params() eq 1 then begin zparcheck, 'xqtv',image, 1, [1,2,3,4,5], 2, 'Image' s = size(image) if not xregistered('xqtv') then xqtv_startup,WID=wid,$ GROUP_LEADER=group_leader else wid = state.p.plotwin_wid *state.d.image = image state.d.ncols = s[1] state.d.nrows = s[2] *state.d.hdr = ' ' if n_elements(MIN) ne 0 and n_elements(MAX) ne 0 then begin state.d.imagemin = min state.d.imagemax = max widget_control,state.w.min_fld[1],set_value=strtrim(state.d.imagemin,2) widget_control,state.w.max_fld[1],set_value=strtrim(state.d.imagemax,2) endif else xqtv_autoscale xqtv_scaleimage xqtv_displayimage widget_control, state.w.xqtv_base, tlb_set_title = 'XQTV' endif else begin if not xregistered('xqtv') then xqtv_startup,WID=wid,$ GROUP_LEADER=group_leader else wid = state.p.plotwin_wid (*state.d.image) = findgen(1024,1024) state.d.ncols = 1024 state.d.nrows = 1024 xqtv_autoscale xqtv_scaleimage xqtv_displayimage endelse end