⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dicom_viewer.pro

📁 DICOM viewer - this software is used to view a set of DICOM images.
💻 PRO
📖 第 1 页 / 共 3 页
字号:

; Replace existing tree with new tree
    widget_control, (*s).wtree, /destroy
    (*s).wtree = widget_tree((*s).tbase, $
        xsize = geom.xsize, ysize = geom.ysize, $
        event_pro = 'dicom_viewer_tree_event', uvalue = files)

; INC : Increment at which data array size is increased
    inc = 100
    ind = 0
    sz = inc

; DICOM_INFO:
; 0 : Patient ID
; 1 : Study Instance UID
; 2 : Series Instance UID
; 3 : UID
; 4 : Patient Name
; 5 : Study
; 6 : Series
; 7 : Image
; 8 : Filename
    dicom_info = strarr(9,sz)

    for i = 0, n_elements(files)-1 do begin

        catch, err

        if err ne 0 then begin

            catch, /cancel
            continue

        endif

        odicom = obj_new('idlffdicomex', files[i], _extra = {no_pixel_data:1})

        if ind eq (sz-1) then begin
        ; Need to increase DICOM_INFO size to accomidate more data

            widget_control, (*s).dirlabel, get_value = tempstr
            widget_control, (*s).dirlabel, set_value = tempstr + '.'

            dicom_info = [[temporary(dicom_info)],[strarr(9,inc)]]
            sz = sz + inc

        endif

    ; Collect information:
        dicom_info[0,ind] = odicom -> getvaluedefault('0010,0020', def) ; Patient ID
        dicom_info[1,ind] = odicom -> getvaluedefault('0020,000D', def) ; Study Instance UID
        dicom_info[2,ind] = odicom -> getvaluedefault('0020,000E', def) ; Series Instance UID
        dicom_info[3,ind] = dicom_info[1,ind] + dicom_info[2,ind] + dicom_info[3,ind] ; UID
        dicom_info[4,ind] = odicom -> getvaluedefault('0010,0010', def) ; Patient Name
        dicom_info[5,ind] = odicom -> getvaluedefault('0020,0010', '') + $ ; Study
            ' ' + odicom -> getvaluedefault('0008,1030', '')
        dicom_info[6,ind] = odicom -> getvaluedefault('0020,0011', '') + $ ; Series
            ' ' + odicom -> getvaluedefault('0008,103E', '')
        dicom_info[7,ind] = odicom -> getvaluedefault('0020,0013', ''); Image
        dicom_info[8,ind] = files[i]

        ind++

        obj_destroy, odicom

    endfor

    if ind eq 0 then begin
    ; No DICOM files found...

        widget_control, (*s).dirlabel, set_value = $
            'No Dicom files found in ' + file_dirname(files[0])
        return, 0

    endif

; Remove extra array elements and sort.
    dicom_info = dicom_info[*,0:(ind-1)]
    dicom_info = dicom_info[*,sort(dicom_info[3,*])]

    seriesdata = lonarr(2,ind)

    pat_name = (pat_id = (sty = (ser = '')))

    for i = 0, ind-1 do begin

        if (pat_id ne dicom_info[0,i]) || (pat_name ne dicom_info[4,i]) then begin
        ; New Patient

            pat_id = dicom_info[0,i]
;            pat_name = dicom_info[4,i]
            wpat = widget_tree((*s).wtree, /folder, $
                value = pat_id + ' : ' + dicom_info[4,i], $
                uvalue = 'PATIENT')

        endif

        if (sty ne dicom_info[1,i]) || (pat_name ne dicom_info[4,i]) then begin
        ; New Study

            sty = dicom_info[1,i]
            wstudy = widget_tree(wpat, /folder, $
                value = 'Study ' + dicom_info[5,i], $
                uvalue = 'STUDY', /expanded)

        endif

        if (ser ne dicom_info[2,i]) || (pat_name ne dicom_info[4,i]) then begin
        ; New Series

            ser = dicom_info[2,i]
            wseries = widget_tree(wstudy, /folder, $
                value = 'Series ' + dicom_info[6,i], $
                uvalue = 'SERIES', /expanded)

        endif

        wimage = widget_tree(wseries, uvalue = dicom_info[8,i], $
            value = 'Image ' + dicom_info[7,i] + ' ( ' + $
            file_basename(dicom_info[8,i]) + ' ) ', $
            uname = dicom_info[8,i])

        seriesdata[*,i] = [wseries,wimage]
        pat_name = dicom_info[4,i]

    endfor

    if file ne '' then begin
    ; Expand tree to select FILE in the tree widget.

        wimage = widget_info((*s).wtree, find_by_uname = file)
        if wimage gt 0 then $
            widget_control, wimage, /set_tree_select, $
                                    /set_tree_visible

    endif

    widget_control, (*s).dirlabel, set_value = file_dirname(files[0])

    if ptr_valid((*s).seriesdata) then $
        ptr_free, (*s).seriesdata
    (*s).seriesdata = ptr_new(seriesdata, /no_copy)

    widget_control, hourglass = 0

    return, 1

