Commit 794ea5034b68ff1c8de8138d88d266bfd9bfbf85

Authored by Paulo Henrique Junqueira Amorim
Committed by GitHub
1 parent 335b3a7c
Exists in master

Micro ct (#40)

ADD: This branch is for InVesalius to read BMP, TIF, JPEG and PNG files.
invesalius/constants.py
... ... @@ -452,7 +452,7 @@ VTK_WARNING = 0
452 452 [ID_DICOM_IMPORT, ID_PROJECT_OPEN, ID_PROJECT_SAVE_AS, ID_PROJECT_SAVE,
453 453 ID_PROJECT_CLOSE, ID_PROJECT_INFO, ID_SAVE_SCREENSHOT, ID_DICOM_LOAD_NET,
454 454 ID_PRINT_SCREENSHOT, ID_IMPORT_OTHERS_FILES, ID_ANALYZE_IMPORT, ID_PREFERENCES,
455   -ID_DICOM_NETWORK] = [wx.NewId() for number in range(13)]
  455 +ID_DICOM_NETWORK, ID_TIFF_JPG_PNG] = [wx.NewId() for number in range(14)]
456 456 ID_EXIT = wx.ID_EXIT
457 457 ID_ABOUT = wx.ID_ABOUT
458 458  
... ...
invesalius/control.py
... ... @@ -35,8 +35,10 @@ import project as prj
35 35 import reader.analyze_reader as analyze
36 36 import reader.dicom_grouper as dg
37 37 import reader.dicom_reader as dcm
  38 +import reader.bitmap_reader as bmp
38 39 import session as ses
39 40  
  41 +
40 42 import utils
41 43 import gui.dialogs as dialogs
42 44 import subprocess
... ... @@ -74,13 +76,20 @@ class Controller():
74 76 'Save raycasting preset')
75 77 Publisher.subscribe(self.OnOpenDicomGroup,
76 78 'Open DICOM group')
  79 + Publisher.subscribe(self.OnOpenBitmapFiles,
  80 + 'Open bitmap files')
77 81 Publisher.subscribe(self.Progress, "Update dicom load")
  82 + Publisher.subscribe(self.Progress, "Update bitmap load")
78 83 Publisher.subscribe(self.OnLoadImportPanel, "End dicom load")
  84 + Publisher.subscribe(self.OnLoadImportBitmapPanel, "End bitmap load")
79 85 Publisher.subscribe(self.OnCancelImport, 'Cancel DICOM load')
  86 + Publisher.subscribe(self.OnCancelImportBitmap, 'Cancel bitmap load')
  87 +
80 88 Publisher.subscribe(self.OnShowDialogCloseProject, 'Close Project')
81 89 Publisher.subscribe(self.OnOpenProject, 'Open project')
82 90 Publisher.subscribe(self.OnOpenRecentProject, 'Open recent project')
83 91 Publisher.subscribe(self.OnShowAnalyzeFile, 'Show analyze dialog')
  92 + Publisher.subscribe(self.OnShowBitmapFile, 'Show bitmap dialog')
84 93  
85 94 Publisher.subscribe(self.ShowBooleanOpDialog, 'Show boolean dialog')
86 95  
... ... @@ -92,7 +101,9 @@ class Controller():
92 101 Publisher.sendMessage('Hide import panel')
93 102  
94 103  
95   -
  104 + def OnCancelImportBitmap(self, pubsub_evt):
  105 + #self.cancel_import = True
  106 + Publisher.sendMessage('Hide import bitmap panel')
96 107  
97 108 ###########################
98 109 ###########################
... ... @@ -119,9 +130,35 @@ class Controller():
119 130 self.LoadProject()
120 131 Publisher.sendMessage("Enable state project", True)
121 132  
122   -
  133 + def OnShowBitmapFile(self, pubsub_evt):
  134 + self.ShowDialogImportBitmapFile()
123 135 ###########################
124 136  
  137 + def ShowDialogImportBitmapFile(self):
  138 + # Offer to save current project if necessary
  139 + session = ses.Session()
  140 + st = session.project_status
  141 + if (st == const.PROJ_NEW) or (st == const.PROJ_CHANGE):
  142 + filename = session.project_path[1]
  143 + answer = dialog.SaveChangesDialog2(filename)
  144 + if answer:
  145 + self.ShowDialogSaveProject()
  146 + self.CloseProject()
  147 + #Publisher.sendMessage("Enable state project", False)
  148 + Publisher.sendMessage('Set project name')
  149 + Publisher.sendMessage("Stop Config Recording")
  150 + Publisher.sendMessage("Set slice interaction style", const.STATE_DEFAULT)
  151 +
  152 + # Import TIFF, BMP, JPEG or PNG
  153 + dirpath = dialog.ShowImportBitmapDirDialog()
  154 +
  155 + if dirpath and not os.listdir(dirpath):
  156 + dialog.ImportEmptyDirectory(dirpath)
  157 + elif dirpath:
  158 + self.StartImportBitmapPanel(dirpath)
  159 + # Publisher.sendMessage("Load data to import panel", dirpath)
  160 +
  161 +
125 162 def ShowDialogImportDirectory(self):
126 163 # Offer to save current project if necessary
127 164 session = ses.Session()
... ... @@ -291,6 +328,12 @@ class Controller():
291 328  
292 329 ###########################
293 330  
  331 + def StartImportBitmapPanel(self, path):
  332 + # retrieve DICOM files splited into groups
  333 + reader = bmp.ProgressBitmapReader()
  334 + reader.SetWindowEvent(self.frame)
  335 + reader.SetDirectoryPath(path)
  336 + Publisher.sendMessage('End busy cursor')
294 337  
295 338 def StartImportPanel(self, path):
296 339  
... ... @@ -324,6 +367,26 @@ class Controller():
324 367 Publisher.sendMessage('Show import panel')
325 368 Publisher.sendMessage("Show import panel in frame")
326 369  
  370 + def OnLoadImportBitmapPanel(self, evt):
  371 + data = evt.data
  372 + ok = self.LoadImportBitmapPanel(data)
  373 + if ok:
  374 + Publisher.sendMessage('Show import bitmap panel in frame')
  375 + #Publisher.sendMessage("Show import panel in frame")
  376 +
  377 + def LoadImportBitmapPanel(self, data):
  378 + #if patient_series and isinstance(patient_series, list):
  379 + #Publisher.sendMessage("Load import panel", patient_series)
  380 + #first_patient = patient_series[0]
  381 + #Publisher.sendMessage("Load bitmap preview", first_patient)
  382 + if data:
  383 + Publisher.sendMessage("Load import bitmap panel", data)
  384 +
  385 + return True
  386 + else:
  387 + dialog.ImportInvalidFiles()
  388 + return False
  389 +
327 390  
328 391 def LoadImportPanel(self, patient_series):
329 392 if patient_series and isinstance(patient_series, list):
... ... @@ -335,6 +398,9 @@ class Controller():
335 398 dialog.ImportInvalidFiles()
336 399 return False
337 400  
  401 +
  402 + #----------- to import by command line ---------------------------------------------------
  403 +
338 404 def OnImportMedicalImages(self, pubsub_evt):
339 405 directory = pubsub_evt.data
340 406 self.ImportMedicalImages(directory)
... ... @@ -358,6 +424,8 @@ class Controller():
358 424 self.LoadProject()
359 425 Publisher.sendMessage("Enable state project", True)
360 426  
  427 + #-------------------------------------------------------------------------------------
  428 +
361 429 def LoadProject(self):
362 430 proj = prj.Project()
363 431  
... ... @@ -401,9 +469,13 @@ class Controller():
401 469 Publisher.sendMessage('Show mask', (mask_index, True))
402 470 else:
403 471 mask_name = const.MASK_NAME_PATTERN % (1,)
404   - thresh = const.THRESHOLD_RANGE
405   - colour = const.MASK_COLOUR[0]
406 472  
  473 + if proj.modality != "UNKNOWN":
  474 + thresh = const.THRESHOLD_RANGE
  475 + else:
  476 + thresh = proj.threshold_range
  477 +
  478 + colour = const.MASK_COLOUR[0]
407 479 Publisher.sendMessage('Create new mask',
408 480 (mask_name, thresh, colour))
409 481  
... ... @@ -483,6 +555,138 @@ class Controller():
483 555 dirpath = session.CreateProject(filename)
484 556 #proj.SavePlistProject(dirpath, filename)
485 557  
  558 +
  559 + def CreateBitmapProject(self, bmp_data, rec_data, matrix, matrix_filename):
  560 + name_to_const = {"AXIAL":const.AXIAL,
  561 + "CORONAL":const.CORONAL,
  562 + "SAGITTAL":const.SAGITAL}
  563 +
  564 + name = rec_data[0]
  565 + orientation = rec_data[1]
  566 + sp_x = float(rec_data[2])
  567 + sp_y = float(rec_data[3])
  568 + sp_z = float(rec_data[4])
  569 + interval = int(rec_data[5])
  570 +
  571 + bits = bmp_data.GetFirstPixelSize()
  572 + sx, sy = size = bmp_data.GetFirstBitmapSize()
  573 +
  574 + proj = prj.Project()
  575 + proj.name = name
  576 + proj.modality = 'UNKNOWN'
  577 + proj.SetAcquisitionModality(proj.modality)
  578 + proj.matrix_shape = matrix.shape
  579 + proj.matrix_dtype = matrix.dtype.name
  580 + proj.matrix_filename = matrix_filename
  581 + #proj.imagedata = imagedata
  582 + #proj.dicom_sample = dicom
  583 + proj.original_orientation =\
  584 + name_to_const[orientation.upper()]
  585 + proj.window = float(matrix.max())
  586 + proj.level = float(matrix.max()/2)
  587 +
  588 + proj.threshold_range = int(matrix.min()), int(matrix.max())
  589 + #const.THRESHOLD_RANGE = proj.threshold_range
  590 +
  591 + proj.spacing = self.Slice.spacing
  592 +
  593 + ######
  594 + session = ses.Session()
  595 + filename = proj.name+".inv3"
  596 +
  597 + filename = filename.replace("/", "") #Fix problem case other/Skull_DICOM
  598 +
  599 + dirpath = session.CreateProject(filename)
  600 +
  601 + def OnOpenBitmapFiles(self, pubsub_evt):
  602 + rec_data = pubsub_evt.data
  603 + bmp_data = bmp.BitmapData()
  604 + matrix, matrix_filename = self.OpenBitmapFiles(bmp_data, rec_data)
  605 +
  606 + self.CreateBitmapProject(bmp_data, rec_data, matrix, matrix_filename)
  607 +
  608 + self.LoadProject()
  609 + Publisher.sendMessage("Enable state project", True)
  610 +
  611 +
  612 + def OpenBitmapFiles(self, bmp_data, rec_data):
  613 +
  614 + if bmp_data.IsAllBitmapSameSize():
  615 +
  616 + name = rec_data[0]
  617 + orientation = rec_data[1]
  618 + sp_x = float(rec_data[2])
  619 + sp_y = float(rec_data[3])
  620 + sp_z = float(rec_data[4])
  621 + interval = int(rec_data[5])
  622 +
  623 + interval += 1
  624 +
  625 + filelist = bmp_data.GetOnlyBitmapPath()[::interval]
  626 + bits = bmp_data.GetFirstPixelSize()
  627 +
  628 + sx, sy = size = bmp_data.GetFirstBitmapSize()
  629 + n_slices = len(filelist)
  630 + resolution_percentage = utils.calculate_resizing_tofitmemory(int(sx), int(sy), n_slices, bits/8)
  631 +
  632 + zspacing = sp_z * interval
  633 + xyspacing = (sp_y, sp_x)
  634 +
  635 + if resolution_percentage < 1.0:
  636 +
  637 + re_dialog = dialog.ResizeImageDialog()
  638 + re_dialog.SetValue(int(resolution_percentage*100))
  639 + re_dialog_value = re_dialog.ShowModal()
  640 + re_dialog.Close()
  641 +
  642 + if re_dialog_value == wx.ID_OK:
  643 + percentage = re_dialog.GetValue()
  644 + resolution_percentage = percentage / 100.0
  645 + else:
  646 + return
  647 +
  648 + xyspacing = xyspacing[0] / resolution_percentage, xyspacing[1] / resolution_percentage
  649 +
  650 +
  651 +
  652 + self.matrix, scalar_range, self.filename = image_utils.bitmap2memmap(filelist, size,
  653 + orientation, (sp_z, sp_y, sp_x),resolution_percentage)
  654 +
  655 +
  656 + self.Slice = sl.Slice()
  657 + self.Slice.matrix = self.matrix
  658 + self.Slice.matrix_filename = self.filename
  659 +
  660 + if orientation == 'AXIAL':
  661 + self.Slice.spacing = xyspacing[0], xyspacing[1], zspacing
  662 + elif orientation == 'CORONAL':
  663 + self.Slice.spacing = xyspacing[0], zspacing, xyspacing[1]
  664 + elif orientation == 'SAGITTAL':
  665 + self.Slice.spacing = zspacing, xyspacing[1], xyspacing[0]
  666 +
  667 + # 1(a): Fix gantry tilt, if any
  668 + #tilt_value = dicom.acquisition.tilt
  669 + #if (tilt_value) and (gui):
  670 + # # Tell user gantry tilt and fix, according to answer
  671 + # message = _("Fix gantry tilt applying the degrees below")
  672 + # value = -1*tilt_value
  673 + # tilt_value = dialog.ShowNumberDialog(message, value)
  674 + # image_utils.FixGantryTilt(self.matrix, self.Slice.spacing, tilt_value)
  675 + #elif (tilt_value) and not (gui):
  676 + # tilt_value = -1*tilt_value
  677 + # image_utils.FixGantryTilt(self.matrix, self.Slice.spacing, tilt_value)
  678 +
  679 + self.Slice.window_level = float(self.matrix.max()/2)
  680 + self.Slice.window_width = float(self.matrix.max())
  681 +
  682 + scalar_range = int(self.matrix.min()), int(self.matrix.max())
  683 + Publisher.sendMessage('Update threshold limits list', scalar_range)
  684 +
  685 + return self.matrix, self.filename#, dicom
  686 +
  687 + else:
  688 + print "Error: All slices must be of the same size."
  689 +
