Beispiel #1
0
    def acquireFrame(self, allowBlanking=True):
        """Acquire one frame and emit sigNewFrame.
        """
        with self.lock:
            prot = self.protocol
            meta = self.metainfo
            rectSystem = self.system

        # Need to build task from a deep copy of the protocol because 
        # it will be modified after execution.
        task = self.manager.createTask(copy.deepcopy(prot))
        
        dur = prot['protocol']['duration']
        start = pg.ptime.time()
        endtime = start + dur - 0.005 

        # Start the task
        task.execute(block = False)

        # Wait until the task has finished
        while not task.isDone():
            with self.lock:
                abort = self._abort
            if abort:
                task.abort()
                self._abort = False
                raise Exception("Imaging acquisition aborted")
            now = pg.ptime.time()
            if now < endtime:
                # long sleep until we expect the protocol to be almost done
                time.sleep(min(0.1, endtime-now))
            else:
                time.sleep(5e-3)

        # Get acquired data and generate metadata
        data = task.getResult()
        pdDevice, pdChannel = meta['Photodetector']
        pmtData = data[pdDevice][pdChannel].view(np.ndarray)
        info = meta.copy()
        info['time'] = start

        info['deviceTranform'] = pg.SRTTransform3D(self.scannerDev.globalTransform())
        tr = rectSystem.imageTransform()
        info['transform'] = pg.SRTTransform3D(tr)

        frame = ImagingFrame(pmtData, rectSystem.copy(), info)
        self.sigNewFrame.emit(frame)
Beispiel #2
0
    def newFrames(self):
        """Return a list of all frames acquired since the last call to newFrames."""
        now = ptime.time()

        dt = now - self.lastFrameTime
        exp = self.getParam('exposure')
        bin = self.getParam('binning')
        fps = 1.0 / (exp + (40e-3 / (bin[0] * bin[1])))
        nf = int(dt * fps)
        if nf == 0:
            return []

        region = self.getParam('region')
        bg = self.getBackground()[region[0]:region[0] + region[2],
                                  region[1]:region[1] + region[3]]

        ## update cells
        spikes = np.random.poisson(min(dt, 0.4) * self.cells['rate'])
        self.cells['value'] *= np.exp(-dt / self.cells['decayTau'])
        self.cells['value'] = np.clip(self.cells['value'] + spikes * 0.2, 0, 1)
        shape = region[2:]
        self.lastFrameTime = now + exp
        data = self.getNoise(shape)
        data[data < 0] = 0

        data += bg * (exp * 1000)

        ## draw cells
        px = (self.pixelVectors()[0]**2).sum()**0.5

        ## Generate transform that maps grom global coordinates to image coordinates
        cameraTr = pg.SRTTransform3D(self.inverseGlobalTransform())
        # note we use binning=(1,1) here because the image is downsampled later.
        frameTr = self.makeFrameTransform(region, [1, 1]).inverted()[0]
        tr = pg.SRTTransform(frameTr * cameraTr)

        for cell in self.cells:
            w = cell['size'] / px
            pos = pg.Point(cell['x'], cell['y'])
            imgPos = tr.map(pos)
            start = (int(imgPos.x()), int(imgPos.y()))
            stop = (int(start[0] + w), int(start[1] + w))
            val = cell['intensity'] * cell['value'] * self.getParam('exposure')
            data[max(0, start[0]):max(0, stop[0]),
                 max(0, start[1]):max(0, stop[1])] += val

        data = fn.downsample(data, bin[0], axis=0)
        data = fn.downsample(data, bin[1], axis=1)
        data = data.astype(np.uint16)

        self.frameId += 1
        frames = []
        for i in range(nf):
            frames.append({
                'data': data,
                'time': now + (i / fps),
                'id': self.frameId
            })
        return frames
