📄 dicom_viewer.pro
字号:
;
; Name - DICOM_VIEWER
;
; Calling Syntax - DICOM_VIEWER
;
; Purpose - Display dicom tags and images. Allow quick navigation
; between dicom files in a directory.using the familiar
; patient, study, series, image hierarchy.
;
; Modification History - 17 May 2004, Written, Atle Borsholm
; Sept 2004, tree widget, iVolume, RTK
; April 2005, Rewrote DICOM_VIEWER_POPULATE_TREE. DSA
; Added Expand/Contract menu buttons. DSA
; Added file directory label. DSA
; May 2005, Modified rubberband zoom DSA
;
;
;----------------------------------------------------------------------
;
; Private:
;
;----------------------------------------------------------------------
; dicom_viewer_table_event
;+
; Handles table events
;
; @param event {in}{type=structure} Event structure.
;-
pro dicom_viewer_table_event, event
compile_opt hidden
widget_control, event.top, get_uvalue = s
if strlowcase(tag_names(event, /struct)) eq 'widget_context' then begin
widget_displaycontextmenu, event.id, event.x, event.y, (*s).table_cbase
endif else begin
if strlowcase(tag_names(event, /struct)) eq 'widget_table_cell_sel' then $
(*s).table_row_select = event.sel_bottom
endelse
end
;
; Private:
;
;----------------------------------------------------------------------
; dicom_viewer_table_event
;+
; Handle table's context menu events
;
; @param event {in}{type=structure} Event structure.
;-
pro dicom_viewer_table_context_event, event
widget_control, event.top, get_uvalue = s
if ((*s).table_row_select ge 0) && ((*s).anonymizer -> query_wizard()) then begin
widget_control, (*s).wtable, get_value = new_tag, $
use_table_select = [0,(*s).table_row_select,0,(*s).table_row_select]
if strlen(new_tag) gt 0 then $
(*s).anonymizer -> define_tags, new_tag
endif
end
;
; Private:
;
;----------------------------------------------------------------------
; dicom_viewer_event
;+
; Handle top level base resize events.
;
; @param ev {in}{type=structure} Event structure.
;-
pro dicom_viewer_event, ev
compile_opt idl2, HIDDEN
; Top level base didn't generate the event, ignore it.
if ev.top ne ev.id then return
WIDGET_CONTROL, ev.top, TLB_GET_SIZE=tlbSize, GET_UVALUE=s
tlbSize = (tlbSize - (*s).padding) > [500,40]
colWidths = WIDGET_INFO((*s).wtable, /COLUMN_WIDTHS)
colWidths = ROUND(colWidths*(tlbSize[0]/TOTAL(colWidths)))
WIDGET_CONTROL, (*s).tbase, SCR_XSIZE=tlbSize[0] - (*s).xpad
WIDGET_CONTROL, (*s).wTree, SCR_XSIZE=tlbSize[0] - (*s).xpad
WIDGET_CONTROL, (*s).wtable, SCR_XSIZE=tlbSize[0], $
SCR_YSIZE=tlbSize[1], COLUMN_WIDTHS=colWidths
end
;----------------------------------------------------------------------
; dicom_viewer_tree_event
;+
; Handle a tree event.
;-
pro dicom_viewer_tree_event, event
compile_opt idl2
; Get the event type and app state
WIDGET_CONTROL, event.id, GET_UVALUE=str
WIDGET_CONTROL, event.top, GET_UVALUE=s
; Disable the series in iVolume menu
WIDGET_CONTROL, (*s).wVol, SENSITIVE=0
; What to do depends upon what was clicked
case str of
'PATIENT': ; ignore for now
'STUDY' : ; ignore for now
'SERIES' : WIDGET_CONTROL, (*s).wVol, SENSITIVE=1 ; allow for series in iVolume
ELSE : begin
widget_control, (*s).outlabel, set_value = ' '
void = dicom_viewer_open_file(str, s) ; open an image, we know it exists
end
endcase
end
;----------------------------------------------------------------------
; dicom_viewer_draw_event
;+
; Handle draw widget events.
;
; @param ev {in}{type=structure} Event structure.
;-
pro dicom_viewer_draw_event, ev
compile_opt HIDDEN
; Get the app structure
widget_control, ev.top, get_uvalue=s
; Right-click (context menu)
if (ev.release eq 4) then begin
WIDGET_DISPLAYCONTEXTMENU, ev.id, ev.x, ev.y, (*s).cbase
endif
; Left-click (zoom)
if (ev.type eq 0) && (ev.press eq 1) then begin
; Begin zoom box
res = (*s).win->PickData((*s).view, (*s).image, [ev.x, ev.y], xyz)
poly = xyz[0:1,[0,0,0,0]] ; replicate 4 corners of box
oPoly = OBJ_NEW('IDLgrPolygon', poly, STYLE=1, COLOR=[0,255,0])
(*s).model->Add, oPoly
(*s).win->Draw
endif else if (ev.type eq 2) && ((*s).model->Count() ge 2) then begin
; Drag zoom box (grow)
res = (*s).win->PickData((*s).view, (*s).image, [ev.x, ev.y], xyz)
oPoly = (*s).model->Get(POSITION=1)
oPoly->GetProperty, DATA=data
data[0,[1,2]] = xyz[0]
data[1,[2,3]] = xyz[1]
oPoly->SetProperty, DATA=data
(*s).win->Draw
endif else if (ev.type eq 1) && (ev.release eq 1) && ((*s).model->Count() gt 1) then begin
; Done with zoom box
oPoly = (*s).model->Get(POSITION=1)
(*s).model->Remove, oPoly
oPoly->GetProperty, DATA=data
OBJ_DESTROY, oPoly
minx = MIN(data[0,*], MAX=maxx)
miny = MIN(data[1,*], MAX=maxy)
if (maxx-minx gt 1) && (maxy-miny gt 1) then begin
(*s).view -> getproperty, viewplane_rect = vpr
range = [maxx-minx, maxy-miny]
k = min(vpr[2:3]/range)
new_range = vpr[2:3]/k
(*s).view -> setproperty, viewplane_rect = [[minx,miny]-float(new_range-range)/2, new_range]
endif
(*s).win->Draw
endif
dicom_viewer_update_sensitivity, s
end
;----------------------------------------------------------------------
; dicom_viewer_context_event
;+
; Right-click in the draw widget.
;
; @param ev {in}{type=structure} Event structure.
;-
pro dicom_viewer_context_event, ev
compile_opt HIDDEN, idl2
; Get the application state
WIDGET_CONTROL, ev.top, GET_UVALUE=s
; And context menu value
WIDGET_CONTROL, ev.id, GET_UVALUE=arg
if (arg eq 'anonymize') then begin
if (*s).anonymizer -> query_wizard() then return
child = widget_info((*s).table_cbase, /child)
widget_control, child, sensitive = 1
(*s).anonymizer -> setproperty, file = (*s).file
wcheck = widget_info((*s).bwiz, /button_set)
outfile = (*s).anonymizer -> anonymize( $
wizard = wcheck)
if widget_info(child, /active) then $
widget_control, child, sensitive = 0
if outfile eq '' then $
return
if wcheck then begin
void = dialog_message(/quest, $
['Anonymized file ' + outfile + ' created', $
'Open this file?'])
if strlowcase(void) eq 'yes' then begin
if file_test(outfile, /directory) then $
dir = outfile $
else $
dir = file_dirname(outfile,/mark_dir)
files=file_search(dir+'*',/test_regular)
if dicom_viewer_open_file(outfile, s) then begin
widget_control, (*s).wtree, set_uvalue=files
void = dicom_viewer_populate_tree(s, outfile)
endif
endif
endif
widget_control, (*s).outlabel, set_value = 'Anonymized file : ' + outfile
endif else begin
; Perform the selected event and update the image
(*s).image->ContextEvent, arg
(*s).win->Draw
dicom_viewer_update_sensitivity, s
; Set the cine timer
if (arg eq 'cine') then begin
if tag_names(ev, /STRUCTURE_NAME) ne 'WIDGET_TIMER' then (*s).cine = ~(*s).cine
if (*s).cine then WIDGET_CONTROL, ev.id, TIMER=0.5 $
else WIDGET_CONTROL, ev.id, /CLEAR_EVENTS
endif
endelse
end
;----------------------------------------------------------------------
; dicom_viewer_maketable
;+
; @returns A string array with the tag numbers and description(*s).
;
; @param oDicom {in}{type=IDLffDICOMEx object reference} A DICOM file.
;-
function dicom_viewer_maketable, oDicom
compile_opt HIDDEN
tags=oDicom->EnumerateTags(/QUIET)
n=n_elements(tags)
table=strarr(6,n)
indent = strmid(replicate(62b,max(tags.level)>1),0,tags.level)
table[0,*]=indent+tags.tag
table[1,*]=strtrim(tags.length,2)
table[2,*]=tags.vr
table[3,*]=strtrim(tags.valuecount,2)
table[4,*]=tags.value
table[5,*]=tags.description
return, table
end
;----------------------------------------------------------------------
; dicom_viewer_open_file
;+
; Open and display a DICOM file.
;
; @returns True (1) if file successfully opened, false (0) otherwise.
;
; @param file {in}{type=string} Pathname of the file to open.
; @param s {in}{type=pointer} Pointer to application state.
;-
function dicom_viewer_open_file, file, s
compile_opt idl2
err = 0
catch, err
if (err eq 0) then begin
o = obj_new('IDLffDicomEx',file,/NON)
(*s).file = file
(*s).image->Import,o
table=dicom_viewer_maketable(o)
ysize=(size(table))[2]
WIDGET_CONTROL, (*s).wtable, SET_VALUE=temporary(table), $
TABLE_YSIZE=ysize, SET_UVALUE=file
WIDGET_CONTROL, (*s).wTable, SET_TABLE_VIEW=[0,0]
WIDGET_CONTROL, (*s).wexport, SENSITIVE=1
(*s).image->GetContext, SENSITIVE=sens, COUNT=n
for i=0,n-1 do WIDGET_CONTROL, (*s).cbut2[i], SENSITIVE=sens[i]
(*s).anonymizer -> setproperty, file = file
catch, /CANCEL
endif else begin
;
; Not a DICOM file.
;
catch, /CANCEL
WIDGET_CONTROL, (*s).wtable, SET_VALUE=strarr(6,6)
(*s).image->IDLgrImage::SetProperty, DATA=bytarr(2,2)
(*s).image -> setproperty, nframes = 0
(*s).view->SetProperty, VIEWPLANE_RECT=[0,0,2,2]
(*s).win->Draw
WIDGET_CONTROL, (*s).wexport, SENSITIVE=0
dicom_viewer_update_sensitivity, s
help, /LAST, OUTPUT=errmsg
(*s).file = ''
void=dialog_message(['Error opening dicom file',errmsg], DIALOG_PARENT=(*s).tlb)
; Unselect any selected tree nodes.
wid = widget_info((*s).wtree, /tree_select)
if wid[0] gt -1 then $
for i = 0, n_elements(wid)-1 do $
widget_control, wid[i], set_tree_select = 0
; Change TLB title.
widget_control, (*s).tlb, tlb_set_title = 'IDL Dicom Viewer'
return, 0
endelse
if obj_valid(o) then obj_destroy, o
(*s).view->SetProperty, VIEWPLANE_RECT=(*s).image->DefaultZoom()
(*s).win->Draw
dicom_viewer_update_sensitivity, s
; Change TLB title to reflect selected file.
widget_control, (*s).tlb, tlb_set_title = 'IDL Dicom Viewer (' + $
file + ')'
return, 1
end
;----------------------------------------------------------------------
; dicom_viewer_populate_tree
;+
; Examine all files in the current directory and load the tree with
; those DICOM files found sorted by patient, study, series and image.
;
; @param s {in}{type=pointer} Pointer to application state structure.
; @param file {in}{type=string} Full path to file being opened.
;-
function dicom_viewer_populate_tree, s, file
compile_opt idl2, logical_predicate
widget_control, hourglass = 1
file = (n_elements(file) gt 0) ? file[0] : ''
widget_control, (*s).dirlabel, set_value = 'Scanning Files...'
widget_control, (*s).wtree, get_uvalue = files
geom = widget_info((*s).wtree, /geometry)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -