Example #1
0
 def addActiveRegion(self, rgnType):
     rgn = pTypes.SimpleParameter(name=rgnType, autoIncrementName=True,
                                  type='bool', value=True, 
                                  removable=True, renamable=True)
     self.params.param('Active Regions').addChild(rgn)
     pos = self.getViewBox().viewRect().center() 
     size = self.params.param('spacing').value()*4
     
     if rgnType == 'Rectangle':
         roi = pg.ROI(pos=pos, size=size, angle=self.angle())
         roi.addScaleHandle([0, 0], [1, 1])
         roi.addScaleHandle([1, 1], [0, 0])
         roi.addRotateHandle([0, 1], [0.5, 0.5])
         roi.addRotateHandle([1, 0], [0.5, 0.5])
     elif rgnType == 'Polygon':
         roi = pg.PolyLineROI((pos, pos+pg.Point(0,1)*size, pos+pg.Point(1,0)*size), closed=True)
     else:
         raise Exception('Not sure how to add region of type:%s' % rgnType)
     
     rgn.item = roi
     self.rgns.append(rgn)
     self.getViewBox().addItem(roi)
     roi.sigRegionChanged.connect(self.invalidatePoints)
     roi.sigRegionChangeFinished.connect(self.stateChangeFinished)
     rgn.sigValueChanged.connect(self.rgnToggled)
     self.invalidatePoints()
     self.stateChangeFinished()
Example #2
0
    def addNew(self):
        rgn = ptree.Parameter.create(name='region',
                                     autoIncrementName=True,
                                     renamable=True,
                                     removable=True,
                                     type='bool',
                                     value=True,
                                     children=[
                                         dict(name='DB Column',
                                              type='str',
                                              value='Region'),
                                         dict(name='Color', type='color'),
                                     ])
        self.addChild(rgn)

        ## find the center of the view
        view = self.canvas.view
        center = view.viewRect().center()
        size = [x * 50 for x in view.viewPixelSize()]
        pts = [
            center, center + pg.Point(size[0], 0),
            center + pg.Point(0, size[1])
        ]

        roi = pg.PolyLineROI(pts, closed=True)
        roi.setZValue(1000)
        view.addItem(roi)
        rgn.roi = roi
        roi.rgn = rgn
        roi.sigRegionChangeFinished.connect(self.regionChanged)
Example #3
0
 def saveState(self):
     ## Saves the position/configuration of the cortexROI, as well as transforms for mapping to atlas coordinates
     
     if self.sliceDir is None:
         return       
    
     ## get state of ROI
     cortexROI = self.roi.saveState()
     quads = self.roi.getQuadrilaterals()
     newQuads = []
     for q in quads:
         newQuads.append([(p.x(), p.y()) for p in q])
     rects = self.roi.getNormalizedRects()
     matrices = []
     for i, q in enumerate(quads):
         matrix = self.atlas.solveBilinearTransform([pg.Point(x) for x in q], [pg.Point(x) for x in rects[i]])
         matrices.append([list(matrix[0]), list(matrix[1])])
     
     state = {
         'cortexROI':cortexROI,
         'quadrilaterals':newQuads,
         'normalizedRects': rects,
         'transformMatrices': matrices
     }
     
     ## write to slice directory meta-info
     atlasInfo = self.sliceDir.info().get('atlas', {}).deepcopy()
     atlasInfo[self.atlas.name()] = state
     self.sliceDir.setInfo(atlas=atlasInfo)
     
     ## set state for atlas object
     self.atlas.setState(state)       
Example #4
0
    def getBackground(self):
        if self.background is None:
            w, h = self.params['sensorSize']

            tr = self.globalTransform()
            tr = pg.SRTTransform(tr)
            m = QtGui.QTransform()
            m.scale(3e6, 3e6)
            m.translate(0.0005, 0.0005)
            tr = tr * m

            origin = tr.map(pg.Point(0, 0))
            x = (tr.map(pg.Point(1, 0)) - origin)
            y = (tr.map(pg.Point(0, 1)) - origin)
            origin = np.array([origin.x(), origin.y()])
            x = np.array([x.x(), x.y()])
            y = np.array([y.x(), y.y()])

            ## slice fractal from pre-rendered data
            vectors = (x, y)
            self.background = pg.affineSlice(self.bgData, (w, h),
                                             origin,
                                             vectors, (0, 1),
                                             order=1)

        return self.background
Example #5
0
    def transformChanged(self):
        # manipulator's global transform has changed; update the center arrow and orientation axis
        dev = self.getDevice()
        pos = dev.mapToGlobal([0, 0, 0])
        x = dev.mapToGlobal([1, 0, 0])

        p1 = pg.Point(x[:2])
        p2 = pg.Point(pos[:2])
        p3 = pg.Point(1, 0)
        angle = (p1 - p2).angle(p3)
        if angle is None:
            angle = 0

        self.centerArrow.setPos(pos[0], pos[1])
        self.centerArrow.setStyle(angle=180 - angle)
        # self.depthLine.setValue(pos[2])
        self.depthArrow.setPos(0, pos[2])

        self.target.setLabelAngle(dev.getYawAngle())

        if self.ui.setOrientationBtn.isChecked():
            return

        with pg.SignalBlock(self.calibrateAxis.sigRegionChangeFinished,
                            self.calibrateAxisChanged):
            self.calibrateAxis.setPos(pos[:2])
            self.calibrateAxis.setAngle(angle)
            ys = self.calibrateAxis.size()[1]
Example #6
0
    def addROI(self, roiType):
        pen = pg.mkPen(pg.intColor(len(self.ROIs)))
        center = self.view.viewRect().center()
        #print 'camerawindow.py: addROI:: ', self.view.viewPixelSize()
        size = [x * 50 for x in self.view.viewPixelSize()]
        if roiType == 'rect':
            roi = PlotROI(center, size)
        elif roiType == 'ellipse':
            roi = pg.EllipseROI(center, size, removable=True)
        elif roiType == 'polygon':
            pts = [
                center, center + pg.Point(0, size[1]),
                center + pg.Point(size[0], 0)
            ]
            roi = pg.PolyLineROI(pts, closed=True, removable=True)
        elif roiType == 'ruler':
            pts = [center, center + pg.Point(size[0], size[1])]
            roi = RulerROI(pts, removable=True)
        else:
            raise ValueError("Invalid ROI type %s" % roiType)

        roi.setZValue(40000)
        roi.setPen(pen)
        self.view.addItem(roi)
        plot = self.roiPlot.plot(pen=pen)
        self.ROIs.append({'roi': roi, 'plot': plot, 'vals': [], 'times': []})
        roi.sigRemoveRequested.connect(self.removeROI)
Example #7
0
 def boundingRect(self):
     w = self.pixelLength(pg.Point(1, 0))
     if w is None:
         return QtCore.QRectF()
     w *= 25
     h = 25 * self.pixelLength(pg.Point(0, 1))
     r = QtCore.QRectF(-w * 2, -h * 2, w * 4, h * 4)
     return r
Example #8
0
    def pixelVectors(self):
        tr = self.globalTransform()
        origin = tr.map(pg.Point(0, 0))
        x = (tr.map(pg.Point(1, 0)) - origin)
        y = (tr.map(pg.Point(0, 1)) - origin)
        origin = np.array([origin.x(), origin.y()])
        x = np.array([x.x(), x.y()])
        y = np.array([y.x(), y.y()])

        return x, y
Example #9
0
    def setScanPosFromRoi(self):
        # Update the position of the scan rectangle from the ROI
        roi = self.currentRoi
        w, h = roi.size()
        
        # get top-left ROI corner in global coordinates
        p0 = roi.mapToView(pg.Point(0,h))
        if p0 is None:
            # could not map point; probably view has been closed.
            return 

        rparam = self.scanProgram.components[0].ctrlParameter()
        rparam.system.p0 = pg.Point(p0)  # top-left
        rparam.system.p1 = pg.Point(roi.mapToView(pg.Point(w,h)))  # rop-right
Example #10
0
 def viewTransformChanged(self):
     w = self.pixelLength(pg.Point(1, 0))
     if w is None:
         self._pxLen = [None, None]
         return
     h = self.pixelLength(pg.Point(0, 1))
     if self.size()[1] < 0:
         h = -h
     self._pxLen = [w, h]
     self.blockSignals(True)
     try:
         self.setSize([w * 50, h * 50])
     finally:
         self.blockSignals(False)
     self.updateText()
     self.prepareGeometryChange()
Example #11
0
 def restoreROI(self):
     
     if self.storedROI is not None:
         (width, height, x, y) = self.storedROI
         self.currentRoi.setSize([width, height])
         self.currentRoi.setPos([x, y])
         self.roiChanged()
     else:
         cpos = self.cameraModule.ui.view.viewRect().center() # center position, stage coordinates
         csize = pg.Point([x*400 for x in self.cameraModule.ui.view.viewPixelSize()])
         width  = csize[0]*2 # width is x in M
         height = csize[1]*2
         csize = pg.Point(width, height)
         cpos = cpos - csize/2.
         self.currentRoi.setSize([width, height])
         self.currentRoi.setPos(cpos)