Beispiel #3
0
    def posChanged(self, pos):
        """Handle device position changes by updating the device transform and
        emitting sigPositionChanged.

        Subclasses must call this method when the device position has changed.
        """
        with self.lock:
            rel = [0] * len(self.pos)
            rel[:len(pos)] = [pos[i] - self.pos[i] for i in range(len(pos))]
            self.pos[:len(pos)] = pos

            self._stageTransform = pg.SRTTransform3D()
            self._stageTransform.translate(*self.pos)
            self._invStageTransform = pg.SRTTransform3D()
            self._invStageTransform.translate(*[-x for x in self.pos])
            self._updateTransform()
        self.sigPositionChanged.emit({'rel': rel, 'abs': self.pos[:]})

        self.checkSwitchChange(self.pos)
Beispiel #4
0
 def setDeviceTransform(self, tr):
     with self.__lock:
         self.__transform = pg.SRTTransform3D(tr)
         self.invalidateCachedTransforms()
     #print "setDeviceTransform", self
     #print "   -> emit sigTransformChanged"
     #import traceback
     #traceback.print_stack()
     
     self.sigTransformChanged.emit(self)
Beispiel #5
0
    def setStageOrientation(self, angle, inverty):
        tr = pg.SRTTransform3D(self.parentDevice().baseTransform())
        tr.setScale(1, -1 if inverty else 1)
        tr.setRotate(angle)
        self.parentDevice().setBaseTransform(tr)

        cal = self.readConfigFile('calibration')
        cal['angle'] = angle
        cal['inverty'] = inverty
        self._stageOrientation = cal
        self.writeConfigFile(cal, 'calibration')
Beispiel #6
0
    def posChanged(self, data):
        with self.lock:
            rel = [0] * len(self.pos)
            if 'rel' in data:
                rel[:len(data['rel'])] = data['rel']
            else:
                rel[:len(data['abs'])] = [
                    data['abs'][i] - self.pos[i]
                    for i in range(len(data['abs']))
                ]
            self.pos[:len(data['abs'])] = data['abs']
        self.sigPositionChanged.emit({'rel': rel, 'abs': self.pos[:]})

        tr = pg.SRTTransform3D()
        tr.translate(*self.pos)
        self.setDeviceTransform(
            tr)  ## this informs rigidly-connected devices that they have moved
Beispiel #7
0
 def __computeGlobalTransform(self, subdev=None, inverse=False):
     ## subdev must be a dict
     with self.__lock:
         devices = self.parentDevices()
         transform = pg.SRTTransform3D()
         for d in devices:
             tr = d.deviceTransform(subdev)
             if tr is None:
                 self.__globalTransform = None
                 return None
             transform = tr * transform
             
     if inverse:
         inv, invertible = transform.inverted()
         if not invertible:
             raise Exception("Transform is not invertible.")
         return inv
     else:
         return transform
Beispiel #8
0
 def __init__(self, dm, config, name):
     object.__init__(self)
     
     ## create proxy object and wrap in its signals
     self.__sigProxy = OptomechDevice.SignalProxyObject()
     self.sigTransformChanged = self.__sigProxy.sigTransformChanged
     self.sigGlobalTransformChanged = self.__sigProxy.sigGlobalTransformChanged
     self.sigSubdeviceTransformChanged = self.__sigProxy.sigSubdeviceTransformChanged
     self.sigGlobalSubdeviceTransformChanged = self.__sigProxy.sigGlobalSubdeviceTransformChanged
     self.sigSubdeviceChanged = self.__sigProxy.sigSubdeviceChanged
     self.sigGlobalSubdeviceChanged = self.__sigProxy.sigGlobalSubdeviceChanged
     self.sigSubdeviceListChanged = self.__sigProxy.sigSubdeviceListChanged
     self.sigGlobalSubdeviceListChanged = self.__sigProxy.sigGlobalSubdeviceListChanged
     
     self.__devManager = dm
     self.__config = config
     self.__children = []
     self.__parent = None
     self.__globalTransform = 0  ## 0 indicates the cache is invalid. None indicates the transform is non-affine.
     self.__inverseGlobalTransform = 0
     self.__transform = pg.SRTTransform3D()
     self.__inverseTransform = 0
     self.__lock = Mutex(recursive=True)
     self.__subdevices = collections.OrderedDict()
     self.__subdevice = None
     self.__name = name
     
     self.sigTransformChanged.connect(self.__emitGlobalTransformChanged)
     self.sigSubdeviceTransformChanged.connect(self.__emitGlobalSubdeviceTransformChanged)
     self.sigSubdeviceChanged.connect(self.__emitGlobalSubdeviceChanged)
     self.sigSubdeviceListChanged.connect(self.__emitGlobalSubdeviceListChanged)
     if config is not None:
         if 'parentDevice' in config:
             try:
                 self.setParentDevice(config['parentDevice'])
             except Exception as ex:
                 if "No device named" in ex.message:
                     print "Cannot set parent device %s; no device by that name." % config['parentDevice']
                 else:
                     raise
         if 'transform' in config:
             self.setDeviceTransform(config['transform'])