end


;----------------------------------------------------------------------
;  dicom_viewer_display_series
;+
;  @returns  Empty string if no error, otherwise returned string is
;            error message.
;
;  @param s {in}{type=pointer} Pointer to application state.
;-
function dicom_viewer_display_series, s
  compile_opt idl2

  WIDGET_CONTROL, /HOURGLASS

  ;  Get the images associated with this series
  wSeries = WIDGET_INFO((*s).wTree, /TREE_SELECT)
  seriesData = *(*s).seriesData
  idx = where(seriesData[0,*] eq wSeries, c)
  if (c eq 0) then return, 'the series has no images'     ;  no images
  wImages = reform(seriesData[1,idx])
  if (n_elements(wImages) lt 3) then return, 'the series must contain at least 3 images' ;  too few images

  ;  Get DICOM objects for each image in the series
  objs = objarr(n_elements(wImages))
  for i=0, n_elements(wImages)-1 do begin
    WIDGET_CONTROL, wImages[i], GET_UVALUE=fname
    objs[i] = obj_new('IDLffDicomEx', fname[0])
  endfor

  ;  Check that all images have the same orientation
  orient = double(objs[0]->GetValueDefault('0020,0037', ''))
  if (orient[0] eq '') then begin
    obj_destroy, objs   ;  image orientation patient tag not filled in
    return, 'the image orientation patient tag is missing or empty'
  endif

  for i=1, n_elements(wImages)-1 do begin
    t = double(objs[i]->GetValueDefault('0020,0037', ''))
    if ~array_equal(orient,t) then begin
      obj_destroy, objs  ;  at least one image doesn't fit
      return, 'the images must all have the same orientation'
    endif
  endfor

  ;  Check that all images have the same attributes
  nframes   = objs[0]->GetValueDefault('0028,0008',1)
  rows      = objs[0]->GetValueDefault('0028,0010',0)
  cols      = objs[0]->GetValueDefault('0028,0011',0)
  bitsalloc = objs[0]->GetValueDefault('0028,0100',8)
  pixelrep  = objs[0]->GetValueDefault('0028,0103',0)

  if (nframes ne 1) then begin
    obj_destroy, objs
    return, 'cannot make a volume from multiframe data'   ;  don't handle multiframe images
  endif

  attr = [nframes, rows, cols, bitsalloc, pixelrep]

  for i=1, n_elements(wImages)-1 do begin
    t = [objs[i]->GetValueDefault('0028,0008',1),  $
         objs[i]->GetValueDefault('0028,0010',0),  $
         objs[i]->GetValueDefault('0028,0011',0),  $
         objs[i]->GetValueDefault('0028,0100',8),  $
         objs[i]->GetValueDefault('0028,0103',0)]
    if ~array_equal(attr, t) then begin
      obj_destroy, objs
      return, 'image attributes are not consistent within the series'   ;  attributes do not match
    endif
  endfor

  ;  Extract all the image positions
  ipp = dblarr(3, n_elements(wImages))
  for i=0, n_elements(wImages)-1 do begin
    ipp[*,i] = double(objs[i]->GetValueDefault('0020,0032', ''))
  endfor

  ;  Build the normal to the plane
  norm = [orient[1]*orient[5] - orient[2]*orient[4],   $
          orient[2]*orient[3] - orient[0]*orient[5],   $
          orient[0]*orient[4] - orient[1]*orient[3]]

  ;  Calculate the distance along the normal for each image and sort
  d = dblarr(n_elements(wImages))
  for i=0, n_elements(wImages)-1 do begin
    d[i] = total(norm*ipp[*,i])
  endfor

  idx = sort(d)
  d = d[idx]               ;  distances
  wImages = wImages[idx]   ;  widget references
  objs = objs[idx]         ;  DICOM objects

  ;  Calculate the z spacing, this must be the same (within 10%) for all slices
  dz = abs(d[0]-d[1])  ; mm
  for i=1, n_elements(wImages)-1 do begin
    diff = abs(dz - abs(d[i] - d[i-1]))
    if (diff gt dz/10.0) then begin
      obj_destroy, objs
      return, 'image slices are not evenly spaced'  ;  slices are not evenly spaced (to within 10%)
    endif
  endfor

  ;  Extract the image data now that the images are in order
  vol = make_array(cols, rows, n_elements(wImages),  $
                   TYPE=size(objs[0]->GetPixelData(),/TYPE))

  for i=0, n_elements(wImages)-1 do begin
    pix = objs[i]->GetPixelData(/ORDER)
    if n_elements(size(pix,/DIM)) ne 2 then begin
      obj_destroy, objs
      return, 'unable to process non-monochrome images'  ;  only processing simple grayscale images
    endif
    vol[*,*,i] = pix
  endfor
  vol = bytscl(temporary(vol))

  ;
  ;  Determine the actual volume size taking the in-plane
  ;  pixel spacing and z spacing into account.  This assumes
  ;  square pixels (the most common case).
  ;
  d = double(objs[0]->GetValueDefault('0028,0030',''))  ; in-plane resolution (mm)
  if (d[0] eq 0.0) then begin
    obj_destroy, objs
    return, 'image in-plane resolution tag missing or empty'  ;  this really should never happen, bad DICOM file
  endif
  dx = d[0]
  dy = d[1]

  ;
  ;  Rescale so that the largest dimension is n in length
  ;
  n = 256
  x = dx*cols
  y = dy*rows
  z = dz*n_elements(wImages)
  order = sort([x,y,z])
  case order[2] of
    0: begin
         newx = n
         newy = long(n*y/x)
         newz = long(n*z/x)
    end
    1: begin
         newy = n
         newx = long(n*x/y)
         newz = long(n*z/y)
    end
    2: begin
         newz = n
         newx = long(n*x/z)
         newy = long(n*y/z)
    end
  endcase

  vol = congrid(temporary(vol), newx, newy, newz)

  ;  Clean up since we no longer need the DICOM objects
  obj_destroy, objs

  ;  Pass the volume to iVolume to display
  iVolume, vol, HINTS=2
  return, ''