486 690 def OnOpenDicomGroup(self, pubsub_evt):
487 691 group, interval, file_range = pubsub_evt.data
488 692 matrix, matrix_filename, dicom = self.OpenDicomGroup(group, interval, file_range, gui=True)
... ...
invesalius/data/imagedata_utils.py
... ... @@ -32,7 +32,9 @@ from vtk.util import numpy_support
32 32  
33 33 import constants as const
34 34 from data import vtk_utils
  35 +from reader import bitmap_reader
35 36 import utils
  37 +import converters
36 38  
37 39 # TODO: Test cases which are originally in sagittal/coronal orientation
38 40 # and have gantry
... ... @@ -416,6 +418,90 @@ class ImageCreator:
416 418  
417 419 return imagedata
418 420  
  421 +def bitmap2memmap(files, slice_size, orientation, spacing, resolution_percentage):
  422 + """
  423 + From a list of dicom files it creates memmap file in the temp folder and
  424 + returns it and its related filename.
  425 + """
  426 + message = _("Generating multiplanar visualization...")
  427 + update_progress= vtk_utils.ShowProgress(len(files) - 1, dialog_type = "ProgressDialog")
  428 +
  429 + temp_file = tempfile.mktemp()
  430 +
  431 + if orientation == 'SAGITTAL':
  432 + if resolution_percentage == 1.0:
  433 + shape = slice_size[0], slice_size[1], len(files)
  434 + else:
  435 + shape = math.ceil(slice_size[0]*resolution_percentage),\
  436 + math.ceil(slice_size[1]*resolution_percentage), len(files)
  437 +
  438 + elif orientation == 'CORONAL':
  439 + if resolution_percentage == 1.0:
  440 + shape = slice_size[1], len(files), slice_size[0]
  441 + else:
  442 + shape = math.ceil(slice_size[1]*resolution_percentage), len(files),\
  443 + math.ceil(slice_size[0]*resolution_percentage)
  444 + else:
  445 + if resolution_percentage == 1.0:
  446 + shape = len(files), slice_size[1], slice_size[0]
  447 + else:
  448 + shape = len(files), math.ceil(slice_size[1]*resolution_percentage),\
  449 + math.ceil(slice_size[0]*resolution_percentage)
  450 +
  451 + matrix = numpy.memmap(temp_file, mode='w+', dtype='int16', shape=shape)
  452 + cont = 0
  453 + max_scalar = None
  454 + min_scalar = None
  455 +
  456 + for n, f in enumerate(files):
  457 + image_as_array = bitmap_reader.ReadBitmap(f)
  458 +
  459 + image = converters.to_vtk(image_as_array, spacing=spacing,\
  460 + slice_number=1, orientation=orientation.upper())
  461 +
  462 + if resolution_percentage != 1.0:
  463 +
  464 +
  465 + image_resized = ResampleImage2D(image, px=None, py=None,\
  466 + resolution_percentage = resolution_percentage, update_progress = None)
  467 +
  468 + image = image_resized
  469 +
  470 + min_aux, max_aux = image.GetScalarRange()
  471 + if min_scalar is None or min_aux < min_scalar:
  472 + min_scalar = min_aux
  473 +
  474 + if max_scalar is None or max_aux > max_scalar:
  475 + max_scalar = max_aux
  476 +
  477 + array = numpy_support.vtk_to_numpy(image.GetPointData().GetScalars())
  478 + array = array.astype("int16")
  479 +
  480 + array = image_as_array
  481 +
  482 + if orientation == 'CORONAL':
  483 + array.shape = matrix.shape[0], matrix.shape[2]
  484 + matrix[:, n, :] = array
  485 + elif orientation == 'SAGITTAL':
  486 + array.shape = matrix.shape[0], matrix.shape[1]
  487 + # TODO: Verify if it's necessary to add the slices swapped only in
  488 + # sagittal rmi or only in # Rasiane's case or is necessary in all
  489 + # sagittal cases.
  490 + matrix[:, :, n] = array
  491 + else:
  492 + print array.shape, matrix.shape
  493 + array.shape = matrix.shape[1], matrix.shape[2]
  494 + matrix[n] = array
  495 + update_progress(cont,message)
  496 + cont += 1
  497 +
  498 + matrix.flush()
  499 + scalar_range = min_scalar, max_scalar
  500 +
  501 + return matrix, scalar_range, temp_file
  502 +
  503 +
  504 +
419 505 def dcm2memmap(files, slice_size, orientation, resolution_percentage):
420 506 """
421 507 From a list of dicom files it creates memmap file in the temp folder and
... ... @@ -462,7 +548,6 @@ def dcm2memmap(files, slice_size, orientation, resolution_percentage):
462 548 resolution_percentage = resolution_percentage, update_progress = None)
463 549  
464 550 image = image_resized
465   - print ">>>>>>>>>", image.GetDimensions()
466 551  
467 552 min_aux, max_aux = image.GetScalarRange()
468 553 if min_scalar is None or min_aux < min_scalar:
... ... @@ -482,7 +567,6 @@ def dcm2memmap(files, slice_size, orientation, resolution_percentage):
482 567 # sagittal cases.
483 568 matrix[:, :, n] = array
484 569 else:
485   - print array.shape, matrix.shape
486 570 array.shape = matrix.shape[1], matrix.shape[2]
487 571 matrix[n] = array
488 572 update_progress(cont,message)
... ...
invesalius/gui/bitmap_preview_panel.py 0 → 100644
... ... @@ -0,0 +1,903 @@
  1 +import wx
  2 +import vtk
  3 +import vtkgdcm
  4 +import time
  5 +
  6 +from vtk.util import numpy_support
  7 +from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor
  8 +from wx.lib.pubsub import pub as Publisher
  9 +
  10 +import constants as const
  11 +import data.vtk_utils as vtku
  12 +from data import converters
  13 +from reader import bitmap_reader
  14 +import utils
  15 +
  16 +NROWS = 3
  17 +NCOLS = 6
  18 +NUM_PREVIEWS = NCOLS*NROWS
  19 +PREVIEW_WIDTH = 70
  20 +PREVIEW_HEIGTH = 70
  21 +
  22 +PREVIEW_BACKGROUND = (255, 255, 255) # White
  23 +
  24 +STR_SIZE = _("Image size: %d x %d")
  25 +STR_SPC = _("Spacing: %.2f")
  26 +STR_LOCAL = _("Location: %.2f")
  27 +STR_PATIENT = "%s\n%s"
  28 +STR_ACQ = _("%s %s\nMade in InVesalius")
  29 +
  30 +myEVT_PREVIEW_CLICK = wx.NewEventType()
  31 +EVT_PREVIEW_CLICK = wx.PyEventBinder(myEVT_PREVIEW_CLICK, 1)
  32 +
  33 +myEVT_PREVIEW_DBLCLICK = wx.NewEventType()
  34 +EVT_PREVIEW_DBLCLICK = wx.PyEventBinder(myEVT_PREVIEW_DBLCLICK, 1)
  35 +
  36 +myEVT_CLICK_SLICE = wx.NewEventType()
  37 +# This event occurs when the user select a preview
  38 +EVT_CLICK_SLICE = wx.PyEventBinder(myEVT_CLICK_SLICE, 1)
  39 +
  40 +myEVT_CLICK_SERIE = wx.NewEventType()
  41 +# This event occurs when the user select a preview
  42 +EVT_CLICK_SERIE = wx.PyEventBinder(myEVT_CLICK_SERIE, 1)
  43 +
  44 +myEVT_CLICK = wx.NewEventType()
  45 +EVT_CLICK = wx.PyEventBinder(myEVT_CLICK, 1)
  46 +
  47 +
  48 +class SelectionEvent(wx.PyCommandEvent):
  49 + pass
  50 +
  51 +
  52 +class PreviewEvent(wx.PyCommandEvent):
  53 + def __init__(self , evtType, id):
  54 + super(PreviewEvent, self).__init__(evtType, id)
  55 +
  56 + def GetSelectID(self):
  57 + return self.SelectedID
  58 +
  59 + def SetSelectedID(self, id):
  60 + self.SelectedID = id
  61 +
  62 + def GetItemData(self):
  63 + return self.data
  64 +
  65 + def GetPressedShift(self):
  66 + return self.pressed_shift
  67 +
  68 + def SetItemData(self, data):
  69 + self.data = data
  70 +
  71 + def SetShiftStatus(self, status):
  72 + self.pressed_shift = status
  73 +
  74 +
  75 +class SerieEvent(PreviewEvent):
  76 + def __init__(self , evtType, id):
  77 + super(SerieEvent, self).__init__(evtType, id)
  78 +
  79 +
  80 +class BitmapInfo(object):
  81 + """
  82 + Keep the informations and the image used by preview.
  83 + """
  84 + def __init__(self, data):
  85 + #self.id = id
  86 + self.id = data[7]
  87 + self.title = data[6]
  88 + self.data = data
  89 + self.pos = data[8]
  90 + #self.subtitle = subtitle
  91 + self._preview = None
  92 + self.selected = False
  93 + #self.filename = ""
  94 + self.thumbnail_path = data[1]
  95 +
  96 + @property
  97 + def preview(self):
  98 +
  99 + if not self._preview:
  100 + bmp = wx.Bitmap(self.thumbnail_path, wx.BITMAP_TYPE_PNG)
  101 + self._preview = bmp.ConvertToImage()
  102 + return self._preview
  103 +
  104 + def release_thumbnail(self):
  105 + self._preview = None
  106 +
  107 +class DicomPaintPanel(wx.Panel):
  108 + def __init__(self, parent):
  109 + super(DicomPaintPanel, self).__init__(parent)
  110 + self._bind_events()
  111 + self.image = None
  112 + self.last_size = (10,10)
  113 +
  114 + def _bind_events(self):
  115 + self.Bind(wx.EVT_PAINT, self.OnPaint)
  116 + self.Bind(wx.EVT_SIZE, self.OnSize)
  117 +
  118 + def _build_bitmap(self, image):
  119 + bmp = wx.BitmapFromImage(image)
  120 + return bmp
  121 +
  122 + def _image_resize(self, image):
  123 + self.Update()
  124 + self.Layout()
  125 + new_size = self.GetSize()
  126 + # This is necessary due to darwin problem #
  127 + if new_size != (0,0):
  128 + self.last_size = new_size
  129 + return image.Scale(*new_size)
  130 + else:
  131 + return image.Scale(*self.last_size)
  132 +
  133 + def SetImage(self, image):
  134 + self.image = image
  135 + r_img = self._image_resize(image)
  136 + self.bmp = self._build_bitmap(r_img)
  137 + self.Refresh()
  138 +
  139 + def OnPaint(self, evt):
  140 + if self.image:
  141 + dc = wx.PaintDC(self)
  142 + dc.Clear()
  143 + dc.DrawBitmap(self.bmp, 0, 0)
  144 +
  145 + def OnSize(self, evt):
  146 + if self.image:
  147 + self.bmp = self._build_bitmap(self._image_resize(self.image))
  148 + self.Refresh()
  149 + evt.Skip()
  150 +
  151 +
  152 +class Preview(wx.Panel):
  153 + """
  154 + The little previews.
  155 + """
  156 + def __init__(self, parent):
  157 + super(Preview, self).__init__(parent)
  158 + # Will it be white?
  159 + self.select_on = False
  160 + self.bitmap_info = None
  161 + self._init_ui()
  162 + self._bind_events()
  163 +
  164 + def _init_ui(self):
  165 + self.SetBackgroundColour(PREVIEW_BACKGROUND)
  166 +
  167 + self.title = wx.StaticText(self, -1, _("Image"))
  168 + self.subtitle = wx.StaticText(self, -1, _("Image"))
  169 + self.image_viewer = DicomPaintPanel(self)
  170 +
  171 + self.sizer = wx.BoxSizer(wx.VERTICAL)
  172 + self.sizer.Add(self.title, 0,
  173 + wx.ALIGN_CENTER_HORIZONTAL)
  174 + self.sizer.Add(self.subtitle, 0,
  175 + wx.ALIGN_CENTER_HORIZONTAL)
  176 + self.sizer.Add(self.image_viewer, 1, wx.ALIGN_CENTRE_HORIZONTAL \
  177 + | wx.SHAPED | wx.ALL, 5)
  178 + self.sizer.Fit(self)
  179 +
  180 + self.SetSizer(self.sizer)
  181 +
  182 + self.Layout()
  183 + self.Update()
  184 + self.Fit()
  185 + self.SetAutoLayout(1)
  186 +
  187 + def _bind_events(self):
  188 + self.Bind( wx.EVT_LEFT_DCLICK, self.OnDClick)
  189 + #self.interactor.Bind( wx.EVT_LEFT_DCLICK, self.OnDClick)
  190 + #self.panel.Bind( wx.EVT_LEFT_DCLICK, self.OnDClick)
  191 + #self.title.Bind( wx.EVT_LEFT_DCLICK, self.OnDClick)
  192 + #self.subtitle.Bind( wx.EVT_LEFT_DCLICK, self.OnDClick)
  193 +
  194 + self.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  195 + #self.interactor.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  196 + #self.panel.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  197 + #self.title.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  198 + #self.subtitle.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  199 +
  200 + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  201 + #self.interactor.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  202 + #self.panel.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  203 + #self.title.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  204 + #self.subtitle.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  205 +
  206 + self.Bind(wx.EVT_LEFT_DOWN, self.OnSelect)
  207 + self.title.Bind(wx.EVT_LEFT_DOWN, self.OnSelect)
  208 + self.subtitle.Bind(wx.EVT_LEFT_DOWN, self.OnSelect)
  209 + self.image_viewer.Bind(wx.EVT_LEFT_DOWN, self.OnSelect)
  210 +
  211 + #self.Bind(wx.EVT_SIZE, self.OnSize)
  212 +
  213 + def SetBitmapToPreview(self, bitmap_info):
  214 + """
  215 + Set a dicom to preview.
  216 + """
  217 +
  218 + """
  219 + self.dicom_info = dicom_info
  220 + self.SetTitle(dicom_info.title)
  221 + self.SetSubtitle(dicom_info.subtitle)
  222 + self.ID = dicom_info.id
  223 + dicom_info.size = self.image_viewer.GetSize()
  224 + image = dicom_info.preview
  225 + self.image_viewer.SetImage(image)
  226 + self.data = dicom_info.id
  227 + self.select_on = dicom_info.selected
  228 + self.Select()
  229 + self.Update()
  230 + """
  231 +
  232 +
  233 +
  234 + if self.bitmap_info:
  235 + self.bitmap_info.release_thumbnail()
  236 +
  237 + self.bitmap_info = bitmap_info
  238 + self.SetTitle(self.bitmap_info.title[-10:])
  239 + self.SetSubtitle('')
  240 +
  241 + ##self.ID = bitmap_info.id
  242 + ##bitmap_info.size = self.image_viewer.GetSize()
  243 + image = self.bitmap_info.preview
  244 +
  245 + self.image_viewer.SetImage(image)
  246 + #self.data = bitmap_info.id
  247 + self.select_on = bitmap_info.selected
  248 + self.Select()
  249 + self.Update()
  250 +
  251 + def SetTitle(self, title):
  252 + self.title.SetLabel(title)
  253 +
  254 + def SetSubtitle(self, subtitle):
  255 + self.subtitle.SetLabel(subtitle)
  256 +
  257 + def OnEnter(self, evt):
  258 + if not self.select_on:
  259 + #c = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DHILIGHT)
  260 + c = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)
  261 + self.SetBackgroundColour(c)
  262 +
  263 + def OnLeave(self, evt):
  264 + if not self.select_on:
  265 + c = (PREVIEW_BACKGROUND)
  266 + self.SetBackgroundColour(c)
  267 +
  268 + def OnSelect(self, evt):
  269 +
  270 + shift_pressed = False
  271 + if evt.m_shiftDown:
  272 + shift_pressed = True
  273 +
  274 + dicom_id = self.bitmap_info.id
  275 + self.select_on = True
  276 + self.bitmap_info.selected = True
  277 + self.Select()
  278 +
  279 + # Generating a EVT_PREVIEW_CLICK event
  280 + my_evt = SerieEvent(myEVT_PREVIEW_CLICK, self.GetId())
  281 +
  282 + my_evt.SetSelectedID(self.bitmap_info.id)
  283 + my_evt.SetItemData(self.bitmap_info.data)
  284 +
  285 + my_evt.SetShiftStatus(shift_pressed)
  286 + my_evt.SetEventObject(self)
  287 + self.GetEventHandler().ProcessEvent(my_evt)
  288 +
  289 + Publisher.sendMessage('Set bitmap in preview panel', self.bitmap_info.pos)
  290 +
  291 + evt.Skip()
  292 +
  293 +
  294 + def OnSize(self, evt):
  295 + if self.bitmap_info:
  296 + self.SetBitmapToPreview(self.bitmap_info)
  297 + evt.Skip()
  298 +
  299 + def Select(self, on=True):
  300 + if self.select_on:
  301 + c = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)
  302 + else:
  303 + c = (PREVIEW_BACKGROUND)
  304 + self.SetBackgroundColour(c)
  305 + self.Refresh()
  306 +
  307 + def OnDClick(self, evt):
  308 + my_evt = SerieEvent(myEVT_PREVIEW_DBLCLICK, self.GetId())
  309 + my_evt.SetSelectedID(self.bitmap_info.id)
  310 + my_evt.SetItemData(self.bitmap_info.data)
  311 + my_evt.SetEventObject(self)
  312 + self.GetEventHandler().ProcessEvent(my_evt)
  313 + evt.Skip()
  314 +
  315 +
  316 +class BitmapPreviewSeries(wx.Panel):
  317 + """A dicom series preview panel"""
  318 + def __init__(self, parent):
  319 + super(BitmapPreviewSeries, self).__init__(parent)
  320 + # TODO: 3 pixels between the previews is a good idea?
  321 + # I have to test.
  322 + #self.sizer = wx.BoxSizer(wx.HORIZONTAL)
  323 + #self.SetSizer(self.sizer)
  324 + self.displayed_position = 0
  325 + self.nhidden_last_display = 0
  326 + self.selected_dicom = None
  327 + self.selected_panel = None
  328 + self._init_ui()
  329 +
  330 + def _init_ui(self):
  331 + scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL)
  332 + self.scroll = scroll
  333 +
  334 + self.grid = wx.GridSizer(rows=NROWS, cols=NCOLS, vgap=3, hgap=3)
  335 +
  336 + sizer = wx.BoxSizer(wx.HORIZONTAL)
  337 + sizer.AddSizer(self.grid, 1, wx.EXPAND|wx.GROW|wx.ALL, 2)
  338 +
  339 + background_sizer = wx.BoxSizer(wx.HORIZONTAL)
  340 + background_sizer.AddSizer(sizer, 1, wx.EXPAND|wx.GROW|wx.ALL, 2)
  341 + background_sizer.Add(scroll, 0, wx.EXPAND|wx.GROW)
  342 + self.SetSizer(background_sizer)
  343 + background_sizer.Fit(self)
  344 +
  345 + self.Layout()
  346 + self.Update()
  347 + self.SetAutoLayout(1)
  348 +
  349 + self.sizer = background_sizer
  350 +
  351 + self._Add_Panels_Preview()
  352 + self._bind_events()
  353 +
  354 + def _Add_Panels_Preview(self):
  355 + self.previews = []
  356 + for i in xrange(NROWS):
  357 + for j in xrange(NCOLS):
  358 + p = Preview(self)
  359 + p.Bind(EVT_PREVIEW_CLICK, self.OnSelect)
  360 + #if (i == j == 0):
  361 + #self._show_shadow(p)
  362 + #p.Hide()
  363 + self.previews.append(p)
  364 + self.grid.Add(p, 1, flag=wx.EXPAND)
  365 +
  366 + #def _show_shadow(self, preview):
  367 + # preview.ShowShadow()
  368 +
  369 + def _bind_events(self):
  370 + # When the user scrolls the window
  371 + self.Bind(wx.EVT_SCROLL, self.OnScroll)
  372 + self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
  373 +
  374 + def OnSelect(self, evt):
  375 + my_evt = SerieEvent(myEVT_CLICK_SERIE, self.GetId())
  376 + my_evt.SetSelectedID(evt.GetSelectID())
  377 + my_evt.SetItemData(evt.GetItemData())
  378 +
  379 + if self.selected_dicom:
  380 + self.selected_dicom.selected = self.selected_dicom is \
  381 + evt.GetEventObject().bitmap_info
  382 + self.selected_panel.select_on = self.selected_panel is evt.GetEventObject()
  383 + self.selected_panel.Select()
  384 + self.selected_panel = evt.GetEventObject()
  385 + self.selected_dicom = self.selected_panel.bitmap_info
  386 + self.GetEventHandler().ProcessEvent(my_evt)
  387 + evt.Skip()
  388 +
  389 + def SetBitmapFiles(self, data):
  390 + #self.files = data
  391 + self.files = []
  392 +
  393 + bitmap = bitmap_reader.BitmapData()
  394 + bitmap.SetData(data)
  395 +
  396 + pos = 0
  397 + for d in data:
  398 + d.append(pos)
  399 + info = BitmapInfo(d)
  400 + self.files.append(info)
  401 + pos += 1
  402 +
  403 + scroll_range = len(self.files)/NCOLS
  404 + if scroll_range * NCOLS < len(self.files):
  405 + scroll_range +=1
  406 + self.scroll.SetScrollbar(0, NROWS, scroll_range, NCOLS)
  407 + self._display_previews()
  408 +
  409 +
  410 + #def SetPatientGroups(self, patient):
  411 + # self.files = []
  412 + # self.displayed_position = 0
  413 + # self.nhidden_last_display = 0
  414 + # group_list = patient.GetGroups()
  415 + # self.group_list = group_list
  416 + # n = 0
  417 + # for group in group_list:
  418 + # info = BitmapInfo((group.dicom.patient.id,
  419 + # group.dicom.acquisition.serie_number),
  420 + # group.dicom,
  421 + # group.title,
  422 + # _("%d images") %(group.nslices))
  423 + # self.files.append(info)
  424 + # n+=1
  425 + # scroll_range = len(self.files)/NCOLS
  426 + # if scroll_range * NCOLS < len(self.files):
  427 + # scroll_range +=1
  428 + # self.scroll.SetScrollbar(0, NROWS, scroll_range, NCOLS)
  429 + # self._display_previews()
  430 +
  431 +
  432 + def _display_previews(self):
  433 + initial = self.displayed_position * NCOLS
  434 + final = initial + NUM_PREVIEWS
  435 + if len(self.files) < final:
  436 + for i in xrange(final-len(self.files)):
  437 + try:
  438 + self.previews[-i-1].Hide()
  439 + except IndexError:
  440 + utils.debug("doesn't exist!")
  441 + pass
  442 + self.nhidden_last_display = final-len(self.files)
  443 + else:
  444 + if self.nhidden_last_display:
  445 + for i in xrange(self.nhidden_last_display):
  446 + try:
  447 + self.previews[-i-1].Show()
  448 + except IndexError:
  449 + utils.debug("doesn't exist!")
  450 + pass
  451 + self.nhidden_last_display = 0
  452 +
  453 + for f, p in zip(self.files[initial:final], self.previews):
  454 + p.SetBitmapToPreview(f)
  455 + if f.selected:
  456 + self.selected_panel = p
  457 +
  458 + for f, p in zip(self.files[initial:final], self.previews):
  459 + p.Show()
  460 +
  461 +
  462 + def OnScroll(self, evt=None):
  463 + if evt:
  464 + if self.displayed_position != evt.GetPosition():
  465 + self.displayed_position = evt.GetPosition()
  466 + else:
  467 + if self.displayed_position != self.scroll.GetThumbPosition():
  468 + self.displayed_position = self.scroll.GetThumbPosition()
  469 + self._display_previews()
  470 +
  471 + def OnWheel(self, evt):
  472 + d = evt.GetWheelDelta() / evt.GetWheelRotation()
  473 + self.scroll.SetThumbPosition(self.scroll.GetThumbPosition() - d)
  474 + self.OnScroll()
  475 +
  476 +
  477 +class SingleImagePreview(wx.Panel):
  478 + def __init__(self, parent):
  479 + wx.Panel.__init__(self, parent, -1)
  480 + self.actor = None
  481 + self.__init_gui()
  482 + self.__init_vtk()
  483 + self.__bind_evt_gui()
  484 + self.__bind_pubsub()
  485 + self.dicom_list = []
  486 + self.nimages = 1
  487 + self.current_index = 0
  488 + self.window_width = const.WINDOW_LEVEL[_("Bone")][0]
  489 + self.window_level = const.WINDOW_LEVEL[_("Bone")][1]
  490 +
  491 + def __init_vtk(self):
  492 + text_image_size = vtku.Text()
  493 + text_image_size.SetPosition(const.TEXT_POS_LEFT_UP)
  494 + text_image_size.SetValue("")
  495 + text_image_size.SetSize(const.TEXT_SIZE_SMALL)
  496 + self.text_image_size = text_image_size
  497 +
  498 + text_image_location = vtku.Text()
  499 + text_image_location.SetVerticalJustificationToBottom()
  500 + text_image_location.SetPosition(const.TEXT_POS_LEFT_DOWN)
  501 + text_image_location.SetValue("")
  502 + text_image_location.SetSize(const.TEXT_SIZE_SMALL)
  503 + self.text_image_location = text_image_location
  504 +
  505 + text_patient = vtku.Text()
  506 + text_patient.SetJustificationToRight()
  507 + text_patient.SetPosition(const.TEXT_POS_RIGHT_UP)
  508 + text_patient.SetValue("")
  509 + text_patient.SetSize(const.TEXT_SIZE_SMALL)
  510 + self.text_patient = text_patient
  511 +
  512 + text_acquisition = vtku.Text()
  513 + text_acquisition.SetJustificationToRight()
  514 + text_acquisition.SetVerticalJustificationToBottom()
  515 + text_acquisition.SetPosition(const.TEXT_POS_RIGHT_DOWN)
  516 + text_acquisition.SetValue("")
  517 + text_acquisition.SetSize(const.TEXT_SIZE_SMALL)
  518 + self.text_acquisition = text_acquisition
  519 +
  520 + renderer = vtk.vtkRenderer()
  521 + renderer.AddActor(text_image_size.actor)
  522 + renderer.AddActor(text_image_location.actor)
  523 + renderer.AddActor(text_patient.actor)
  524 + renderer.AddActor(text_acquisition.actor)
  525 + self.renderer = renderer
  526 +
  527 + style = vtk.vtkInteractorStyleImage()
  528 +
  529 + interactor = wxVTKRenderWindowInteractor(self.panel, -1,
  530 + size=wx.Size(340,340))
  531 + interactor.GetRenderWindow().AddRenderer(renderer)
  532 + interactor.SetInteractorStyle(style)
  533 + interactor.Render()
  534 + self.interactor = interactor
  535 +
  536 + sizer = wx.BoxSizer(wx.VERTICAL)
  537 + sizer.Add(interactor, 1, wx.GROW|wx.EXPAND)
  538 + sizer.Fit(self.panel)
  539 + self.panel.SetSizer(sizer)
  540 + self.Layout()
  541 + self.Update()
  542 +
  543 + def __init_gui(self):
  544 + self.panel = wx.Panel(self, -1)
  545 +
  546 + slider = wx.Slider(self,
  547 + id=-1,
  548 + value=0,
  549 + minValue=0,
  550 + maxValue=99,
  551 + style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS)
  552 + slider.SetWindowVariant(wx.WINDOW_VARIANT_SMALL)
  553 + slider.SetTickFreq(1, 1)
  554 + self.slider = slider
  555 +
  556 + checkbox = wx.CheckBox(self, -1, _("Auto-play"))
  557 + self.checkbox = checkbox
  558 +
  559 + in_sizer = wx.BoxSizer(wx.HORIZONTAL)
  560 + in_sizer.Add(slider, 1, wx.GROW|wx.EXPAND)
  561 + in_sizer.Add(checkbox, 0)
  562 +
  563 + sizer = wx.BoxSizer(wx.VERTICAL)
  564 + sizer.Add(self.panel, 20, wx.GROW|wx.EXPAND)
  565 + sizer.Add(in_sizer, 1, wx.GROW|wx.EXPAND)
  566 + sizer.Fit(self)
  567 +
  568 + self.SetSizer(sizer)
  569 + self.Layout()
  570 + self.Update()
  571 + self.SetAutoLayout(1)
  572 +
  573 + def __bind_evt_gui(self):
  574 + self.slider.Bind(wx.EVT_SLIDER, self.OnSlider)
  575 + self.checkbox.Bind(wx.EVT_CHECKBOX, self.OnCheckBox)
  576 +
  577 + def __bind_pubsub(self):
  578 + Publisher.subscribe(self.ShowBitmapByPosition, 'Set bitmap in preview panel')
  579 +
  580 + def ShowBitmapByPosition(self, evt):
  581 + pos = evt.data
  582 + self.ShowSlice(pos)
  583 +
  584 +
  585 + def OnSlider(self, evt):
  586 + pos = evt.GetInt()
  587 + self.ShowSlice(pos)
  588 + evt.Skip()
  589 +
  590 + def OnCheckBox(self, evt):
  591 + self.ischecked = evt.IsChecked()
  592 + if evt.IsChecked():
  593 + wx.CallAfter(self.OnRun)
  594 + evt.Skip()
  595 +
  596 + def OnRun(self):
  597 + pos = self.slider.GetValue()
  598 + pos += 1
  599 + if not (self.nimages- pos):
  600 + pos = 0
  601 + self.slider.SetValue(pos)
  602 + self.ShowSlice(pos)
  603 + time.sleep(0.2)
  604 + if self.ischecked:
  605 + try:
  606 + wx.Yield()
  607 + #TODO: temporary fix necessary in the Windows XP 64 Bits
  608 + #BUG in wxWidgets http://trac.wxwidgets.org/ticket/10896
  609 + except(wx._core.PyAssertionError):
  610 + utils.debug("wx._core.PyAssertionError")
  611 + finally:
  612 + wx.CallAfter(self.OnRun)
  613 +
  614 + def SetBitmapFiles(self, data):
  615 + #self.dicom_list = group.GetHandSortedList()
  616 + self.bitmap_list = data
  617 + self.current_index = 0
  618 + self.nimages = len(data)
  619 + # GUI
  620 + self.slider.SetMax(self.nimages-1)
  621 + self.slider.SetValue(0)
  622 + self.ShowSlice()
  623 +
  624 + def ShowSlice(self, index = 0):
  625 + bitmap = self.bitmap_list[index]
  626 +
  627 + # UPDATE GUI
  628 + ## Text related to size
  629 + value = STR_SIZE %(bitmap[3], bitmap[4])
  630 + self.text_image_size.SetValue(value)
  631 +
  632 + value1 = ''
  633 + value2 = ''
  634 +
  635 + value = "%s\n%s" %(value1, value2)
  636 + self.text_image_location.SetValue(value)
  637 +
  638 +
  639 + #self.text_patient.SetValue(value)
  640 + self.text_patient.SetValue('')
  641 +
  642 + #self.text_acquisition.SetValue(value)
  643 + self.text_acquisition.SetValue('')
  644 +
  645 +
  646 +
  647 + n_array = bitmap_reader.ReadBitmap(bitmap[0])
  648 +
  649 + image = converters.to_vtk(n_array, spacing=(1,1,1),\
  650 + slice_number=1, orientation="AXIAL")
  651 +
  652 +
  653 + # ADJUST CONTRAST
  654 + window_level = n_array.max()/2
  655 + window_width = n_array.max()
  656 +
  657 + colorer = vtk.vtkImageMapToWindowLevelColors()
  658 + colorer.SetInputData(image)
  659 + colorer.SetWindow(float(window_width))
  660 + colorer.SetLevel(float(window_level))
  661 + colorer.Update()
  662 +
  663 + if self.actor is None:
  664 + self.actor = vtk.vtkImageActor()
  665 + self.renderer.AddActor(self.actor)
  666 +
  667 + # PLOT IMAGE INTO VIEWER
  668 + self.actor.SetInputData(colorer.GetOutput())
  669 + self.renderer.ResetCamera()
  670 + self.interactor.Render()
  671 +
  672 + # Setting slider position
  673 + self.slider.SetValue(index)
  674 +
  675 +
  676 +#class BitmapPreviewSlice(wx.Panel):
  677 +# def __init__(self, parent):
  678 +# super(BitmapPreviewSlice, self).__init__(parent)
  679 +# # TODO: 3 pixels between the previews is a good idea?
  680 +# # I have to test.
  681 +# self.displayed_position = 0
  682 +# self.nhidden_last_display = 0
  683 +# self.selected_dicom = None
  684 +# self.selected_panel = None
  685 +# self.first_selection = None
  686 +# self.last_selection = None
  687 +# self._init_ui()
  688 +#
  689 +# def _init_ui(self):
  690 +# scroll = wx.ScrollBar(self, -1, style=wx.SB_VERTICAL)
  691 +# self.scroll = scroll
  692 +#
  693 +# self.grid = wx.GridSizer(rows=NROWS, cols=NCOLS, vgap=3, hgap=3)
  694 +#
  695 +# sizer = wx.BoxSizer(wx.HORIZONTAL)
  696 +# sizer.AddSizer(self.grid, 1, wx.EXPAND|wx.GROW|wx.ALL, 2)
  697 +#
  698 +# background_sizer = wx.BoxSizer(wx.HORIZONTAL)
  699 +# background_sizer.AddSizer(sizer, 1, wx.EXPAND|wx.GROW|wx.ALL, 2)
  700 +# background_sizer.Add(scroll, 0, wx.EXPAND|wx.GROW)
  701 +# self.SetSizer(background_sizer)
  702 +# background_sizer.Fit(self)
  703 +#
  704 +# self.Layout()
  705 +# self.Update()
  706 +# self.SetAutoLayout(1)
  707 +#
  708 +# self.sizer = background_sizer
  709 +#
  710 +# self._Add_Panels_Preview()
  711 +# self._bind_events()
  712 +#
  713 +# def _Add_Panels_Preview(self):
  714 +# self.previews = []
  715 +# for i in xrange(NROWS):
  716 +# for j in xrange(NCOLS):
  717 +# p = Preview(self)
  718 +# p.Bind(EVT_PREVIEW_CLICK, self.OnPreviewClick)
  719 +# #p.Hide()
  720 +# self.previews.append(p)
  721 +# self.grid.Add(p, 1, flag=wx.EXPAND)
  722 +#
  723 +# def _bind_events(self):
  724 +# # When the user scrolls the window
  725 +# self.Bind(wx.EVT_SCROLL, self.OnScroll)
  726 +# self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
  727 +#
  728 +# def SetDicomDirectory(self, directory):
  729 +# utils.debug("Setting Dicom Directory %s" % directory)
  730 +# self.directory = directory
  731 +# self.series = dicom_reader.GetSeries(directory)[0]
  732 +#
  733 +# def SetPatientGroups(self, patient):
  734 +# self.group_list = patient.GetGroups()
  735 +#
  736 +#
  737 +# #def SetDicomSerie(self, pos):
  738 +# # self.files = []
  739 +# # self.displayed_position = 0
  740 +# # self.nhidden_last_display = 0
  741 +# # group = self.group_list[pos]
  742 +# # self.group = group
  743 +# # #dicom_files = group.GetList()
  744 +# # dicom_files = group.GetHandSortedList()
  745 +# # n = 0
  746 +# # for dicom in dicom_files:
  747 +# # info = BitmapInfo(n, dicom,
  748 +# # _("Image %d") % (dicom.image.number),
  749 +# # "%.2f" % (dicom.image.position[2]))
  750 +# # self.files.append(info)
  751 +# # n+=1
  752 +#
  753 +# # scroll_range = len(self.files)/NCOLS
  754 +# # if scroll_range * NCOLS < len(self.files):
  755 +# # scroll_range +=1
  756 +# # self.scroll.SetScrollbar(0, NROWS, scroll_range, NCOLS)
  757 +#
  758 +# # self._display_previews()
  759 +#
  760 +# #def SetDicomGroup(self, group):
  761 +# # self.files = []
  762 +# # self.displayed_position = 0
  763 +# # self.nhidden_last_display = 0
  764 +# # #dicom_files = group.GetList()
  765 +# # dicom_files = group.GetHandSortedList()
  766 +# # n = 0
  767 +# # for dicom in dicom_files:
  768 +# # info = BitmapInfo(n, dicom,
  769 +# # _("Image %d") % (dicom.image.number),
  770 +# # "%.2f" % (dicom.image.position[2]),
  771 +# # )
  772 +# # self.files.append(info)
  773 +# # n+=1
  774 +#
  775 +# # scroll_range = len(self.files)/NCOLS
  776 +# # if scroll_range * NCOLS < len(self.files):
  777 +# # scroll_range +=1
  778 +# # self.scroll.SetScrollbar(0, NROWS, scroll_range, NCOLS)
  779 +#
  780 +# # self._display_previews()
  781 +#
  782 +# #def SetDicomGroup(self, group):
  783 +# # self.files = []
  784 +# # self.displayed_position = 0
  785 +# # self.nhidden_last_display = 0
  786 +# # #dicom_files = group.GetList()
  787 +# # dicom_files = group.GetHandSortedList()
  788 +# # n = 0
  789 +# # for dicom in dicom_files:
  790 +# # info = BitmapInfo(n, dicom,
  791 +# # _("Image %d") % (dicom.image.number),
  792 +# # "%.2f" % (dicom.image.position[2]),
  793 +# # )
  794 +# # self.files.append(info)
  795 +# # n+=1
  796 +#
  797 +# # scroll_range = len(self.files)/NCOLS
  798 +# # if scroll_range * NCOLS < len(self.files):
  799 +# # scroll_range +=1
  800 +# # self.scroll.SetScrollbar(0, NROWS, scroll_range, NCOLS)
  801 +#
  802 +# # self._display_previews()
  803 +#
  804 +#
  805 +# def _display_previews(self):
  806 +# initial = self.displayed_position * NCOLS
  807 +# final = initial + NUM_PREVIEWS
  808 +# if len(self.files) < final:
  809 +# for i in xrange(final-len(self.files)):
  810 +# try:
  811 +# self.previews[-i-1].Hide()
  812 +# except IndexError:
  813 +# utils.debug("doesn't exist!")
  814 +# self.nhidden_last_display = final-len(self.files)
  815 +# else:
  816 +# if self.nhidden_last_display:
  817 +# for i in xrange(self.nhidden_last_display):
  818 +# try:
  819 +# self.previews[-i-1].Show()
  820 +# except IndexError:
  821 +# utils.debug("doesn't exist!")
  822 +# self.nhidden_last_display = 0
  823 +#
  824 +# for f, p in zip(self.files[initial:final], self.previews):
  825 +# p.SetBitmapToPreview(f)
  826 +# if f.selected:
  827 +# self.selected_panel = p
  828 +# #p.interactor.Render()
  829 +#
  830 +# for f, p in zip(self.files[initial:final], self.previews):
  831 +# p.Show()
  832 +#
  833 +# def OnPreviewClick(self, evt):
  834 +#
  835 +# dicom_id = evt.GetSelectID()
  836 +#
  837 +# if self.first_selection is None:
  838 +# self.first_selection = dicom_id
  839 +#
  840 +# if self.last_selection is None:
  841 +# self.last_selection = dicom_id
  842 +#
  843 +#
  844 +# if evt.GetPressedShift():
  845 +#
  846 +# if dicom_id < self.first_selection and dicom_id < self.last_selection:
  847 +# self.first_selection = dicom_id
  848 +# else:
  849 +# self.last_selection = dicom_id
  850 +# else:
  851 +# self.first_selection = dicom_id
  852 +# self.last_selection = dicom_id
  853 +#
  854 +# for i in xrange(len(self.files)):
  855 +#
  856 +# if i == dicom_id:
  857 +# self.files[i].selected = True
  858 +# else:
  859 +# self.files[i].selected = False
  860 +#
  861 +#
  862 +# my_evt = SerieEvent(myEVT_CLICK_SLICE, self.GetId())
  863 +# my_evt.SetSelectedID(evt.GetSelectID())
  864 +# my_evt.SetItemData(evt.GetItemData())
  865 +#
  866 +# if self.selected_dicom:
  867 +# self.selected_dicom.selected = self.selected_dicom is \
  868 +# evt.GetEventObject().bitmap_info
  869 +# self.selected_panel.select_on = self.selected_panel is evt.GetEventObject()
  870 +#
  871 +# if self.first_selection != self.last_selection:
  872 +# for i in xrange(len(self.files)):
  873 +# if i >= self.first_selection and i <= self.last_selection:
  874 +# self.files[i].selected = True
  875 +# else:
  876 +# self.files[i].selected = False
  877 +#
  878 +# else:
  879 +# self.selected_panel.Select()
  880 +#
  881 +# self._display_previews()
  882 +# self.selected_panel = evt.GetEventObject()
  883 +# self.selected_dicom = self.selected_panel.bitmap_info
  884 +# self.GetEventHandler().ProcessEvent(my_evt)
  885 +#
  886 +# #Publisher.sendMessage("Selected Import Images", [self.first_selection, \
  887 +# # self.last_selection])
  888 +#
  889 +# def OnScroll(self, evt=None):
  890 +# if evt:
  891 +# if self.displayed_position != evt.GetPosition():
  892 +# self.displayed_position = evt.GetPosition()
  893 +# else:
  894 +# if self.displayed_position != self.scroll.GetThumbPosition():
  895 +# self.displayed_position = self.scroll.GetThumbPosition()
  896 +# self._display_previews()
  897 +#
  898 +# def OnWheel(self, evt):
  899 +# d = evt.GetWheelDelta() / evt.GetWheelRotation()
  900 +# self.scroll.SetThumbPosition(self.scroll.GetThumbPosition() - d)
  901 +# self.OnScroll()
  902 +
  903 +
... ...
invesalius/gui/dialogs.py
... ... @@ -39,6 +39,12 @@ from gui.widgets.clut_imagedata import CLUTImageDataWidget, EVT_CLUT_NODE_CHANGE
39 39  
40 40 import numpy as np
41 41  
  42 +try:
  43 + from agw import floatspin as FS
  44 +except ImportError: # if it's not there locally, try the wxPython lib.
  45 + import wx.lib.agw.floatspin as FS
  46 +
  47 +
42 48 class MaskEvent(wx.PyCommandEvent):
43 49 def __init__(self , evtType, id, mask_index):
44 50 wx.PyCommandEvent.__init__(self, evtType, id,)
... ... @@ -306,6 +312,48 @@ def ShowImportDirDialog():
306 312 os.chdir(current_dir)
307 313 return path
308 314  
  315 +def ShowImportBitmapDirDialog():
  316 + current_dir = os.path.abspath(".")
  317 +
  318 + if (sys.platform == 'win32') or (sys.platform == 'linux2'):
  319 + session = ses.Session()
  320 +
  321 + if (session.GetLastDicomFolder()):
  322 + folder = session.GetLastDicomFolder()
  323 + else:
  324 + folder = ''
  325 + else:
  326 + folder = ''
  327 +
  328 + dlg = wx.DirDialog(None, _("Choose a folder with TIFF, BMP, JPG or PNG:"), folder,
  329 + style=wx.DD_DEFAULT_STYLE
  330 + | wx.DD_DIR_MUST_EXIST
  331 + | wx.DD_CHANGE_DIR)
  332 +
  333 + path = None
  334 + try:
  335 + if dlg.ShowModal() == wx.ID_OK:
  336 + # GetPath returns in unicode, if a path has non-ascii characters a
  337 + # UnicodeEncodeError is raised. To avoid this, path is encoded in utf-8
  338 + if sys.platform == "win32":
  339 + path = dlg.GetPath()
  340 + else:
  341 + path = dlg.GetPath().encode('utf-8')
  342 +
  343 + except(wx._core.PyAssertionError): #TODO: error win64
  344 + if (dlg.GetPath()):
  345 + path = dlg.GetPath()
  346 +
  347 + if (sys.platform != 'darwin'):
  348 + if (path):
  349 + session.SetLastDicomFolder(path)
  350 +
  351 + # Only destroy a dialog after you're done with it.
  352 + dlg.Destroy()
  353 + os.chdir(current_dir)
  354 + return path
  355 +
  356 +
309 357 def ShowSaveAsProjectDialog(default_filename=None):
310 358 current_dir = os.path.abspath(".")
311 359 dlg = wx.FileDialog(None,
... ... @@ -1630,3 +1678,114 @@ class ReorientImageDialog(wx.Dialog):
1630 1678 Publisher.sendMessage('Disable style', const.SLICE_STATE_REORIENT)
1631 1679 Publisher.sendMessage('Enable style', const.STATE_DEFAULT)
1632 1680 self.Destroy()
  1681 +
  1682 +
  1683 +
  1684 +class ImportBitmapParameters(wx.Dialog):
  1685 +
  1686 + def __init__(self):
  1687 + pre = wx.PreDialog()
  1688 + pre.Create(wx.GetApp().GetTopWindow(), -1, _(u"Parameters"),size=wx.Size(380,230),\
  1689 + style=wx.DEFAULT_DIALOG_STYLE|wx.FRAME_FLOAT_ON_PARENT|wx.STAY_ON_TOP)
  1690 +
  1691 + self.interval = 0
  1692 +
  1693 + self.PostCreate(pre)
  1694 +
  1695 + self._init_gui()
  1696 +
  1697 + self.bind_evts()
  1698 + self.CenterOnScreen()
  1699 +
  1700 +
  1701 + def _init_gui(self):
  1702 +
  1703 +
  1704 + p = wx.Panel(self, -1, style = wx.TAB_TRAVERSAL
  1705 + | wx.CLIP_CHILDREN
  1706 + | wx.FULL_REPAINT_ON_RESIZE)
  1707 +
  1708 + gbs_principal = self.gbs = wx.GridBagSizer(3,1)
  1709 +
  1710 + gbs = self.gbs = wx.GridBagSizer(4, 2)
  1711 +
  1712 + stx_name = wx.StaticText(p, -1, _(u"Project name:"))
  1713 + tx_name = self.tx_name = wx.TextCtrl(p, -1, "InVesalius Bitmap", size=wx.Size(220,-1))
  1714 +
  1715 + stx_orientation = wx.StaticText(p, -1, _(u"Slices orientation:"))
  1716 + cb_orientation_options = [_(u'Axial'), _(u'Coronal'), _(u'Sagital')]
  1717 + cb_orientation = self.cb_orientation = wx.ComboBox(p, value="Axial", choices=cb_orientation_options,\
  1718 + size=wx.Size(160,-1), style=wx.CB_DROPDOWN|wx.CB_READONLY)
  1719 +
  1720 + stx_spacing = wx.StaticText(p, -1, _(u"Spacing (mm):"))
  1721 +
  1722 + gbs.Add(stx_name, (0,0))
  1723 + gbs.Add(tx_name, (0,1))
  1724 +
  1725 + gbs.Add(stx_orientation, (1,0))
  1726 + gbs.Add(cb_orientation, (1,1))
  1727 +
  1728 + gbs.Add(stx_spacing, (2,0))
  1729 +
  1730 + #--- spacing --------------
  1731 + gbs_spacing = wx.GridBagSizer(2, 6)
  1732 +
  1733 + stx_spacing_x = stx_spacing_x = wx.StaticText(p, -1, _(u"X:"))
  1734 + fsp_spacing_x = self.fsp_spacing_x = FS.FloatSpin(p, -1, min_val=0,\
  1735 + increment=0.25, value=1.0, digits=6)
  1736 +
  1737 + stx_spacing_y = stx_spacing_y = wx.StaticText(p, -1, _(u"Y:"))
  1738 + fsp_spacing_y = self.fsp_spacing_y = FS.FloatSpin(p, -1, min_val=0,\
  1739 + increment=0.25, value=1.0, digits=6)
  1740 +
  1741 + stx_spacing_z = stx_spacing_z = wx.StaticText(p, -1, _(u"Z:"))
  1742 + fsp_spacing_z = self.fsp_spacing_z = FS.FloatSpin(p, -1, min_val=0,\
  1743 + increment=0.25, value=1.0, digits=6)
  1744 +
  1745 + gbs_spacing.Add(stx_spacing_x, (0,0))
  1746 + gbs_spacing.Add(fsp_spacing_x, (0,1))
  1747 +
  1748 + gbs_spacing.Add(stx_spacing_y, (0,2))
  1749 + gbs_spacing.Add(fsp_spacing_y, (0,3))
  1750 +
  1751 + gbs_spacing.Add(stx_spacing_z, (0,4))
  1752 + gbs_spacing.Add(fsp_spacing_z, (0,5))
  1753 +
  1754 + #----- buttons ------------------------
  1755 + gbs_button = wx.GridBagSizer(1, 4)
  1756 +
  1757 + btn_ok = self.btn_ok= wx.Button(p, wx.ID_OK)
  1758 + btn_ok.SetDefault()
  1759 +
  1760 + btn_cancel = wx.Button(p, wx.ID_CANCEL)
  1761 +
  1762 + gbs_button.Add(btn_cancel, (1,2))
  1763 + gbs_button.Add(btn_ok, (1,3))
  1764 +
  1765 +
  1766 + gbs_principal.Add(gbs, (0,0))
  1767 + gbs_principal.Add(gbs_spacing, (1,0))
  1768 + gbs_principal.Add(gbs_button, (2,0), flag = wx.ALIGN_RIGHT)
  1769 +
  1770 + box = wx.BoxSizer()
  1771 + box.Add(gbs_principal, 1, wx.ALL|wx.EXPAND, 10)
  1772 +
  1773 + p.SetSizer(box)
  1774 +
  1775 +
  1776 + def bind_evts(self):
  1777 + self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
  1778 +
  1779 + def SetInterval(self, v):
  1780 + self.interval = v
  1781 +
  1782 + def OnOk(self, evt):
  1783 + self.Close()
  1784 + self.Destroy()
  1785 +
  1786 + values = [self.tx_name.GetValue(), self.cb_orientation.GetValue().upper(),\
  1787 + self.fsp_spacing_x.GetValue(), self.fsp_spacing_y.GetValue(),\
  1788 + self.fsp_spacing_z.GetValue(), self.interval]
  1789 + Publisher.sendMessage('Open bitmap files', values)
  1790 +
  1791 +
... ...
invesalius/gui/frame.py
... ... @@ -36,6 +36,7 @@ import default_tasks as tasks
36 36 import default_viewers as viewers
37 37 import gui.dialogs as dlg
38 38 import import_panel as imp
  39 +import import_bitmap_panel as imp_bmp
39 40 import import_network_panel as imp_net
40 41 import project as prj
41 42 import session as ses
... ... @@ -126,6 +127,7 @@ class Frame(wx.Frame):
126 127 sub(self._ShowImportPanel, 'Show import panel in frame')
127 128 #sub(self._ShowHelpMessage, 'Show help message')
128 129 sub(self._ShowImportNetwork, 'Show retrieve dicom panel')
  130 + sub(self._ShowImportBitmap, 'Show import bitmap panel in frame')
129 131 sub(self._ShowTask, 'Show task panel')
130 132 sub(self._UpdateAUI, 'Update AUI')
131 133 sub(self._Exit, 'Exit')
... ... @@ -170,8 +172,14 @@ class Frame(wx.Frame):
170 172 # are shown, this should be hiden
171 173 caption = _("Preview medical data to be reconstructed")
172 174 aui_manager.AddPane(imp.Panel(self), wx.aui.AuiPaneInfo().
173   - Name("Import").Centre().Hide().
174   - MaximizeButton(True).Floatable(True).
  175 + Name("Import").CloseButton(False).Centre().Hide().
  176 + MaximizeButton(False).Floatable(True).
  177 + Caption(caption).CaptionVisible(True))
  178 +
  179 + caption = _("Preview bitmap to be reconstructed")
  180 + aui_manager.AddPane(imp_bmp.Panel(self), wx.aui.AuiPaneInfo().
  181 + Name("ImportBMP").CloseButton(False).Centre().Hide().
  182 + MaximizeButton(False).Floatable(True).
175 183 Caption(caption).CaptionVisible(True))
176 184  
177 185 ncaption = _("Retrieve DICOM from PACS")
... ... @@ -298,6 +306,9 @@ class Frame(wx.Frame):
298 306 Publisher.sendMessage("Set layout button full")
299 307 aui_manager = self.aui_manager
300 308 aui_manager.GetPane("Import").Show(0)
  309 +
  310 + aui_manager.GetPane("ImportBMP").Show(0)
  311 +
301 312 aui_manager.GetPane("Data").Show(1)
302 313 aui_manager.GetPane("Tasks").Show(1)
303 314 aui_manager.Update()
... ... @@ -314,6 +325,18 @@ class Frame(wx.Frame):
314 325 aui_manager.GetPane("Import").Show(0)
315 326 aui_manager.Update()
316 327  
  328 + def _ShowImportBitmap(self, evt_pubsub):
  329 + """
  330 + Show viewers and task, hide import panel.
  331 + """
  332 + Publisher.sendMessage("Set layout button full")
  333 + aui_manager = self.aui_manager
  334 + aui_manager.GetPane("ImportBMP").Show(1)
  335 + aui_manager.GetPane("Data").Show(0)
  336 + aui_manager.GetPane("Tasks").Show(0)
  337 + aui_manager.GetPane("Import").Show(0)
  338 + aui_manager.Update()
  339 +
317 340 def _ShowHelpMessage(self, evt_pubsub):
318 341 aui_manager = self.aui_manager
319 342 pos = aui_manager.GetPane("Data").window.GetScreenPosition()
... ... @@ -371,6 +394,8 @@ class Frame(wx.Frame):
371 394 self.ShowOpenProject()
372 395 elif id == const.ID_ANALYZE_IMPORT:
373 396 self.ShowAnalyzeImporter()
  397 + elif id == const.ID_TIFF_JPG_PNG:
  398 + self.ShowBitmapImporter()
374 399 elif id == const.ID_PROJECT_SAVE:
375 400 session = ses.Session()
376 401 if session.temp_item:
... ... @@ -501,6 +526,12 @@ class Frame(wx.Frame):
501 526 """
502 527 Publisher.sendMessage('Show analyze dialog', True)
503 528  
  529 + def ShowBitmapImporter(self):
  530 + """
  531 + Tiff, BMP, JPEG and PNG
  532 + """
  533 + Publisher.sendMessage('Show bitmap dialog', True)
  534 +
504 535 def FlipVolume(self, axis):
505 536 Publisher.sendMessage('Flip volume', axis)
506 537 Publisher.sendMessage('Reload actual slice')
... ... @@ -581,6 +612,7 @@ class MenuBar(wx.MenuBar):
581 612 #Import Others Files
582 613 others_file_menu = wx.Menu()
583 614 others_file_menu.Append(const.ID_ANALYZE_IMPORT, "Analyze")
  615 + others_file_menu.Append(const.ID_TIFF_JPG_PNG, "TIFF,BMP,JPG or PNG")
584 616  
585 617 # FILE
586 618 file_menu = wx.Menu()
... ...
invesalius/gui/import_bitmap_panel.py 0 → 100644
... ... @@ -0,0 +1,484 @@
  1 +#--------------------------------------------------------------------------
  2 +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas
  3 +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer
  4 +# Homepage: http://www.softwarepublico.gov.br
  5 +# Contact: invesalius@cti.gov.br
  6 +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt)
  7 +#--------------------------------------------------------------------------
  8 +# Este programa e software livre; voce pode redistribui-lo e/ou
  9 +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme
  10 +# publicada pela Free Software Foundation; de acordo com a versao 2
  11 +# da Licenca.
  12 +#
  13 +# Este programa eh distribuido na expectativa de ser util, mas SEM
  14 +# QUALQUER GARANTIA; sem mesmo a garantia implicita de
  15 +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM
  16 +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais
  17 +# detalhes.
  18 +#--------------------------------------------------------------------------
  19 +import wx
  20 +import wx.gizmos as gizmos
  21 +from wx.lib.pubsub import pub as Publisher
  22 +import wx.lib.splitter as spl
  23 +
  24 +import constants as const
  25 +import gui.dialogs as dlg
  26 +import bitmap_preview_panel as bpp
  27 +import reader.dicom_grouper as dcm
  28 +from dialogs import ImportBitmapParameters
  29 +
  30 +myEVT_SELECT_SERIE = wx.NewEventType()
  31 +EVT_SELECT_SERIE = wx.PyEventBinder(myEVT_SELECT_SERIE, 1)
  32 +
  33 +myEVT_SELECT_SLICE = wx.NewEventType()
  34 +EVT_SELECT_SLICE = wx.PyEventBinder(myEVT_SELECT_SLICE, 1)
  35 +
  36 +myEVT_SELECT_PATIENT = wx.NewEventType()
  37 +EVT_SELECT_PATIENT = wx.PyEventBinder(myEVT_SELECT_PATIENT, 1)
  38 +
  39 +myEVT_SELECT_SERIE_TEXT = wx.NewEventType()
  40 +EVT_SELECT_SERIE_TEXT = wx.PyEventBinder(myEVT_SELECT_SERIE_TEXT, 1)
  41 +
  42 +class SelectEvent(wx.PyCommandEvent):
  43 + def __init__(self , evtType, id):
  44 + super(SelectEvent, self).__init__(evtType, id)
  45 +
  46 + def GetSelectID(self):
  47 + return self.SelectedID
  48 +
  49 + def SetSelectedID(self, id):
  50 + self.SelectedID = id
  51 +
  52 + def GetItemData(self):
  53 + return self.data
  54 +
  55 + def SetItemData(self, data):
  56 + self.data = data
  57 +
  58 +
  59 +class Panel(wx.Panel):
  60 + def __init__(self, parent):
  61 + wx.Panel.__init__(self, parent, pos=wx.Point(5, 5))#,
  62 + #size=wx.Size(280, 656))
  63 +
  64 + sizer = wx.BoxSizer(wx.VERTICAL)
  65 + sizer.Add(InnerPanel(self), 1, wx.EXPAND|wx.GROW|wx.ALL, 5)
  66 +
  67 + self.SetSizer(sizer)
  68 + sizer.Fit(self)
  69 +
  70 + self.Layout()
  71 + self.Update()
  72 + self.SetAutoLayout(1)
  73 +
  74 +
  75 +# Inner fold panel
  76 +class InnerPanel(wx.Panel):
  77 + def __init__(self, parent):
  78 + wx.Panel.__init__(self, parent, pos=wx.Point(5, 5))#,
  79 + #size=wx.Size(680, 656))
  80 +
  81 + self.patients = []
  82 + self.first_image_selection = None
  83 + self.last_image_selection = None
  84 + self._init_ui()
  85 + self._bind_events()
  86 + self._bind_pubsubevt()
  87 +
  88 + def _init_ui(self):
  89 + splitter = spl.MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE)
  90 + splitter.SetOrientation(wx.VERTICAL)
  91 + self.splitter = splitter
  92 +
  93 + panel = wx.Panel(self)
  94 + self.btn_cancel = wx.Button(panel, wx.ID_CANCEL)
  95 + self.btn_ok = wx.Button(panel, wx.ID_OK, _("Import"))
  96 +
  97 + btnsizer = wx.StdDialogButtonSizer()
  98 + btnsizer.AddButton(self.btn_ok)
  99 + btnsizer.AddButton(self.btn_cancel)
  100 + btnsizer.Realize()
  101 +
  102 + self.combo_interval = wx.ComboBox(panel, -1, "", choices=const.IMPORT_INTERVAL,
  103 + style=wx.CB_DROPDOWN|wx.CB_READONLY)
  104 + self.combo_interval.SetSelection(0)
  105 +
  106 + inner_sizer = wx.BoxSizer(wx.HORIZONTAL)
  107 + inner_sizer.AddSizer(btnsizer, 0, wx.LEFT|wx.TOP, 5)
  108 + inner_sizer.Add(self.combo_interval, 0, wx.LEFT|wx.RIGHT|wx.TOP, 5)
  109 + panel.SetSizer(inner_sizer)
  110 + inner_sizer.Fit(panel)
  111 +
  112 + sizer = wx.BoxSizer(wx.VERTICAL)
  113 + sizer.Add(splitter, 20, wx.EXPAND)
  114 + sizer.Add(panel, 0, wx.EXPAND|wx.LEFT, 90)
  115 +
  116 + self.text_panel = TextPanel(splitter)
  117 + splitter.AppendWindow(self.text_panel, 250)
  118 +
  119 + self.image_panel = ImagePanel(splitter)
  120 + splitter.AppendWindow(self.image_panel, 250)
  121 +
  122 + self.SetSizer(sizer)
  123 + sizer.Fit(self)
  124 +
  125 + self.Layout()
  126 + self.Update()
  127 + self.SetAutoLayout(1)
  128 +
  129 + def _bind_pubsubevt(self):
  130 + Publisher.subscribe(self.ShowBitmapPreview, "Load import bitmap panel")
  131 + Publisher.subscribe(self.GetSelectedImages ,"Selected Import Images")
  132 +
  133 + def ShowBitmapPreview(self, pubsub_evt):
  134 + data = pubsub_evt.data
  135 + #self.patients.extend(dicom_groups)
  136 + self.text_panel.Populate(data)
  137 +
  138 + def GetSelectedImages(self, pubsub_evt):
  139 + self.first_image_selection = pubsub_evt.data[0]
  140 + self.last_image_selection = pubsub_evt.data[1]
  141 +
  142 + def _bind_events(self):
  143 + self.Bind(EVT_SELECT_SERIE, self.OnSelectSerie)
  144 + self.Bind(EVT_SELECT_SLICE, self.OnSelectSlice)
  145 + self.Bind(EVT_SELECT_PATIENT, self.OnSelectPatient)
  146 + self.btn_ok.Bind(wx.EVT_BUTTON, self.OnClickOk)
  147 + self.btn_cancel.Bind(wx.EVT_BUTTON, self.OnClickCancel)
  148 + self.text_panel.Bind(EVT_SELECT_SERIE_TEXT, self.OnDblClickTextPanel)
  149 +
  150 + def OnSelectSerie(self, evt):
  151 + #patient_id, serie_number = evt.GetSelectID()
  152 + #self.text_panel.SelectSerie(evt.GetSelectID())
  153 + #for patient in self.patients:
  154 + # if patient_id == patient.GetDicomSample().patient.id:
  155 + # for group in patient.GetGroups():
  156 + # if serie_number == group.GetDicomSample().acquisition.serie_number:
  157 + # self.image_panel.SetSerie(group)
  158 +
  159 + pass
  160 +
  161 +
  162 +
  163 + def OnSelectSlice(self, evt):
  164 + pass
  165 +
  166 + def OnSelectPatient(self, evt):
  167 + pass
  168 +
  169 + def OnDblClickTextPanel(self, evt):
  170 + group = evt.GetItemData()
  171 + self.LoadDicom(group)
  172 +
  173 + def OnClickOk(self, evt):
  174 + parm = dlg.ImportBitmapParameters()
  175 + parm.SetInterval(self.combo_interval.GetSelection())
  176 + parm.ShowModal()
  177 +
  178 + group = self.text_panel.GetSelection()
  179 + if group:
  180 + self.LoadDicom(group)
  181 +
  182 + def OnClickCancel(self, evt):
  183 + Publisher.sendMessage("Cancel DICOM load")
  184 +
  185 + def LoadDicom(self, group):
  186 + #interval = self.combo_interval.GetSelection()
  187 + #if not isinstance(group, dcm.DicomGroup):
  188 + # group = max(group.GetGroups(), key=lambda g: g.nslices)
  189 +
  190 + #slice_amont = group.nslices
  191 + #if (self.first_image_selection != None) and (self.first_image_selection != self.last_image_selection):
  192 + # slice_amont = (self.last_image_selection) - self.first_image_selection
  193 + # slice_amont += 1
  194 + # if slice_amont == 0:
  195 + # slice_amont = group.nslices
  196 +
  197 + #nslices_result = slice_amont / (interval + 1)
  198 + #if (nslices_result > 1):
  199 + # Publisher.sendMessage('Open DICOM group', (group, interval,
  200 + # [self.first_image_selection, self.last_image_selection]))
  201 + #else:
  202 + # dlg.MissingFilesForReconstruction()
  203 + pass
  204 +
  205 +
  206 +class TextPanel(wx.Panel):
  207 + def __init__(self, parent):
  208 + wx.Panel.__init__(self, parent, -1)
  209 +
  210 + self._selected_by_user = True
  211 + self.idserie_treeitem = {}
  212 + self.treeitem_idpatient = {}
  213 +
  214 + self.__init_gui()
  215 + self.__bind_events_wx()
  216 + self.__bind_pubsub_evt()
  217 +
  218 + def __bind_pubsub_evt(self):
  219 + Publisher.subscribe(self.SelectSeries, 'Select series in import panel')
  220 +
  221 + def __bind_events_wx(self):
  222 + self.Bind(wx.EVT_SIZE, self.OnSize)
  223 +
  224 + def __init_gui(self):
  225 + tree = gizmos.TreeListCtrl(self, -1, style =
  226 + wx.TR_DEFAULT_STYLE
  227 + | wx.TR_HIDE_ROOT
  228 + | wx.TR_ROW_LINES
  229 + | wx.TR_COLUMN_LINES
  230 + | wx.TR_FULL_ROW_HIGHLIGHT
  231 + | wx.TR_SINGLE
  232 + | wx.TR_HIDE_ROOT
  233 + )
  234 +
  235 +
  236 + tree.AddColumn(_("Path"))
  237 + tree.AddColumn(_("Type"))
  238 + tree.AddColumn(_("Width x Height"))
  239 +
  240 +
  241 + tree.SetMainColumn(0)
  242 + tree.SetColumnWidth(0, 880)
  243 + tree.SetColumnWidth(1, 60)
  244 + tree.SetColumnWidth(2, 130)
  245 +
  246 + self.root = tree.AddRoot(_("InVesalius Database"))
  247 + self.tree = tree
  248 +
  249 + def SelectSeries(self, pubsub_evt):
  250 + group_index = pubsub_evt.data
  251 +
  252 + def Populate(self, data):
  253 + tree = self.tree
  254 + for value in data:
  255 + parent = tree.AppendItem(self.root, value[0])
  256 + self.tree.SetItemText(parent, value[2], 1)
  257 + self.tree.SetItemText(parent, value[5], 2)
  258 +
  259 + tree.Expand(self.root)
  260 + #tree.SelectItem(parent_select)
  261 + tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate)
  262 + tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
  263 +
  264 + Publisher.sendMessage('Load bitmap into import panel', data)
  265 +
  266 +
  267 + def OnSelChanged(self, evt):
  268 + item = self.tree.GetSelection()
  269 + if self._selected_by_user:
  270 + group = self.tree.GetItemPyData(item)
  271 + if isinstance(group, dcm.DicomGroup):
  272 + Publisher.sendMessage('Load group into import panel',
  273 + group)
  274 +
  275 + elif isinstance(group, dcm.PatientGroup):
  276 + id = group.GetDicomSample().patient.id
  277 + my_evt = SelectEvent(myEVT_SELECT_PATIENT, self.GetId())
  278 + my_evt.SetSelectedID(id)
  279 + self.GetEventHandler().ProcessEvent(my_evt)
  280 +
  281 + Publisher.sendMessage('Load bitmap into import panel',
  282 +
  283 + group)
  284 + else:
  285 + parent_id = self.tree.GetItemParent(item)
  286 + self.tree.Expand(parent_id)
  287 + evt.Skip()
  288 +
  289 + def OnActivate(self, evt):
  290 + item = evt.GetItem()
  291 + group = self.tree.GetItemPyData(item)
  292 + my_evt = SelectEvent(myEVT_SELECT_SERIE_TEXT, self.GetId())
  293 + my_evt.SetItemData(group)
  294 + self.GetEventHandler().ProcessEvent(my_evt)
  295 +
  296 + def OnSize(self, evt):
  297 + self.tree.SetSize(self.GetSize())
  298 +
  299 + def SelectSerie(self, serie):
  300 + self._selected_by_user = False
  301 + item = self.idserie_treeitem[serie]
  302 + self.tree.SelectItem(item)
  303 + self._selected_by_user = True
  304 +
  305 + def GetSelection(self):
  306 + """Get selected item"""
  307 + item = self.tree.GetSelection()
  308 + group = self.tree.GetItemPyData(item)
  309 + return group
  310 +
  311 +
  312 +class ImagePanel(wx.Panel):
  313 + def __init__(self, parent):
  314 + wx.Panel.__init__(self, parent, -1)
  315 + self._init_ui()
  316 + self._bind_events()
  317 +
  318 + def _init_ui(self):
  319 + splitter = spl.MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE)
  320 + splitter.SetOrientation(wx.HORIZONTAL)
  321 + self.splitter = splitter
  322 +
  323 + splitter.ContainingSizer = wx.BoxSizer(wx.HORIZONTAL)
  324 +
  325 + sizer = wx.BoxSizer(wx.HORIZONTAL)
  326 + sizer.Add(splitter, 1, wx.EXPAND)
  327 + self.SetSizer(sizer)
  328 +
  329 + self.text_panel = SeriesPanel(splitter)
  330 + splitter.AppendWindow(self.text_panel, 600)
  331 +
  332 + self.image_panel = SlicePanel(splitter)
  333 + splitter.AppendWindow(self.image_panel, 250)
  334 +
  335 + self.SetSizer(sizer)
  336 + sizer.Fit(self)
  337 +
  338 + self.Layout()
  339 + self.Update()
  340 + self.SetAutoLayout(1)
  341 +
  342 + def _bind_events(self):
  343 + self.text_panel.Bind(EVT_SELECT_SERIE, self.OnSelectSerie)
  344 + self.text_panel.Bind(EVT_SELECT_SLICE, self.OnSelectSlice)
  345 +
  346 + def OnSelectSerie(self, evt):
  347 + evt.Skip()
  348 +
  349 + def OnSelectSlice(self, evt):
  350 + self.image_panel.bitmap_preview.ShowSlice(evt.GetSelectID())
  351 + evt.Skip()
  352 +
  353 + def SetSerie(self, serie):
  354 + self.image_panel.bitmap_preview.SetDicomGroup(serie)
  355 +
  356 +
  357 +class SeriesPanel(wx.Panel):
  358 + def __init__(self, parent):
  359 + wx.Panel.__init__(self, parent, -1)
  360 + #self.SetBackgroundColour((0,0,0))
  361 +
  362 + self.thumbnail_preview = bpp.BitmapPreviewSeries(self)
  363 + #self.bitmap_preview = bpp.BitmapPreviewSlice(self)
  364 + #self.bitmap_preview.Show(0)
  365 +
  366 +
  367 + self.sizer = wx.BoxSizer(wx.HORIZONTAL)
  368 + self.sizer.Add(self.thumbnail_preview, 1, wx.EXPAND | wx.ALL, 5)
  369 + #self.sizer.Add(self.bitmap_preview, 1, wx.EXPAND | wx.ALL, 5)
  370 + self.sizer.Fit(self)
  371 +
  372 + self.SetSizer(self.sizer)
  373 +
  374 + self.Layout()
  375 + self.Update()
  376 + self.SetAutoLayout(1)
  377 +
  378 + self.__bind_evt()
  379 + self._bind_gui_evt()
  380 +
  381 + def __bind_evt(self):
  382 + #Publisher.subscribe(self.ShowDicomSeries, 'Load bitmap preview')
  383 + #Publisher.subscribe(self.SetDicomSeries, 'Load group into import panel')
  384 + Publisher.subscribe(self.SetBitmapFiles, 'Load bitmap into import panel')
  385 +
  386 + def _bind_gui_evt(self):
  387 + self.thumbnail_preview.Bind(bpp.EVT_CLICK_SERIE, self.OnSelectSerie)
  388 + #self.bitmap_preview.Bind(bpp.EVT_CLICK_SLICE, self.OnSelectSlice)
  389 +
  390 + #def SetDicomSeries(self, pubsub_evt):
  391 + # group = pubsub_evt.data
  392 + # self.bitmap_preview.SetDicomGroup(group)
  393 + # self.bitmap_preview.Show(1)
  394 + # self.thumbnail_preview.Show(0)
  395 + # self.sizer.Layout()
  396 + # self.Update()
  397 +
  398 + def GetSelectedImagesRange(self):
  399 + return [self.bitmap_preview.first_selected, self.dicom_preview_last_selection]
  400 +
  401 + def SetBitmapFiles(self, pubsub_evt):
  402 +
  403 +
  404 + bitmap = pubsub_evt.data
  405 + #self.bitmap_preview.Show(0)
  406 + self.thumbnail_preview.Show(1)
  407 +
  408 + self.thumbnail_preview.SetBitmapFiles(bitmap)
  409 + #self.bitmap_preview.SetPatientGroups(patient)
  410 +
  411 + self.Update()
  412 +
  413 + def OnSelectSerie(self, evt):
  414 + data = evt.GetItemData()
  415 +
  416 + my_evt = SelectEvent(myEVT_SELECT_SERIE, self.GetId())
  417 + my_evt.SetSelectedID(evt.GetSelectID())
  418 + my_evt.SetItemData(evt.GetItemData())
  419 + self.GetEventHandler().ProcessEvent(my_evt)
  420 +
  421 + #self.bitmap_preview.SetDicomGroup(data)
  422 + #self.bitmap_preview.Show(1)
  423 + #self.thumbnail_preview.Show(0)
  424 + self.sizer.Layout()
  425 + self.Show()
  426 + self.Update()
  427 +
  428 + def OnSelectSlice(self, evt):
  429 + my_evt = SelectEvent(myEVT_SELECT_SLICE, self.GetId())
  430 + my_evt.SetSelectedID(evt.GetSelectID())
  431 + my_evt.SetItemData(evt.GetItemData())
  432 + self.GetEventHandler().ProcessEvent(my_evt)
  433 +
  434 +
  435 + #def ShowDicomSeries(self, pubsub_evt):
  436 + # patient = pubsub_evt.data
  437 + # if isinstance(patient, dcm.PatientGroup):
  438 + # self.thumbnail_preview.SetPatientGroups(patient)
  439 + # self.bitmap_preview.SetPatientGroups(patient)
  440 +
  441 +
  442 +class SlicePanel(wx.Panel):
  443 + def __init__(self, parent):
  444 + wx.Panel.__init__(self, parent, -1)
  445 + self.__init_gui()
  446 + self.__bind_evt()
  447 +
  448 + def __bind_evt(self):
  449 + #Publisher.subscribe(self.ShowDicomSeries, 'Load bitmap preview')
  450 + #Publisher.subscribe(self.SetDicomSeries, 'Load group into import panel')
  451 + Publisher.subscribe(self.SetBitmapFiles, 'Load bitmap into import panel')
  452 +
  453 + def __init_gui(self):
  454 + self.SetBackgroundColour((255,255,255))
  455 + self.bitmap_preview = bpp.SingleImagePreview(self)
  456 +
  457 + sizer = wx.BoxSizer(wx.VERTICAL)
  458 + sizer.Add(self.bitmap_preview, 1, wx.GROW|wx.EXPAND)
  459 + sizer.Fit(self)
  460 + self.SetSizer(sizer)
  461 + self.Layout()
  462 + self.Update()
  463 + self.SetAutoLayout(1)
  464 + self.sizer = sizer
  465 +
  466 + def SetBitmapFiles(self, pubsub_evt):
  467 + data = pubsub_evt.data
  468 + self.bitmap_preview.SetBitmapFiles(data)
  469 + self.sizer.Layout()
  470 + self.Update()
  471 +
  472 + #def SetDicomSeries(self, evt):
  473 + # group = evt.data
  474 + # self.bitmap_preview.SetDicomGroup(group)
  475 + # self.sizer.Layout()
  476 + # self.Update()
  477 +
  478 + #def ShowDicomSeries(self, pubsub_evt):
  479 + # patient = pubsub_evt.data
  480 + # group = patient.GetGroups()[0]
  481 + # self.bitmap_preview.SetDicomGroup(group)
  482 + # self.sizer.Layout()
  483 + # self.Update()
  484 +
... ...
invesalius/gui/task_slice.py
... ... @@ -524,6 +524,7 @@ class MaskProperties(wx.Panel):
524 524 self.bind_evt_gradient = False
525 525 self.gradient.SetMinValue(thresh_min)
526 526 self.gradient.SetMaxValue(thresh_max)
  527 + print ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", thresh_min, thresh_max
527 528 self.bind_evt_gradient = True
528 529 thresh = (thresh_min, thresh_max)
529 530 if thresh in Project().threshold_modes.values():
... ...
invesalius/presets.py
... ... @@ -73,12 +73,13 @@ class Presets():
73 73 def UpdateThresholdModes(self, evt):
74 74  
75 75 thresh_min, thresh_max = evt.data
76   -
77 76 presets_list = (self.thresh_ct, self.thresh_mri)
78 77  
79 78 for presets in presets_list:
80 79 for key in presets:
81 80 (t_min, t_max) = presets[key]
  81 +
  82 +
82 83 if (t_min is None) or (t_max is None): # setting custom preset
83 84 t_min = thresh_min
84 85 t_max = thresh_max
... ... @@ -93,7 +94,7 @@ class Presets():
93 94 t_min = thresh_min
94 95 if (t_max < thresh_min):
95 96 t_max = thresh_max
96   -
  97 +