Beispiel #9
0
    def __computeGlobalTransform(self, subdev=None, inverse=False):
        ## subdev must be a dict
        parent = self.parentDevice()
        if parent is None:
            parentTr = pg.SRTTransform3D()
        else:
            parentTr = parent.globalTransform(subdev)
        if parentTr is None:
            return None
        deviceTr = self.deviceTransform(subdev)
        if deviceTr is None:
            return None

        transform = parentTr * deviceTr

        if inverse:
            inv, invertible = transform.inverted()
            if not invertible:
                raise Exception("Transform is not invertible.")
            return inv
        else:
            return transform
Beispiel #10
0
 def setPosition(self, pos):
     self.pos = pos
     tr = pg.SRTTransform3D()
     tr.translate(pos)
     self.setDeviceTransform(tr)
     self.sigPositionChanged.emit(self)
Beispiel #11
0
 def deviceTransform(self):
     return pg.SRTTransform3D(OptomechDevice.deviceTransform(self))
Beispiel #12
0
    def setDeviceTransform(self, tr):
        OptomechDevice.setDeviceTransform(self, tr)

        cal = self.readConfigFile('calibration')
        cal['transform'] = pg.SRTTransform3D(tr)
        self.writeConfigFile(cal, 'calibration')
Beispiel #13
0
    def __init__(self, dm, config, name):
        object.__init__(self)

        ## create proxy object and wrap in its signals
        self.__sigProxy = OptomechDevice.SignalProxyObject()
        self.sigTransformChanged = self.__sigProxy.sigTransformChanged
        self.sigGlobalTransformChanged = self.__sigProxy.sigGlobalTransformChanged
        self.sigSubdeviceTransformChanged = self.__sigProxy.sigSubdeviceTransformChanged
        self.sigGlobalSubdeviceTransformChanged = self.__sigProxy.sigGlobalSubdeviceTransformChanged
        self.sigOpticsChanged = self.__sigProxy.sigOpticsChanged
        self.sigGlobalOpticsChanged = self.__sigProxy.sigGlobalOpticsChanged
        self.sigSubdeviceChanged = self.__sigProxy.sigSubdeviceChanged
        self.sigGlobalSubdeviceChanged = self.__sigProxy.sigGlobalSubdeviceChanged
        self.sigSubdeviceListChanged = self.__sigProxy.sigSubdeviceListChanged
        self.sigGlobalSubdeviceListChanged = self.__sigProxy.sigGlobalSubdeviceListChanged

        self.__devManager = dm
        self.__config = config
        self.__name = name

        # __ports is a list of port names to which devices may be attached.
        # Most devices will have a single port called 'default' to which all children attach.
        # In some cases, the device has a specific set of named ports where children
        # can be attached (eg: a dichroic filter cube might have "excitation" and "emission" ports).
        self.__ports = []

        # All devices have 0 or 1 parent
        self.__parent = None
        # When connected to a parent device, we also optionally specify *where* on
        # the device to connect (usually this is just 'default').
        self.__parentPort = None

        # keep track of children so that we can inform them quickly when a parent transform has changed
        self.__children = []

        # Cached transforms from this device to global
        # 0 indicates the cache is invalid. None indicates the transform is non-affine,
        # and might not be cacheable.
        self.__globalTransform = 0
        self.__inverseGlobalTransform = 0

        # Transformation from this device to its parent (or to global if there is no parent)
        self.__transform = pg.SRTTransform3D()
        # Cached inverse of __transform
        self.__inverseTransform = 0

        # Contains {port: [list of optics]} describing the optics (usually filters) for each port
        self.__optics = {}

        # Swappable sub-devices. (eg: objective changers, filter wheels)
        self.__subdevices = collections.OrderedDict()
        self.__subdevice = None

        self.__lock = Mutex(recursive=True)

        self.sigTransformChanged.connect(self.__emitGlobalTransformChanged)
        self.sigSubdeviceTransformChanged.connect(
            self.__emitGlobalSubdeviceTransformChanged)
        self.sigOpticsChanged.connect(self.__emitGlobalOpticsChanged)
        self.sigSubdeviceChanged.connect(self.__emitGlobalSubdeviceChanged)
        self.sigSubdeviceListChanged.connect(
            self.__emitGlobalSubdeviceListChanged)

        if config is not None:
            if 'parentDevice' in config:
                try:
                    parent = config['parentDevice']
                    if isinstance(parent, str):
                        self.setParentDevice(parent)
                    elif isinstance(parent, dict) and 'name' in parent:
                        self.setParentDevice(parent['name'],
                                             port=parent.get(
                                                 'port', 'default'))
                    else:
                        raise TypeError(
                            "Invalid parent device specification: %s" %
                            repr(parent))

                except Exception as ex:
                    if "No device named" in ex.args[0]:
                        print(
                            "Cannot set parent device %s; no device by that name."
                            % repr(config['parentDevice']))
                    else:
                        raise

            if 'transform' in config:
                self.setDeviceTransform(config['transform'])

            self.__ports = config.get('ports', ['default'])
            assert isinstance(self.__ports, list)
            self.__optics = config.get('optics', {'default': []})
            assert isinstance(self.__optics, dict)

        # declare that this device supports the OptomechDevice API
        self.addInterface('OptomechDevice')