Example #12
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
Example #13
0
 def getSnapPosition(self, pos):
     ## Given that pos has been requested, return the nearest snap-to position
     ## optionally, snap may be passed in to specify a rectangular snap grid.
     ## override this function for more interesting snap functionality..
 
     layout = self.params['layout']
     spacing = self.params['spacing']
     
     if layout == 'Square':
         snap = pg.Point(spacing, spacing)
         w = round(pos[0] / snap[0]) * snap[0]
         h = round(pos[1] / snap[1]) * snap[1]
         return pg.Point(w, h)
     
     elif layout == 'Hexagonal':
         snap1 = pg.Point(spacing, spacing*3.0**0.5)
         dx = 0.5*snap1[0]
         dy = 0.5*snap1[1]
         w1 = round(pos[0] / snap1[0]) * snap1[0]
         h1 = round(pos[1] / snap1[1]) * snap1[1]
         w2 = round((pos[0]-dx) / snap1[0]) * snap1[0] + dx
         h2 = round((pos[1]-dy) / snap1[1]) * snap1[1] + dy
         if (pg.Point(w1, h1)-pos).length() < (pg.Point(w2,h2) - pos).length():
             return pg.Point(w1, h1)
         else:
             return pg.Point(w2, h2)
Example #14
0
 def saveState(self):
     center = self.roi.mapToView(pg.Point(0, 0))
     return {
         'startTime': self.params['startTime'],
         'duration': self.params['duration'],
         'radius': self.params['radius'],
         'thickness': self.params['thickness'],
         'spacing': self.params['spacing'],
         'center': (center.x(), center.y()),
     }
Example #15
0
 def targetChanged(self, dev, pos):
     self.target.setPos(pg.Point(pos[:2]))
     self.depthTarget.setPos(0, pos[2])
     self.target.setVisible(True)
     self._haveTarget = True
     self.depthTarget.setVisible(True)
     self.ui.targetBtn.setEnabled(True)
     self.ui.approachBtn.setEnabled(True)
     self.ui.setTargetBtn.setChecked(False)
     self.focusChanged()
Example #16
0
    def generatePoints(self):
        layout = self.params['layout']

        # get x/y point spacing
        sepx = sepy = self.params['spacing']
        if layout == 'Hexagonal':
            sepy *= 3 ** 0.5

        # find grid points inside each active region
        points = []
        for rgn in self.rgns:
            if not rgn.value():
                continue
            roi = rgn.item
            rect = self.mapFromItem(roi, roi.boundingRect()).boundingRect()

            ## find 'snap' position of first spot
            newPos = self.getSnapPosition((rect.x(), rect.y()))
            x = newPos.x() - sepx
            y = newPos.y() - sepy
            w = rect.width() + 2*sepx
            h = rect.height() + 2*sepy

            if layout == "Hexagonal":
                # make every other row of the grid starting from top
                points.append(self.generateGrid([x, y], [x+w, y+h], [sepx, sepy]))
                # make every other row of the grid starting with 2nd row
                points.append(self.generateGrid([x+0.5*sepx, y+0.5*sepy], [x+w, y+h], [sepx, sepy]))
            elif layout == "Square":
                points.append(self.generateGrid([x, y], [x+w, y+h], [sepx, sepx]))
        
        if len(points) == 0:
            return np.empty((0,2), dtype=float)
        
        # stack all point arrays together
        points = np.ascontiguousarray(np.vstack(points))
        # do some rounding to make it easier to detect duplicate points
        dec = int(-np.log10(sepx) + 4)
        points = np.round(points, dec)
        # keep only unique points
        points = np.unique(points.view(dtype=[('x', float), ('y', float)]))        
        # convert back to normal array
        points = points.view(dtype=float).reshape(len(points), 2)
        
        # get shape of total active region
        activeArea = Qt.QPainterPath()
        for rgn in self.rgns:
            if rgn.value():
                roi = rgn.item
                activeArea |= self.mapFromItem(roi, roi.shape())
            
        # filter for all points within active region
        mask = np.array([activeArea.contains(pg.Point(*pt)) for pt in points], dtype=bool)

        return points[mask]
Example #17
0
 def addItem(self, item, pos=(0,0), scale=(1,1), z=None):
     """Adds an item into the scene. The item is placed in the global coordinate system;
     it will stay fixed on the subject even if the scope moves or changes objective."""
     
     self.view.addItem(item)
     
     if pos is None:
         pos = self.view.viewRect().center()
     item.setPos(pg.Point(pos))
     item.scale(scale[0], scale[1])
     if z is not None:
         item.setZValue(z)
Example #18
0
    def analyzeTransform(self):
        """Return the position and yaw angle of the device transform
        """
        p = pg.debug.Profiler(disabled=True)
        dev = self.getDevice()
        p('getdev')
        pos = dev.mapToGlobal([0, 0, 0])
        p('map1')

        x = dev.mapToGlobal([1, 0, 0])
        p('map2')

        p1 = pg.Point(x[:2])
        p2 = pg.Point(pos[:2])
        p3 = pg.Point(1, 0)
        p('points')
        angle = (p1 - p2).angle(p3)
        if angle is None:
            angle = 0
        p('angle')
        return pos, angle
Example #19
0
    def paint(self, p, *args):
        pg.LineSegmentROI.paint(self, p, *args)
        h1 = self.handles[0]['item'].pos()
        h2 = self.handles[1]['item'].pos()
        p1 = p.transform().map(h1)
        p2 = p.transform().map(h2)

        vec = pg.Point(h2) - pg.Point(h1)
        length = vec.length()
        angle = vec.angle(pg.Point(1, 0))

        pvec = p2 - p1
        pvecT = pg.Point(pvec.y(), -pvec.x())
        pos = 0.5 * (p1 + p2) + pvecT * 40 / pvecT.length()

        p.resetTransform()

        txt = pg.siFormat(length, suffix='m') + '\n%0.1f deg' % angle
        p.drawText(QtCore.QRectF(pos.x() - 50,
                                 pos.y() - 50, 100, 100),
                   QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, txt)
Example #20
0
    def roiChanged(self):
        """ read the ROI rectangle width and height and repost
        in the parameter tree """
        if self.ignoreRoiChange:
            return

        self.scanVoltageCache = None  # invalidate cache

        # update scan position
        self.setScanPosFromRoi()

        # update scan shape if needed
        roi = self.currentRoi
        state = roi.getState()
        w, h = state['size']
        rparam = self.scanProgram.components[0].ctrlParameter()
        param = self.param.child('Scan Control')
        rows = int(param['Image Width'] * h / w)
        if param['Image Height'] != rows:
            # update image height; this will cause acq thread protocol to be updated
            with param.treeChangeBlocker():
                param['Image Height'] = rows
        else:
            # ..otherwise we need to request the update here.
            if self.imagingThread.isRunning():
                self.updateImagingProtocol()

        # record position of ROI in Scanner's local coordinate system
        # we can use this later to allow the ROI to track stage movement
        tr = self.scannerDev.inverseGlobalTransform() # maps from global to device local
        pt1 = pg.Point(*state['pos'])
        pt2 = pt1 + pg.Point(*state['size'])
        self.currentRoi.scannerCoords = [
            tr.map(pt1),
            tr.map(pt2),
            ]
Example #21
0
 def segmentClicked(self, segment, ev=None, pos=None): ## ev/pos should be in this item's coordinate system
     if ev != None:
         pos = ev.pos()
     elif pos != None:
         pos = pos
     else:
         raise Exception("Either an event or a position must be specified")
     
     ## figure out which segment to add corresponding handle to
     n = len(self.segments)
     ind = self.segments.index(segment)
     #mirrorInd = (n - ind) - 2 
     mirrorInd= n-ind 
     
     ## figure out position at which to add second handle:
     h1 = pg.Point(self.mapFromItem(segment, segment.handles[0]['item'].pos()))
     h2 = pg.Point(self.mapFromItem(segment, segment.handles[1]['item'].pos()))
     
     dist = (h1-pos).length()/(h1-h2).length()
     
     h3 = pg.Point(self.mapFromItem(self.segments[mirrorInd], self.segments[mirrorInd].handles[0]['item'].pos()))
     h4 = pg.Point(self.mapFromItem(self.segments[mirrorInd], self.segments[mirrorInd].handles[1]['item'].pos()))
     
     mirrorPos = h4 - (h4-h3)*dist
     
     ## add handles:
     if mirrorInd > ind:
         ROI.PolyLineROI.segmentClicked(self, self.segments[mirrorInd], pos=mirrorPos)
         ROI.PolyLineROI.segmentClicked(self, segment, pos=pos)
         
         ROI.LineSegmentROI([pos, mirrorPos], [0,0], handles=(self.segments[ind].handles[1]['item'], self.segments[mirrorInd+1].handles[1]['item']), pen=self.pen, movable=False, parent=self)
         
     else:
         ROI.PolyLineROI.segmentClicked(self, segment, pos=pos)
         ROI.PolyLineROI.segmentClicked(self, self.segments[mirrorInd], pos=mirrorPos)
         ROI.LineSegmentROI([mirrorPos, pos], [0,0], handles=(self.segments[mirrorInd].handles[1]['item'], self.segments[ind+1].handles[1]['item']), pen=self.pen, movable=False, parent=self)
Example #22
0
 def createROI(self, roiColor='r'):
     # the initial ROI will be nearly as big as the field, and centered.
     cpos = self.scannerDev.mapToGlobal((0,0)) # get center position in scanner coordinates
     csize = self.scannerDev.mapToGlobal((self.fieldSize, self.fieldSize))
     objScale = self.scannerDev.parentDevice().getObjective().scale().x()
     height = width = self.fieldSize*objScale
     
     csize = pg.Point(width, height)
     cpos = cpos - csize/2.
     
     roiColor = self.getObjectiveColor(self.scopeDev.currentObjective) # pick up an objective color...
     roi = RegionCtrl(cpos, csize, roiColor) # Note that the position actually gets over ridden by the camera additem below..
     self.cameraModule.window().addItem(roi)
     roi.setPos(cpos)
     roi.sigRegionChangeFinished.connect(self.roiChanged)
     return roi
Example #23
0
 def roiChanged(self):
     """ read the ROI rectangle width and height and repost
     in the parameter tree """
     state = self.roi.getState()
     w, h = state['size']
     # Remember: ROI origin is in bottom-left because camera module has +y pointing upward.
     self.params.system.p0 = pg.Point(self.roi.mapToView(pg.Point(
         0, h)))  # top-left
     self.params.system.p1 = pg.Point(self.roi.mapToView(pg.Point(
         w, h)))  # rop-right
     self.params.system.p2 = pg.Point(self.roi.mapToView(pg.Point(
         0, 0)))  # bottom-left
     self.params.updateSystem()
Example #24
0
    def writeArray(self, array, mapping=None):
        # Compute start/end indexes
        start, npts = self._arrayIndexes()

        # Generate spiral path
        sg = self.spiralGeometry()
        path = sg.path(npts, uniform=True)

        # Move to center position
        center = self.roi.mapToView(pg.Point(0, 0))
        path += np.array([center.x(), center.y()])

        # map to scanner voltage and write into array
        x, y = (path[:, 0], path[:, 1])
        if mapping is not None:
            x, y = mapping(x, y)
        array[start:start + npts, 0] = x
        array[start:start + npts, 1] = y

        return start, start + npts
Example #25
0
 def getMatrix(self, pos):
     """Return the transformMatrix to use for the given pos."""
     quads = self.state['quadrilaterals']
     ind=None
     for i, q in enumerate(quads):
         if QtGui.QPolygonF([QtCore.QPointF(*x) for x in q]).containsPoint(QtCore.QPointF(pos), QtCore.Qt.OddEvenFill):
             ind = i
     if ind == None: ## in case pos is outside the quadrilaterals
         bestMin = 1000
         for i, q in enumerate(quads):
             dist = [pg.Point(x-pos).length() for x in q]
             minDist = min(dist)
             dist.remove(minDist)
             minDist += min(dist)
             if minDist < bestMin:
                 bestMin = minDist
                 ind = i    
         
     m = self.state['transformMatrices'][ind]
     return np.array([m[0], m[1]])
Example #26
0
    def paint(self, p, *args):
        p.setRenderHint(p.Antialiasing)
        px = self.pixelLength(pg.Point(1, 0))
        py = self.pixelLength(pg.Point(0, 1))
        w = 5 * px
        h = 5 * py
        r = QtCore.QRectF(-w, -h, w * 2, h * 2)
        p.setPen(pg.mkPen('y'))
        p.setBrush(pg.mkBrush(0, 0, 255, 100))
        p.drawEllipse(r)
        p.drawLine(pg.Point(-w * 2, 0), pg.Point(w * 2, 0))
        p.drawLine(pg.Point(0, -h * 2), pg.Point(0, h * 2))

        if self.label is not None:
            angle = self.labelAngle * np.pi / 180.
            pos = p.transform().map(QtCore.QPointF(
                0, 0)) + 15 * QtCore.QPointF(np.cos(angle), -np.sin(angle))
            p.resetTransform()
            p.drawText(QtCore.QRectF(pos.x() - 10,
                                     pos.y() - 10, 20, 20),
                       QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter,
                       self.label)
Example #27
0
    def runCalibration(self):
        """The scanner calibration routine:
            1) Measure background frame, then scan mirrors 
               while collecting frames as fast as possible (self.scan())
            2) Locate spot in every frame using gaussian fit
            3) Map image spot locations to coordinate system of Scanner device's parent
            3) Do parabolic fit to determine mapping between voltage and position
        """
        camera = str(self.ui.cameraCombo.currentText())
        laser = str(self.ui.laserCombo.currentText())
        blurRadius = 5
        
        ## Do fast scan of entire allowed command range
        (background, cameraResult, positions) = self.scan()
        #self.calibrationResult = {'bg': background, 'frames': cameraResult, 'pos': positions}

        with pg.ProgressDialog("Calibrating scanner: Computing spot positions...", 0, 100) as dlg:
            dlg.show()
            dlg.raise_()  # Not sure why this is needed here..

            ## Forget first 2 frames since some cameras can't seem to get these right.
            frames = cameraResult.asArray()
            frames = frames[2:]
            positions = positions[2:]
            
            ## Do background subtraction
            ## take out half the data until it can do the calculation without having a MemoryError.
            finished = False
            gc.collect()
            while not finished:
                try:
                    frames = frames.astype(np.float32)
                    frames -= background.astype(np.float32)
                    finished=True
                except MemoryError:
                    frames = frames[::2,:,:]
                    positions = positions[::2]
                    finished = False
                
            ## Find a frame with a spot close to the center (within center 1/3)
            cx = frames.shape[1] / 3
            cy = frames.shape[2] / 3
            centerSlice = blur(frames[:, cx:cx*2, cy:cy*2], (0, 5, 5)).max(axis=1).max(axis=1)
            maxIndex = argmax(centerSlice)
            maxFrame = frames[maxIndex]
            dlg.setValue(5)

            ## Determine spot intensity and width
            mfBlur = blur(maxFrame, blurRadius)
            amp = mfBlur.max() - median(mfBlur)  ## guess intensity of spot
            (x, y) = argwhere(mfBlur == mfBlur.max())[0]   ## guess location of spot
            fit = fitGaussian2D(maxFrame, [amp, x, y, maxFrame.shape[0] / 10, 0.])[0]  ## gaussian fit to locate spot exactly
            # convert sigma to full width at 1/e
            fit[3] = abs(2 * (2 ** 0.5) * fit[3]) ## sometimes the fit for width comes out negative. *shrug*
            someFrame = cameraResult.frames()[0]
            frameTransform = pg.SRTTransform(someFrame.globalTransform())
            pixelSize = someFrame.info()['pixelSize'][0]
            spotAmplitude = fit[0]
            spotWidth = abs(fit[3] * pixelSize)
            size = self.spotSize(mfBlur)
            dlg.setValue(50)

            ## Determine location of spot within each frame, 
            ## ignoring frames where the spot is too dim or too close to the frame edge
            spotLocations = []
            globalSpotLocations = []
            spotCommands = []
            spotFrames = []
            margin = fit[3]
            
            for i in range(len(positions)):
                dlg.setValue(50. + 50. * i / frames.shape[0])
                if dlg.wasCanceled():
                    raise HelpfulException('Calibration canceled by user.', msgType='warning')

                frame = frames[i]
                fBlur = blur(frame.astype(np.float32), blurRadius)
    
                mx = fBlur.max()
                diff = mx - fBlur.min()
                ss = self.spotSize(fBlur)
                if ss < size * 0.6:
                    #print "Ignoring spot:", ss
                    continue
                #else:
                    #print "Keeping spot:", ss
                    
                (x, y) = argwhere(fBlur == mx)[0]   # guess location of spot
                if x < margin or x > frame.shape[0] - margin:
                    #print "   ..skipping; too close to edge", x, y
                    continue
                if y < margin or y > frame.shape[1] - margin:
                    #print "   ..skipping; too close to edge", x, y
                    continue
                
                frame[x,y] = -1  ## mark location of peak in image
                
                ## convert pixel location to coordinate system of scanner's parent
                globalPos = frameTransform.map(pg.Point(x, y))  ## Map from frame pixel location to global coordinates
                localPos = self.dev.mapGlobalToParent(globalPos)  ## map from global to parent coordinate system. This is the position we calibrate to.
                #print (x, y), (globalPos.x(), globalPos.y()), (localPos.x(), localPos.y())
                
                spotLocations.append([localPos.x(), localPos.y()])
                globalSpotLocations.append([globalPos.x(), globalPos.y()])
                spotCommands.append(positions[i])
                spotFrames.append(frame[newaxis])
        
        ## sanity check on spot frame
        if len(spotFrames) == 0:
            self.ui.view.setImage(frames)
            raise HelpfulException('Calibration never detected laser spot!  Looking for spots that are %f pixels wide.'% fit[3], reasons=['shutter is disabled', 'mirrors are disabled', 'objective is not clean', 'spot is not visible or not bright enough when shutter is open'])

        spotFrameMax = concatenate(spotFrames).max(axis=0)
        self.ui.view.setImage(spotFrameMax, transform=frameTransform)
        
        self.clearSpots()
        for sl in globalSpotLocations:
            #self.addSpot(sl, fit[3]*binning[0])
            self.addSpot(sl, spotWidth)
        self.ui.view.autoRange()
        
        if len(spotFrames) < 10:
            raise HelpfulException('Calibration detected only %d frames with laser spot; need minimum of 10.' % len(spotFrames), reasons=['spot is too dim for camera sensitivity', 'objective is not clean', 'mirrors are scanning too quickly', 'mirror scanning region is not within the camera\'s view'])
        
        ## Fit all data to a map function
        mapParams = self.generateMap(array(spotLocations), array(spotCommands))
        #print 
        #print "Map parameters:", mapParams
        
        if spotWidth < 0:
            raise Exception()
        return (mapParams, (spotAmplitude, spotWidth))
Example #28
0
    def getBackground(self):
        if self.background is None:
            w, h = self.params['sensorSize']
            tr = self.globalTransform()

            if isinstance(self.bgData, dict):
                # select data based on objective
                obj = self.getObjective()
                data = self.bgData[obj]
                info = self.bgInfo[obj]
                px = info['pixelSize']
                pz = info['depths'][1] - info['depths'][0]

                m = pg.QtGui.QMatrix4x4()
                pos = info['transform']['pos']
                m.scale(1 / px[0], 1 / px[1], 1 / pz)
                m.translate(-pos[0], -pos[1], -info['depths'][0])

                tr2 = m * tr
                origin = tr2.map(pg.Vector(0, 0, 0))
                #print(origin)
                origin = [int(origin.x()), int(origin.y()), origin.z()]

                ## slice data
                camRect = QtCore.QRect(origin[0], origin[1], w, h)
                dataRect = QtCore.QRect(0, 0, data.shape[1], data.shape[2])
                overlap = camRect.intersected(dataRect)
                tl = overlap.topLeft() - camRect.topLeft()

                z = origin[2]
                z1 = np.floor(z)
                z2 = np.ceil(z)
                s = (z - z1) / (z2 - z1)
                z1 = int(np.clip(z1, 0, data.shape[0] - 1))
                z2 = int(np.clip(z2, 0, data.shape[0] - 1))
                src1 = data[z1,
                            overlap.left():overlap.left() + overlap.width(),
                            overlap.top():overlap.top() + overlap.height()]
                src2 = data[z2,
                            overlap.left():overlap.left() + overlap.width(),
                            overlap.top():overlap.top() + overlap.height()]
                src = src1 * (1 - s) + src2 * s

                bg = np.empty((w, h), dtype=data.dtype)
                bg[:] = 100
                bg[tl.x():tl.x() + overlap.width(),
                   tl.y():tl.y() + overlap.height()] = src
                self.background = bg
                #vectors = ([1, 0, 0], [0, 1, 0])
                #self.background = pg.affineSlice(data, (w,h), origin, vectors, (1, 2, 0), order=1)
            else:
                tr = pg.SRTTransform(tr)
                m = QtGui.QTransform()

                m.scale(3e6, 3e6)
                m.translate(0.0005, 0.0005)
                tr = tr * m

                origin = tr.map(pg.Point(0, 0))
                x = (tr.map(pg.Point(1, 0)) - origin)
                y = (tr.map(pg.Point(0, 1)) - origin)
                origin = np.array([origin.x(), origin.y()])
                x = np.array([x.x(), x.y()])
                y = np.array([y.x(), y.y()])

                ## slice fractal from pre-rendered data
                vectors = (x, y)
                self.background = pg.affineSlice(self.bgData, (w, h),
                                                 origin,
                                                 vectors, (0, 1),
                                                 order=1)

        return self.background
Example #29
0
    def generateVoltageArray(self, arr):
        """
        Use a polyline to make a scan that covers multiple regions in an
        interleaved fashion. Alternate line segments of the polyline
        are either the "scan" or the "interscan", allowing rapid movement
        between successive points. 
        Interscan intervals are green on the line, scan intervals are white
        """
        pts = list(map(pg.Point, cmd['points']))
        startPos = pts[0]
        stopPos = pts[-1]

        #scanPoints = cmd['sweepDuration']/dt # in point indices, not time.
        #interTracePoints = cmd['intertraceDuration']/dt
        #scanPause = np.ones(int(interTracePoints))
        #cmd['samplesPerScan'] = scanPoints
        #cmd['samplesPerPause'] = interTracePoints
        sweepSpeed = 1000 * cmd['sweepSpeed']  # in m/msec
        interSweepSpeed = 1000 * cmd['interSweepSpeed']
        ScanFlag = False
        xp = np.array([])
        yp = np.array([])
        pockels = np.array([])
        nSegmentScans = 0
        nIntersegmentScans = 0
        scanPointList = []
        interScanFlag = False
        for k in range(len(pts)):  # loop through the list of points
            k2 = k + 1
            if k2 > len(pts) - 1:
                k2 = 0
            dist = (pg.Point(pts[k] - pts[k2])).length()
            if interScanFlag is False:
                scanPoints = int((dist / sweepSpeed) / dt)
                xPos = np.linspace(pts[k].x(), pts[k2].x(), scanPoints)
                yPos = np.linspace(pts[k].y(), pts[k2].y(), scanPoints)
                pockels = np.append(pockels, np.ones(scanPoints))
                nSegmentScans += 1
                scanPointList.append(scanPoints)
            else:
                interSweepPoints = int((dist / interSweepSpeed) / dt)
                xPos = np.linspace(pts[k].x(), pts[k2].x(), interSweepPoints)
                yPos = np.linspace(pts[k].y(), pts[k2].y(), interSweepPoints)
                pockels = np.append(pockels, np.zeros(interSweepPoints))
                nIntersegmentScans += 1
                scanPointList.append(interSweepPoints)
            x, y = dev.mapToScanner(xPos, yPos, cmd['laser'])
            xp = np.append(xp, x)
            yp = np.append(yp, y)
            interScanFlag = not interScanFlag

        cmd['nSegmentScans'] = nSegmentScans
        cmd['nIntersegmentScans'] = nIntersegmentScans
        cmd['scanPointList'] = scanPointList
        x = np.tile(xp, cmd['nScans'])
        y = np.tile(yp, cmd['nScans'])
        arr[0, startInd:startInd + len(x)] = x
        arr[1, startInd:startInd + len(y)] = y
        arr[0, startInd + len(x):stopInd] = arr[
            0, startInd + len(x) -
            1]  # fill in any unused sample on this scan section
        arr[1, startInd + len(y):stopInd] = arr[1, startInd + len(y) - 1]
        lastPos = (x[-1], y[-1])

        return stopInd