97 98 presets[key] = (t_min, t_max)
98 99  
99 100 Publisher.sendMessage('Update threshold limits', (thresh_min,
... ...
invesalius/reader/bitmap_reader.py 0 → 100644
... ... @@ -0,0 +1,389 @@
  1 +#--------------------------------------------------------------------------
  2 +# Software: InVesalius - Software de Reconstrucao 3D de Imagens Medicas
  3 +# Copyright: (C) 2001 Centro de Pesquisas Renato Archer
  4 +# Homepage: http://www.softwarepublico.gov.br
  5 +# Contact: invesalius@cti.gov.br
  6 +# License: GNU - GPL 2 (LICENSE.txt/LICENCA.txt)
  7 +#--------------------------------------------------------------------------
  8 +# Este programa e software livre; voce pode redistribui-lo e/ou
  9 +# modifica-lo sob os termos da Licenca Publica Geral GNU, conforme
  10 +# publicada pela Free Software Foundation; de acordo com a versao 2
  11 +# da Licenca.
  12 +#
  13 +# Este programa eh distribuido na expectativa de ser util, mas SEM
  14 +# QUALQUER GARANTIA; sem mesmo a garantia implicita de
  15 +# COMERCIALIZACAO ou de ADEQUACAO A QUALQUER PROPOSITO EM
  16 +# PARTICULAR. Consulte a Licenca Publica Geral GNU para obter mais
  17 +# detalhes.
  18 +#--------------------------------------------------------------------------
  19 +import os
  20 +import Queue
  21 +import threading
  22 +import tempfile
  23 +import sys
  24 +import vtk
  25 +import re
  26 +import constants as const
  27 +import wx
  28 +
  29 +from wx.lib.pubsub import pub as Publisher
  30 +from multiprocessing import cpu_count
  31 +
  32 +from vtk.util import numpy_support
  33 +from scipy import misc
  34 +import numpy
  35 +import imghdr
  36 +
  37 +from data import converters
  38 +
  39 +#flag to control vtk error in read files
  40 +no_error = True
  41 +vtk_error = False
  42 +
  43 +class Singleton:
  44 +
  45 + def __init__(self,klass):
  46 + self.klass = klass
  47 + self.instance = None
  48 +
  49 + def __call__(self,*args,**kwds):
  50 + if self.instance == None:
  51 + self.instance = self.klass(*args,**kwds)
  52 + return self.instance
  53 +
  54 +@Singleton
  55 +class BitmapData:
  56 +
  57 + def __init__(self):
  58 + self.data = None
  59 +
  60 + def GetData(self):
  61 + return self.data
  62 +
  63 + def SetData(self, data):
  64 + self.data = data
  65 +
  66 + def GetOnlyBitmapPath(self):
  67 + paths = [item[0] for item in self.data]
  68 + return paths
  69 +
  70 + def GetFirstBitmapSize(self):
  71 + return (self.data[0][3], self.data[0][4])
  72 +
  73 + def IsAllBitmapSameSize(self):
  74 + sizes = [item[5] for item in self.data]
  75 +
  76 + k = {}
  77 + for v in sizes:
  78 + k[v] = ''
  79 +
  80 + if len(k.keys()) > 1:
  81 + return False
  82 + else:
  83 + return True
  84 +
  85 + def GetFirstPixelSize(self):
  86 +
  87 + path = self.data[0][0]
  88 + size = ReadBitmap(path).dtype.itemsize * 8
  89 +
  90 + return size
  91 +
  92 +
  93 +
  94 +class BitmapFiles:
  95 +
  96 + def __init__(self):
  97 + self.bitmapfiles = []
  98 +
  99 + def Add(self, bmp):
  100 + self.bitmapfiles.append(bmp)
  101 +
  102 + def Sort(self, x):
  103 +
  104 + c_re = re.compile('\d+')
  105 +
  106 + if len(c_re.findall(x[0])) > 0:
  107 + return c_re.findall(x[0])[-1]
  108 + else:
  109 + return '0'
  110 +
  111 + def GetValues(self):
  112 + bmpfile = self.bitmapfiles
  113 + bmpfile.sort(key = self.Sort)
  114 +
  115 + bmp_data = BitmapData()
  116 + bmp_data.data = bmpfile
  117 +
  118 + return bmpfile
  119 +
  120 +class LoadBitmap:
  121 +
  122 + def __init__(self, bmp_file, filepath):
  123 + self.bmp_file = bmp_file
  124 + if sys.platform == 'win32':
  125 + self.filepath = filepath.encode(utils.get_system_encoding())
  126 + else:
  127 + self.filepath = filepath
  128 +
  129 + self.run()
  130 +
  131 + def run(self):
  132 + global vtk_error
  133 +
  134 + #----- verify extension ------------------
  135 + #ex = self.filepath.split('.')[-1]
  136 + extension = VerifyDataType(self.filepath)
  137 +
  138 + file_name = self.filepath.split(os.path.sep)[-1]
  139 +
  140 + #if extension == 'bmp':
  141 + # reader = vtk.vtkBMPReader()
  142 + n_array = ReadBitmap(self.filepath)
  143 +
  144 + if not(isinstance(n_array, numpy.ndarray)):
  145 + return False
  146 +
  147 + image = converters.to_vtk(n_array, spacing=(1,1,1),\
  148 + slice_number=1, orientation="AXIAL")
  149 +
  150 +
  151 + #reader.SetFileName(self.filepath)
  152 + #reader.Update()
  153 +
  154 + dim = image.GetDimensions()
  155 + x = dim[0]
  156 + y = dim[1]
  157 +
  158 + img = vtk.vtkImageResample()
  159 + img.SetInputData(image)
  160 + img.SetAxisMagnificationFactor ( 0, 0.25 )
  161 + img.SetAxisMagnificationFactor ( 1, 0.25 )
  162 + img.SetAxisMagnificationFactor ( 2, 1 )
  163 + img.Update()
  164 +
  165 + tp = img.GetOutput().GetScalarTypeAsString()
  166 +
  167 + image_copy = vtk.vtkImageData()
  168 + image_copy.DeepCopy(img.GetOutput())
  169 +
  170 + thumbnail_path = tempfile.mktemp()
  171 +
  172 + write_png = vtk.vtkPNGWriter()
  173 + write_png.SetInputConnection(img.GetOutputPort())
  174 + write_png.AddObserver("WarningEvent", VtkErrorPNGWriter)
  175 + write_png.SetFileName(thumbnail_path)
  176 + write_png.Write()
  177 +
  178 + if vtk_error:
  179 + img = vtk.vtkImageCast()
  180 + img.SetInputData(image_copy)
  181 + img.SetOutputScalarTypeToUnsignedShort()
  182 + #img.SetClampOverflow(1)
  183 + img.Update()
  184 +
  185 + write_png = vtk.vtkPNGWriter()
  186 + write_png.SetInputConnection(img.GetOutputPort())
  187 + write_png.SetFileName(thumbnail_path)
  188 + write_png.Write()
  189 +
  190 + vtk_error = False
  191 +
  192 + id = wx.NewId()
  193 +
  194 + bmp_item = [self.filepath, thumbnail_path, extension, x, y,\
  195 + str(x) + ' x ' + str(y), file_name, id]
  196 + self.bmp_file.Add(bmp_item)
  197 +
  198 +
  199 +def yGetBitmaps(directory, recursive=True, gui=True):
  200 + """
  201 + Return all full paths to DICOM files inside given directory.
  202 + """
  203 + nfiles = 0
  204 + # Find total number of files
  205 + if recursive:
  206 + for dirpath, dirnames, filenames in os.walk(directory):
  207 + nfiles += len(filenames)
  208 + else:
  209 + dirpath, dirnames, filenames = os.walk(directory)
  210 + nfiles = len(filenames)
  211 +
  212 +
  213 + counter = 0
  214 + bmp_file = BitmapFiles()
  215 +
  216 + # Retrieve only TIFF, BMP, JPEG and PNG files
  217 + if recursive:
  218 + for dirpath, dirnames, filenames in os.walk(directory):
  219 + for name in filenames:
  220 + filepath = os.path.join(dirpath, name)
  221 + counter += 1
  222 + if gui:
  223 + yield (counter,nfiles)
  224 + #LoadDicom(grouper, filepath)
  225 + LoadBitmap(bmp_file, filepath)
  226 + else:
  227 + dirpath, dirnames, filenames = os.walk(directory)
  228 + for name in filenames:
  229 + filepath = str(os.path.join(dirpath, name))
  230 + counter += 1
  231 + if gui:
  232 + yield (counter,nfiles)
  233 + #q.put(filepath)
  234 +
  235 + #for t in threads:
  236 + # q.put(0)
  237 +
  238 + #for t in threads:
  239 + # t.join()
  240 +
  241 + #TODO: Is this commented update necessary?
  242 + #grouper.Update()
  243 + yield bmp_file.GetValues()
  244 +
  245 +
  246 +class ProgressBitmapReader:
  247 + def __init__(self):
  248 + Publisher.subscribe(self.CancelLoad, "Cancel bitmap load")
  249 +
  250 + def CancelLoad(self, evt_pubsub):
  251 + self.running = False
  252 + self.stoped = True
  253 +
  254 + def SetWindowEvent(self, frame):
  255 + self.frame = frame
  256 +
  257 + def SetDirectoryPath(self, path,recursive=True):
  258 + self.running = True
  259 + self.stoped = False
  260 + self.GetBitmaps(path,recursive)
  261 +
  262 + def UpdateLoadFileProgress(self,cont_progress):
  263 + Publisher.sendMessage("Update bitmap load", cont_progress)
  264 +
  265 + def EndLoadFile(self, bitmap_list):
  266 + Publisher.sendMessage("End bitmap load", bitmap_list)
  267 +
  268 + def GetBitmaps(self, path, recursive):
  269 +
  270 + #if not const.VTK_WARNING:
  271 + # log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt')
  272 + # fow = vtk.vtkFileOutputWindow()
  273 + # fow.SetFileName(log_path)
  274 + # ow = vtk.vtkOutputWindow()
  275 + # ow.SetInstance(fow)
  276 +
  277 + y = yGetBitmaps(path, recursive)
  278 + for value_progress in y:
  279 + if not self.running:
  280 + break
  281 + if isinstance(value_progress, tuple):
  282 + self.UpdateLoadFileProgress(value_progress)
  283 + else:
  284 + self.EndLoadFile(value_progress)
  285 +
  286 + #Is necessary in the case user cancel
  287 + #the load, ensure that dicomdialog is closed
  288 + if(self.stoped):
  289 + self.UpdateLoadFileProgress(None)
  290 + self.stoped = False
  291 +
  292 +def VtkErrorPNGWriter(obj, f):
  293 + global vtk_error
  294 + vtk_error = True
  295 +
  296 +def ScipyRead(filepath):
  297 + try:
  298 + r = misc.imread(filepath, flatten=True)
  299 + dt = r.dtype
  300 +
  301 + if dt == "float" or dt == "float16"\
  302 + or dt == "float32" or dt == "float64":
  303 + shift=-r.max()/2
  304 + simage = numpy.zeros_like(r, dtype='int16')
  305 + simage[:] = r.astype('int32') + shift
  306 +
  307 + return simage
  308 + else:
  309 + return r
  310 + except(IOError):
  311 + return False
  312 +
  313 +def VtkRead(filepath, t):
  314 +
  315 + global no_error
  316 +
  317 + if t == "bmp":
  318 + reader = vtk.vtkBMPReader()
  319 +
  320 + elif t == "tiff" or t == "tif":
  321 + reader = vtk.vtkTIFFReader()
  322 +
  323 + elif t == "png":
  324 + reader = vtk.vtkPNGReader()
  325 +
  326 + elif t == "jpeg" or t == "jpg":
  327 + reader = vtk.vtkJPEGReader()
  328 +
  329 + else:
  330 + return False
  331 +
  332 + reader.AddObserver("ErrorEvent", VtkErrorToPy)
  333 + reader.SetFileName(filepath)
  334 + reader.Update()
  335 +
  336 + if no_error:
  337 + image = reader.GetOutput()
  338 + dim = image.GetDimensions()
  339 +
  340 + if reader.GetNumberOfScalarComponents() > 1:
  341 + luminanceFilter = vtk.vtkImageLuminance()
  342 + luminanceFilter.SetInputData(image)
  343 + luminanceFilter.Update()
  344 +
  345 + image = vtk.vtkImageData()
  346 + image.DeepCopy(luminanceFilter.GetOutput())
  347 +
  348 + img_array = numpy_support.vtk_to_numpy(image.GetPointData().GetScalars())
  349 + img_array.shape = (dim[1], dim[0])
  350 +
  351 + return img_array
  352 + else:
  353 + no_error = True
  354 + return False
  355 +
  356 +
  357 +def ReadBitmap(filepath):
  358 +
  359 + t = VerifyDataType(filepath)
  360 +
  361 + if t == False:
  362 + return False
  363 +
  364 + img_array = VtkRead(filepath, t)
  365 +
  366 + if not(isinstance(img_array, numpy.ndarray)):
  367 +
  368 + no_error = True
  369 +
  370 + img_array = ScipyRead(filepath)
  371 +
  372 + if not(isinstance(img_array, numpy.ndarray)):
  373 + return False
  374 +
  375 + return img_array
  376 +
  377 +
  378 +def VtkErrorToPy(obj, evt):
  379 + global no_error
  380 + no_error = False
  381 +
  382 +
  383 +def VerifyDataType(filepath):
  384 + try:
  385 + t = imghdr.what(filepath)
  386 + return t
  387 + except IOError:
  388 + return False
  389 +
... ...