Beispiel #14
0
    def update(self):
        self.lastResult = []
        frame = self.lastFrame
        if frame is None:
            self.clear()
            return
        # imageDownSample = self.ui.downSampling.value() # this is the "image" downsample,
        # get the downsample for the daq. This is far more complicated than it should be...

        # Get PMT signal(s)
        pmtdata = []
        for detector in self.params.param('detectors'):
            data = frame['result'][detector.value()]["Channel":'Input']
            t = data.xvals('Time')
            pmtdata.append(data.asarray())
        
        if len(pmtdata) == 0:
            return

        # parse program options
        scanCmd = frame['cmd'][self.params['scanner']]
        if 'program' not in scanCmd:
            return
        progs = scanCmd['program']
        if len(progs) == 0:
            self.image.setImage(np.zeros((1,1)))
            return

        # Update list so user can select program component
        supportedTypes = ['rect']
        progs = dict([(prog['name'], prog) for prog in progs if prog['type'] in supportedTypes])
        self.params.child('scanProgram').setLimits(progs.keys())
        selectedProg = self.params['scanProgram']
        if selectedProg not in progs:
            return
        prog = progs[selectedProg]
        
        if prog['type'] == 'rect':
            # keep track of some analysis in case it should be stored later
            result = {
                'params': self.params.saveState(filter='user')['children'],
                'pmtdata': pmtdata,
            }
            self.lastResult.append(result)

            rs = RectScan()
            rs.restoreState(prog['scanInfo'])
            result['scanParams'] = rs

            decomb = self.params['decomb']
            
            # Extract from PMT array
            imageData = []
            for chan in pmtdata:
                chanImage = rs.extractImage(chan, offset=decomb, subpixel=self.params['decomb', 'subpixel'])
                imageData.append(chanImage.reshape(chanImage.shape + (1,)))
                
            if len(imageData) == 1:
                imageData = imageData[0]
                levelMode = 'mono'
            else:
                if len(imageData) == 2:
                    imageData.append(np.zeros(imageData[0].shape, dtype=imageData[0].dtype))
                imageData = np.concatenate(imageData, axis=-1)
                levelMode = 'rgba'

            if imageData.size == 0:
                self.clear()
                raise Exception('image Data has zero size')

            # Downsample
            ds = self.params['downsample']
            if ds > 1:
                imageData = pg.downsample(imageData, ds, axis=2)

            # Collected as (frame, row, col) but pg prefers images like (frame, col, row)
            imageData = imageData.transpose((0, 2, 1, 3)[:imageData.ndim])
            result['image'] = imageData

            # compute global transform
            tr = rs.imageTransform()
            st = pg.QtGui.QTransform()
            st.scale(self.params['downsample'], 1)
            tr = st * tr
            result['transform'] = pg.SRTTransform3D(tr)

            frameTimes = rs.frameTimes()

            # Display image locally
            self.imageView.setImage(imageData, xvals=frameTimes, levelMode=levelMode)
            self.imageView.getView().setAspectLocked(True)
#            self.imageView.imageItem.setRect(QtCore.QRectF(0., 0., rs.width, rs.height))  # TODO: rs.width and rs.height might not be correct!
            self.imageView.imageItem.resetTransform()
            self.imageView.imageItem.scale((rs.width/rs.height)/(imageData.shape[1]/imageData.shape[2]), 1.0)
            self.imageView.autoRange()

            # Display image remotely (in the same camera module as used by the scanner device)
            if self.params['display']:
                self.img.setVisible(True)
                sd = self.pr.getDevice(self.params['scanner'])
                camMod = sd.cameraModule().window()
                camMod.addItem(self.img, z=1000)
                self.img.setImage(imageData.mean(axis=0))
                self.img.setTransform(tr)
            else:
                self.img.setVisible(False)
        else:
            raise Exception("Imaging module only supports rect scans (not %s)." % prog['type'])
Beispiel #15
0
    def __init__(self, image=None, **opts):
        """
        CanvasItem displaying an image. 
        The image may be 2 or 3-dimensional.
        Options:
            image: May be a fileHandle, ndarray, or GraphicsItem.
            handle: May optionally be specified in place of image

        """

        ## If no image was specified, check for a file handle..
        if image is None:
            image = opts.get('handle', None)

        item = None
        self.data = None
        self.currentT = None

        if isinstance(image, QtGui.QGraphicsItem):
            item = image
        elif isinstance(image, np.ndarray):
            self.data = image
        elif isinstance(image, DataManager.FileHandle):
            opts['handle'] = image
            self.handle = image
            self.data = self.handle.read()

            if 'name' not in opts:
                opts['name'] = self.handle.shortName()

            try:
                if 'transform' in self.handle.info():
                    tr = pg.SRTTransform3D(self.handle.info()['transform'])
                    tr = pg.SRTTransform(tr)  ## convert to 2D
                    opts['pos'] = tr.getTranslation()
                    opts['scale'] = tr.getScale()
                    opts['angle'] = tr.getRotation()
                else:  ## check for older info formats
                    if 'imagePosition' in self.handle.info():
                        opts['scale'] = self.handle.info()['pixelSize']
                        opts['pos'] = self.handle.info()['imagePosition']
                    elif 'Downsample' in self.handle.info():
                        ### Needed to support an older format stored by 2p imager
                        if 'pixelSize' in self.handle.info():
                            opts['scale'] = self.handle.info()['pixelSize']
                        if 'microscope' in self.handle.info():
                            m = self.handle.info()['microscope']
                            print 'm: ', m
                            print 'mpos: ', m['position']
                            opts['pos'] = m['position'][0:2]
                        else:
                            info = self.data._info[-1]
                            opts['pos'] = info.get('imagePosition', None)
                    elif hasattr(self.data, '_info'):
                        info = self.data._info[-1]
                        opts['scale'] = info.get('pixelSize', None)
                        opts['pos'] = info.get('imagePosition', None)
                    else:
                        opts['defaultUserTransform'] = {'scale': (1e-5, 1e-5)}
                        opts['scalable'] = True
            except:
                debug.printExc(
                    'Error reading transformation for image file %s:' %
                    image.name())

        if item is None:
            item = pg.ImageItem()
        CanvasItem.__init__(self, item, **opts)

        self.histogram = pg.PlotWidget()
        self.blockHistogram = False
        self.histogram.setMaximumHeight(100)
        self.levelRgn = pg.LinearRegionItem()
        self.histogram.addItem(self.levelRgn)
        self.updateHistogram(autoLevels=True)

        # addWidget arguments: row, column, rowspan, colspan
        self.layout.addWidget(self.histogram, self.layout.rowCount(), 0, 1, 3)

        self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
        #self.timeSlider.setMinimum(0)
        #self.timeSlider.setMaximum(self.data.shape[0]-1)
        self.layout.addWidget(self.timeSlider, self.layout.rowCount(), 0, 1, 3)
        self.timeSlider.valueChanged.connect(self.timeChanged)
        self.timeSlider.sliderPressed.connect(self.timeSliderPressed)
        self.timeSlider.sliderReleased.connect(self.timeSliderReleased)
        thisRow = self.layout.rowCount()

        self.edgeBtn = QtGui.QPushButton('Edge')
        self.edgeBtn.clicked.connect(self.edgeClicked)
        self.layout.addWidget(self.edgeBtn, thisRow, 0, 1, 1)

        self.meanBtn = QtGui.QPushButton('Mean')
        self.meanBtn.clicked.connect(self.meanClicked)
        self.layout.addWidget(self.meanBtn, thisRow + 1, 0, 1, 1)

        self.tvBtn = QtGui.QPushButton('tv denoise')
        self.tvBtn.clicked.connect(self.tvClicked)
        self.layout.addWidget(self.tvBtn, thisRow + 2, 0, 1, 1)

        self.maxBtn = QtGui.QPushButton('Max no Filter')
        self.maxBtn.clicked.connect(self.maxClicked)
        self.layout.addWidget(self.maxBtn, thisRow, 1, 1, 1)

        self.maxBtn2 = QtGui.QPushButton('Max w/Gaussian')
        self.maxBtn2.clicked.connect(self.max2Clicked)
        self.layout.addWidget(self.maxBtn2, thisRow + 1, 1, 1, 1)

        self.maxMedianBtn = QtGui.QPushButton('Max w/Median')
        self.maxMedianBtn.clicked.connect(self.maxMedianClicked)
        self.layout.addWidget(self.maxMedianBtn, thisRow + 2, 1, 1, 1)

        self.filterOrder = QtGui.QComboBox()
        self.filterLabel = QtGui.QLabel('Order')
        for n in range(1, 11):
            self.filterOrder.addItem("%d" % n)
        self.layout.addWidget(self.filterLabel, thisRow + 3, 2, 1, 1)
        self.layout.addWidget(self.filterOrder, thisRow + 3, 3, 1, 1)

        self.zPlanes = QtGui.QComboBox()
        self.zPlanesLabel = QtGui.QLabel('# planes')
        for s in ['All', '1', '2', '3', '4', '5']:
            self.zPlanes.addItem("%s" % s)
        self.layout.addWidget(self.zPlanesLabel, thisRow + 3, 0, 1, 1)
        self.layout.addWidget(self.zPlanes, thisRow + 3, 1, 1, 1)

        ## controls that only appear if there is a time axis
        self.timeControls = [
            self.timeSlider, self.edgeBtn, self.maxBtn, self.meanBtn,
            self.maxBtn2, self.maxMedianBtn, self.filterOrder, self.zPlanes
        ]

        if self.data is not None:
            self.updateImage(self.data)

        self.graphicsItem().sigImageChanged.connect(self.updateHistogram)
        self.levelRgn.sigRegionChanged.connect(self.levelsChanged)
        self.levelRgn.sigRegionChangeFinished.connect(
            self.levelsChangeFinished)
Beispiel #16
0
    def __init__(self, image=None, **opts):

        ## If no image was specified, check for a file handle..
        if image is None:
            image = opts.get('handle', None)

        item = None
        self.data = None

        if isinstance(image, QtGui.QGraphicsItem):
            item = image
        elif isinstance(image, np.ndarray):
            self.data = image
        elif isinstance(image, DataManager.FileHandle):
            opts['handle'] = image
            self.handle = image
            self.data = self.handle.read()

            if 'name' not in opts:
                opts['name'] = self.handle.shortName()

            try:
                if 'transform' in self.handle.info():
                    tr = pg.SRTTransform3D(self.handle.info()['transform'])
                    tr = pg.SRTTransform(tr)  ## convert to 2D
                    opts['pos'] = tr.getTranslation()
                    opts['scale'] = tr.getScale()
                    opts['angle'] = tr.getRotation()
                else:  ## check for older info formats
                    if 'imagePosition' in self.handle.info():
                        opts['scale'] = self.handle.info()['pixelSize']
                        opts['pos'] = self.handle.info()['imagePosition']
                    elif 'Downsample' in self.handle.info():
                        ### Needed to support an older format stored by 2p imager
                        if 'pixelSize' in self.handle.info():
                            opts['scale'] = self.handle.info()['pixelSize']
                        if 'microscope' in self.handle.info():
                            m = self.handle.info()['microscope']
                            opts['pos'] = m['position'][0:2]
                        else:
                            info = self.data._info[-1]
                            opts['pos'] = info.get('imagePosition', None)
                    elif hasattr(self.data, '_info'):
                        info = self.data._info[-1]
                        opts['scale'] = info.get('pixelSize', None)
                        opts['pos'] = info.get('imagePosition', None)
                    else:
                        opts['defaultUserTransform'] = {'scale': (1e-5, 1e-5)}
                        opts['scalable'] = True
            except:
                debug.printExc(
                    'Error reading transformation for image file %s:' %
                    image.name())

        if item is None:
            item = pg.ImageItem()
        CanvasItem.__init__(self, item, **opts)

        self.splitter = QtGui.QSplitter()
        self.splitter.setOrientation(QtCore.Qt.Vertical)
        self.layout.addWidget(self.splitter, self.layout.rowCount(), 0, 1, 2)

        self.filterGroup = pg.GroupBox("Image Filter")
        fgl = QtGui.QGridLayout()
        fgl.setContentsMargins(3, 3, 3, 3)
        fgl.setSpacing(1)
        self.filterGroup.setLayout(fgl)
        self.filter = ImageFilterWidget()
        self.filter.sigStateChanged.connect(self.filterStateChanged)
        fgl.addWidget(self.filter)
        self.splitter.addWidget(self.filterGroup)

        self.histogram = pg.HistogramLUTWidget()
        self.histogram.setImageItem(self.graphicsItem())

        # addWidget arguments: row, column, rowspan, colspan
        self.splitter.addWidget(self.histogram)

        self.imgModeCombo = QtGui.QComboBox()
        self.imgModeCombo.addItems(
            ['SourceOver', 'Overlay', 'Plus', 'Multiply'])
        self.layout.addWidget(self.imgModeCombo, self.layout.rowCount(), 0, 1,
                              1)
        self.imgModeCombo.currentIndexChanged.connect(self.imgModeChanged)

        self.autoBtn = QtGui.QPushButton("Auto")
        self.autoBtn.setCheckable(True)
        self.autoBtn.setChecked(True)
        self.layout.addWidget(self.autoBtn,
                              self.layout.rowCount() - 1, 1, 1, 1)

        self.timeSlider = QtGui.QSlider(QtCore.Qt.Horizontal)
        self.layout.addWidget(self.timeSlider, self.layout.rowCount(), 0, 1, 2)
        self.timeSlider.valueChanged.connect(self.timeChanged)

        # ## controls that only appear if there is a time axis
        self.timeControls = [self.timeSlider]

        if self.data is not None:
            if isinstance(self.data, pg.metaarray.MetaArray):
                self.filter.setInput(self.data.asarray())
            else:
                self.filter.setInput(self.data)
            self.updateImage()

            # Needed to ensure selection box wraps the image properly
            tr = self.saveTransform()
            self.resetUserTransform()
            self.restoreTransform(tr)
Beispiel #17
0
 def setDeviceTransform(self, tr):
     with self.__lock:
         self.__transform = pg.SRTTransform3D(tr)
         self.invalidateCachedTransforms()
     
     self.sigTransformChanged.emit(self)