Example #30
0
def show(dh=None):
    """
    Display a graphic of the currently selected slice / cell
    """
    
    global v, g, atlas
    if dh is None:
        dh = man.currentFile
    v.clear()
    
    if 'cell' in dh.shortName().lower():
        cd = dh
        sd = cd.parent()
    else:
        sd = dh
        cd = None
    atlas.loadState(sd)
    g = atlas.schematicGraphicsItems()
    v.addItem(g)
    
    if cd is not None:
        ## small image to go over slice schematic
        imgf = cd['morphology.png']
        imgd = pg.colorToAlpha(imgf.read(), np.array([255,255,255]))
        mimg1 = pg.ImageItem(imgd)
        tr = pg.SRTTransform(imgf.info()['userTransform'])
        mimg1.setTransform(tr)
        mimg1.setParentItem(g.sliceGroup)
        g.cellImg1 = mimg1
        
        ## larger image to be displayed above
        cellGroup = pg.ItemGroup()
        g.cellGroup = cellGroup
        mimg2 = pg.ImageItem(imgd)
        mimg2.setParentItem(cellGroup)
        mimg2.setTransform(tr * g.sliceGroup.transform())
        mimg2.scale(1.0 / g.sliceScaleFactor, 1.0 / g.sliceScaleFactor)
        #angle = pg.SRTTransform(g.sliceGroup.transform()).getRotation()
        #mimg2.rotate(angle)
        cellScale = 50.
        cellGroup.scale(cellScale, cellScale)
        g.cellImg2 = mimg2
        
        ## reposition image above slice schematic
        b1 = g.atlasGroup.mapRectToParent(g.atlasGroup.childrenBoundingRect())
        b2 = g.sliceClip.mapRectToParent(g.sliceClip.boundingRect())
        bounds = b1 | b2
        cellGroup.setParentItem(g)
        imgBounds = g.mapRectFromItem(mimg2, mimg2.boundingRect())
        pos = pg.Point(bounds.center().x() - imgBounds.center().x(), bounds.top()-imgBounds.bottom()) 
        cellGroup.setPos(pos)
        
        ## add scale bar
        sbLength = 25e-6
        g.cellScale = Qt.QGraphicsLineItem(0.0, 0.0, sbLength, 0.0)
        g.cellScale.setPen(pg.mkPen(color=0.0, width=100e-6/cellScale, cosmetic=False))
        g.cellScale.setParentItem(cellGroup)
        g.cellScale.setZValue(10)
        g.cellScale.text = pg.TextItem(u"25 µm", anchor=(0.5, 1), color=(0,0,0))
        g.cellScale.text.setParentItem(g.cellScale)
        g.cellScale.text.setPos(sbLength*0.5, -50e-6/cellScale)
        corner = mimg2.mapToParent(mimg2.boundingRect()).boundingRect().bottomRight()
        g.cellScale.setPos(corner + pg.Point(-sbLength/2., -sbLength/3.))
        
        cell = dh
        sl = cell.parent()
        day = sl.parent()
        name = day.shortName() + "_" + sl.shortName() + "_" + cell.shortName()
        g.cellName = pg.TextItem(name, color=(0,0,0))
        g.cellName.setParentItem(cellGroup)
        g.cellName.setPos(corner + pg.Point(-sbLength*4,-sbLength/4.))