.. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_anaevensimplerviewer.py: Build a custom simplified viewer based on Anatomist =================================================== An even simplified version of the anasimpleviewer application, which may also be used as a programming example. Its code is in the “bin/”” directory of the binary packages. .. .. figure:: ../images/anaevensimplerviewer.png .. image:: /auto_examples/images/sphx_glr_anaevensimplerviewer_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out Out: .. code-block:: none config.setitem: setAutomaticReferential : 1 config.setitem: windowSizeFactor : 1.0 hdr: { 'volume_dimension' : [ 256, 256, 124, 1 ], 'sizeX' : 256, 'sizeY' : 256, 'sizeZ' : 124, 'sizeT' : 1, 'format' : 'GIS', 'voxel_size' : [ 1.01561999320984, 1.01561999320984, 1.10000002384186 ], 'object_type' : 'Volume', 'data_type' : 'S16', 'ascii' : 0, 'byte_swapping' : 1, 'texture_min' : 0, 'texture_max' : 618, 'boundingbox_min' : [ 0, 0, 0, 0 ], 'boundingbox_max' : [ 256, 256, 124, 1 ] } Exiting | .. code-block:: default from __future__ import print_function from __future__ import absolute_import import anatomist.direct.api as ana from soma import aims from soma.aims import colormaphints import sys import os from soma.qt_gui import qt_backend from soma.qt_gui.qt_backend import Qt, loadUi import six from six.moves import zip def findChild(x, y): return Qt.QObject.findChild(x, Qt.QObject, y) if Qt.QApplication.instance() is None: run_qt = True else: run_qt = False # start the Anatomist engine, in batch mode (no main window) a = ana.Anatomist('-b') # load the anasimpleviewer GUI uifile = 'anasimpleviewer-qt4.ui' anasimpleviewerdir = os.path.join(six.text_type(a.anatomistSharedPath()), 'anasimpleviewer') cwd = os.getcwd() # PyQt4 uic doesn' seem to allow specifying the directory when looking for # icon files: we have no other choice than globally changing the working # directory os.chdir(anasimpleviewerdir) awin = loadUi(os.path.join(anasimpleviewerdir, uifile)) os.chdir(cwd) # global variables: lists of windows, objects, a fusion2d with a number of # volumes in it awindows = [] aobjects = [] fusion2d = [] # vieww: parent block widget for anatomist windows vieww = findChild(awin, 'windows') viewgridlay = Qt.QGridLayout(vieww) nviews = 0 # This class holds methods for menu/actions callbacks, and utility functions # like load/view objects, remove/delete, etc. class AnaSimpleViewer(Qt.QObject): def __init__(self): Qt.QObject.__init__(self) self.filedialogdir = '.' def createWindow(self, wintype='Axial'): '''Opens a new window in the windows grid layout. The new window will be set in MNI referential, and have no menu/toolbars. ''' global vieww, nviews x = nviews % 2 y = nviews / 2 nviews += 1 w = a.createWindow(wintype, no_decoration=True, options={'hidden': 1}) w.setAcceptDrops(False) viewgridlay.addWidget(w.getInternalRep(), x, y) # keep it in anasimpleviewer list of windows awindows.append(w) a.assignReferential(a.mniTemplateRef, w) # force redrawing in MNI orientation # (there should be a better way to do so...) if wintype == 'Axial': w.muteAxial() elif wintype == 'Coronal': w.muteCoronal() elif wintype == 'Sagittal': w.muteSagittal() elif wintype == 'Oblique': w.muteOblique() # set a black background a.execute('WindowConfig', windows=[w], light={'background': [0., 0., 0., 1.]}) def loadObject(self, fname): '''Load an object and display it in all anasimpleviewer windows ''' obj = a.loadObject(fname) self.registerObject(obj) def registerObject(self, obj): '''Register an object in anasimpleviewer objects list, and display it ''' findChild(awin, 'objectslist').addItem(obj.name) # keep it in the global list aobjects.append(obj) if obj.objectType == 'VOLUME': # volume are checked for possible adequate colormaps hints = colormaphints.checkVolume( ana.cpp.AObjectConverter.aims(obj)) obj.attributed()['colormaphints'] = hints bb = obj.boundingbox() # create the 4 windows if they don't exist if len(awindows) == 0: self.createWindow('Coronal') self.createWindow('Axial') self.createWindow('Sagittal') self.createWindow('3D') # set a cool angle of view for 3D a.execute('Camera', windows=[awindows[-1]], view_quaternion=[0.404603, 0.143829, 0.316813, 0.845718]) # view obj in these views self.addObject(obj) # set the cursot at the center of the object (actually, overcome a bug # in anatomist...) position = (aims.Point3df(bb[1][:3]) - bb[0][:3]) / 2. t = a.getTransformation(obj.getReferential(), awindows[0].getReferential()) if t: position = t.transform(position) a.execute('LinkedCursor', window=awindows[0], position=position) def addVolume(self, obj, opts={}): '''Display a volume in all windows. If several volumes are displayed, a Fusion2D will be built to wrap all of them. ''' global fusion2d if obj in fusion2d: return if len(fusion2d) == 0: # only one object fusion2d = [None, obj] else: # several objects: fusion them fusobjs = fusion2d[1:] + [obj] f2d = a.fusionObjects(fusobjs, method='Fusion2DMethod') if fusion2d[0] is not None: # destroy the previous fusion a.deleteObjects(fusion2d[0]) else: a.removeObjects(fusion2d[1], awindows) fusion2d = [f2d] + fusobjs # repalette( fusobjs ) obj = f2d if obj.objectType == 'VOLUME': # choose a good colormap for a single volume if 'volume_contents_likelihoods' in obj.attributed()['colormaphints']: cmap = colormaphints.chooseColormaps( (obj.attributed()['colormaphints'], )) obj.setPalette(cmap[0]) else: # choose good colormaps for the current set of volumes hints = [x.attributed()['colormaphints'] for x in obj.children] children = [x for x, y in zip(obj.children, hints) if 'volume_contents_likelihoods' in y] hints = [x for x in hints if 'volume_contents_likelihoods' in x] cmaps = colormaphints.chooseColormaps(hints) for x, y in zip(children, cmaps): x.setPalette(y) a.addObjects(obj, awindows, **opts) def removeVolume(self, obj, opts={}): '''Hides a volume from views (low-level function: use removeObject) ''' global fusion2d if obj in fusion2d: fusobjs = [o for o in fusion2d[1:] if o != obj] if len(fusobjs) >= 2: f2d = a.fusionObjects(fusobjs, method='Fusion2DMethod') else: f2d = None if fusion2d[0] is not None: a.deleteObjects(fusion2d[0]) else: a.removeObjects(fusion2d[1], awindows) if len(fusobjs) == 0: fusion2d = [] else: fusion2d = [f2d] + fusobjs # repalette( fusobjs ) if f2d: obj = f2d elif len(fusobjs) == 1: obj = fusobjs[0] else: return a.addObjects(obj, awindows, **opts) def addObject(self, obj): '''Display an object in all windows ''' opts = {} if obj.objectType == 'VOLUME': # volumes have a specific function since several volumes have to be # fusionned, and a volume rendering may occur self.addVolume(obj, opts) return elif obj.objectType == 'GRAPH': opts['add_graph_nodes'] = 1 a.addObjects(obj, awindows, **opts) def removeObject(self, obj): '''Hides an object from views ''' if obj.objectType == 'VOLUME': self.removeVolume(obj) else: a.removeObjects(obj, awindows, remove_children=True) def fileOpen(self): '''File browser + load object(s) ''' fdialog = Qt.QFileDialog() fdialog.setDirectory(self.filedialogdir) fdialog.setFileMode(fdialog.ExistingFiles) res = fdialog.exec_() if res: fnames = fdialog.selectedFiles() self.filedialogdir = fdialog.directory() for fname in fnames: self.loadObject(six.text_type(fname)) def selectedObjects(self): '''list of objects selected in the list box on the upper left panel ''' olist = findChild(awin, 'objectslist') sobjs = [] for o in olist.selectedItems(): sobjs.append(six.text_type(o.text()).strip('\0')) return [o for o in aobjects if o.name in sobjs] def editAdd(self): '''Display selected objects''' objs = self.selectedObjects() for o in objs: self.addObject(o) def editRemove(self): '''Hide selected objects''' objs = self.selectedObjects() for o in objs: self.removeObject(o) def editDelete(self): '''Delete selected objects''' objs = self.selectedObjects() for o in objs: self.removeObject(o) olist = findChild(awin, 'objectslist') for o in objs: olist.takeItem(olist.row(olist.findItems(o.name, Qt.Qt.MatchExactly)[0])) global aobjects aobjects = [o for o in aobjects if o not in objs] a.deleteObjects(objs) def closeAll(self): '''Exit''' print("Exiting") global vieww, awindows, fusion2d, aobjects, anasimple global awin, viewgridlay # remove windows from their parent to prevent them to be brutally # deleted by Qt. w = None # ensure there is a w variable before the "del" later for w in awindows: w.hide() viewgridlay.removeWidget(w.internalRep._get()) w.setParent(None) del w del viewgridlay, vieww del anasimple del awindows, fusion2d, aobjects awin.close() del awin a = ana.Anatomist() a.close() # instantiate the machine anasimple = AnaSimpleViewer() # connect GUI actions callbacks findChild(awin, 'fileOpenAction').triggered.connect(anasimple.fileOpen) findChild(awin, 'fileExitAction').triggered.connect(anasimple.closeAll) findChild(awin, 'editAddAction').triggered.connect(anasimple.editAdd) findChild(awin, 'editRemoveAction').triggered.connect(anasimple.editRemove) findChild(awin, 'editDeleteAction').triggered.connect(anasimple.editDelete) # display on the whole screen awin.showMaximized() # tweak: override some user config options a.config()['setAutomaticReferential'] = 1 a.config()['windowSizeFactor'] = 1. # run Qt if __name__ == '__main__': #run_qt = False if not 'sphinx_gallery' in sys.modules and run_qt: Qt.QApplication.instance().exec_() elif 'sphinx_gallery' in sys.modules: # load a data awin.showNormal() awin.resize(1000, 700) # control the size of the snapshot anasimple.loadObject('irm.ima') # these 2 events ensure things are actually drawn Qt.QApplication.instance().processEvents() Qt.QApplication.instance().processEvents() # snapshot the whole widget if Qt.QT_VERSION >= 0x050000: ws = awin.grab() # Qt5 only else: ws = Qt.QPixmap.grabWidget(awin) # Qt4 only # openGl areas are not rendered in the snapshot, we have to make them # by hand p = Qt.QPainter(ws) for w in awindows: s = w.snapshotImage() # draw the GL rendering into the image (pixmap) p.drawImage(w.mapTo(awin, Qt.QPoint(0, 0)), s) del w, s, p # snapshot to matplotlib import matplotlib #backend = matplotlib.get_backend() matplotlib.use('agg', force=True, warn=False) # force agg from matplotlib import pyplot im = qt_backend.qimage_to_np(ws) plot = pyplot.imshow(im) axes = pyplot.axes() axes.get_xaxis().set_visible(False) axes.get_yaxis().set_visible(False) pyplot.show(block=False) # matplotlib.use(backend, force=True) # restore backend if run_qt or 'sphinx_gallery' in sys.modules: anasimple.closeAll() .. rst-class:: sphx-glr-timing **Total running time of the script:** ( 0 minutes 3.762 seconds) .. _sphx_glr_download_auto_examples_anaevensimplerviewer.py: .. only :: html .. container:: sphx-glr-footer :class: sphx-glr-footer-example .. container:: sphx-glr-download :download:`Download Python source code: anaevensimplerviewer.py ` .. container:: sphx-glr-download :download:`Download Jupyter notebook: anaevensimplerviewer.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_