end


;----------------------------------------------------------------------
;  dicom_viewer_menu
;+
;  Handle menu choices.
;
;  @param ev {in}{type=structure}  Event structure.
;-
pro dicom_viewer_menu, ev
    compile_opt logical_predicate, HIDDEN

    ;  Get the uvalue identifying the menu choice.
    WIDGET_CONTROL, ev.id, GET_UVALUE=uval

    ;  Get the application state and current file.
    WIDGET_CONTROL, ev.top, GET_UVALUE=s
    WIDGET_CONTROL, (*s).wtable, GET_UVALUE=file

    case uval of
        'open': BEGIN
            ;
            ;  Open a file
            ;
            if size(file,/type) then path=file_dirname(file) else path=!dir
            file=dialog_pickfile(TITLE='Please select file to open this directory', path=path, $
                                 DIALOG_PARENT=ev.top)
            if (file[0] eq '') then return

            if n_elements(file) eq 1 then begin
                file = file[0]
                if file_test(file,/DIRECTORY) then dir = file $
                else dir=file_dirname(file,/MARK_DIR)
                files=file_search(dir+'*',/TEST_REGULAR)
                ;  Update the list with all the files in the directory
            endif else begin
                files = file
                file = file[0]
            endelse

            ;  Open and display the selected file
            if dicom_viewer_open_file(file, s) then begin
              WIDGET_CONTROL, (*s).wTree, SET_UVALUE=files
              void = dicom_viewer_populate_tree(s, file)
            endif

            dicom_viewer_update_sensitivity, s
        END

        'opendir': begin

            if size(file,/type) then path=file_dirname(file) else path=!dir
            dir = dialog_pickfile(title = 'Please select a directory to open.', $
                dialog_parent = ev.top, /directory, path = path)

            if dir ne '' then begin

                files = file_search(dir + '*')
                widget_control, (*s).wtree, set_uvalue = files

                widget_control, (*s).wtable, set_value=strarr(6,6)
                (*s).image->idlgrimage::setproperty, data=bytarr(2,2)
                (*s).view->setproperty, viewplane_rect=[0,0,2,2]
                (*s).image -> setproperty, nframes = 0
                (*s).win->draw
                widget_control, (*s).wexport, sensitive=0

                widget_control, ev.top, base_set_title = 'IDL Dicom Viewer'

                dicom_viewer_update_sensitivity, s

                if dicom_viewer_populate_tree(s, '') then $
                    widget_control, (*s).wtable, set_uvalue = files[0]

            endif


        end

        'export': BEGIN
            catch, err
            if (err eq 0) then begin
                outFile = dialog_pickfile(TITLE='Write DICOM tag info to text file', /WRITE, DIALOG_PARENT=ev.top)
                if outFile eq '' then return
                o = obj_new('IDLffDICOMEx',file,/non)
                void = o->EnumerateTags(FILENAME=outFile, /QUIET)
                catch, /CANCEL
            endif else begin
                catch, /CANCEL
                WIDGET_CONTROL, (*s).wtable, SET_VALUE=strarr(6,6)
                (*s).image->IDLgrImage::SetProperty, DATA=bytarr(2,2)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -