Ejemplo n.º 1
0
 def resetCams(self, curTime, cameras, table):
     resetEndTime = curTime
     for camera in cameras:
         exposureStart = max(curTime,
                             self.getTimeWhenCameraCanExpose(table, camera))
         # Cameras that have a pre-set exposure time can only use that
         # exposure time for clearing the sensor, hence why we take the
         # maximum of the min exposure time and the current exposure time.
         # \todo Is it possible for getExposureTime() to be less than
         # getMinExposureTime()? That would be a bug, right?
         minExposureTime = max(decimal.Decimal('.1'),
                               camera.getMinExposureTime(isExact=True),
                               camera.getExposureTime(isExact=True))
         exposureMode = camera.getExposureMode()
         if exposureMode == cockpit.handlers.camera.TRIGGER_AFTER:
             table.addToggle(exposureStart + minExposureTime, camera)
         elif exposureMode == cockpit.handlers.camera.TRIGGER_DURATION:
             table.addAction(exposureStart, camera, True)
             table.addAction(exposureStart + minExposureTime, camera, False)
         else:  # TRIGGER_BEFORE case
             table.addToggle(exposureStart, camera)
         resetEndTime = max(resetEndTime, exposureStart + minExposureTime)
         self.cameraToImageCount[camera] += 1
         self.cameraToIgnoredImageIndices[camera].add(
             self.cameraToImageCount[camera])
         self.cameraToIsReady[camera] = True
     return resetEndTime + decimal.Decimal('1e-6')
Ejemplo n.º 2
0
    def testGetMinExposureTime(self):
        callback = unittest.mock.Mock(return_value=50)
        self.args['callbacks'] = {'getMinExposureTime' : callback}
        camera = cockpit.handlers.camera.CameraHandler(**self.args)

        self.assertEqual(camera.getMinExposureTime(), 50)
        callback.assert_called_with('mock')
Ejemplo n.º 3
0
    def expose(self,
               curTime,
               cameras,
               lightTimePairs,
               table,
               pseudoGlobalExposure=False,
               previousMovementTime=0):
        # First, determine which cameras are not ready to be exposed, because
        # they may have seen light they weren't supposed to see (due to

        # bleedthrough from other cameras' exposures). These need
        # to be triggered (and we need to record that we want to throw away
        # those images) before we can proceed with the real exposure.
        camsToReset = set()
        for camera in cameras:
            if not self.cameraToIsReady[camera]:
                camsToReset.add(camera)
        if camsToReset:
            curTime = self.resetCams(curTime, camsToReset, table)
        # Figure out when we can start the exposure, based on the cameras
        # involved: their exposure modes, readout times, and last trigger
        # times determine how soon we can next trigger them (see
        # getTimeWhenCameraCanExpose() for more information).
        exposureStartTime = curTime
        # Adjust the exposure start based on when the cameras are ready.
        for camera in cameras:
            camExposureReadyTime = self.getTimeWhenCameraCanExpose(
                table, camera)
            # we add the readout time to get when the light should be trigger to
            # obtain pseudo global exposure
            camPseudoGlobalReadyTime = (camExposureReadyTime +
                                        self.cameraToReadoutTime[camera])
            exposureStartTime = max(exposureStartTime, camExposureReadyTime)

        # Determine the maximum exposure time, which depends on our light
        # sources as well as how long we have to wait for the cameras to be
        # ready to be triggered.
        maxExposureTime = 0
        if lightTimePairs:
            maxExposureTime = max(lightTimePairs, key=lambda a: a[1])[1]
        # Check cameras to see if they have minimum exposure times; take them
        # into account for when the exposure can end. Additionally, if they
        # are frame-transfer cameras, then we need to adjust maxExposureTime
        # to ensure that our triggering of the camera does not come too soon
        # (while it is still reading out the previous frame).

        for camera in cameras:
            maxExposureTime = max(maxExposureTime,
                                  camera.getMinExposureTime(isExact=True))
            if camera.getExposureMode(
            ) == cockpit.handlers.camera.TRIGGER_AFTER:
                nextReadyTime = self.getTimeWhenCameraCanExpose(table, camera)
                # Ensure camera is exposing for long enough to finish reading
                # out the last frame.
                maxExposureTime = max(maxExposureTime,
                                      nextReadyTime - exposureStartTime)

        # Open the shutters for the specified exposure times, centered within
        # the max exposure time.
        # Note that a None value here means the user wanted to expose the
        # cameras without any special light.
        exposureEndTime = exposureStartTime + maxExposureTime
        for light, exposureTime, in lightTimePairs:
            if light is not None and light.name is not 'ambient':  # i.e. not ambient light
                # Center the light exposure.
                timeSlop = maxExposureTime - exposureTime
                offset = timeSlop / 2
                table.addAction(exposureEndTime - exposureTime - offset, light,
                                True)
                table.addAction(exposureEndTime - offset, light, False)
            # Record this exposure time.
            if exposureTime not in self.lightToExposureTime[light]:
                self.lightToExposureTime[light].add(exposureTime)

        # Trigger the cameras. Keep track of which cameras we *aren't* using
        # here; if they are continuous-exposure cameras, then they may have
        # seen light that they shouldn't have, and need to be invalidated.

        usedCams = set()
        for camera in cameras:
            usedCams.add(camera)
            mode = camera.getExposureMode()
            if mode == cockpit.handlers.camera.TRIGGER_AFTER:
                table.addToggle(exposureEndTime, camera)
            elif mode == cockpit.handlers.camera.TRIGGER_DURATION:
                table.addAction(exposureStartTime, camera, True)
                table.addAction(exposureEndTime, camera, False)
            elif mode == cockpit.handlers.camera.TRIGGER_DURATION_PSEUDOGLOBAL:
                # We added some security time to the readout time that
                # we have to remove now
                cameraExposureStartTime = (exposureStartTime -
                                           self.cameraToReadoutTime[camera] -
                                           decimal.Decimal(0.005))
                table.addAction(cameraExposureStartTime, camera, True)
                table.addAction(exposureEndTime, camera, False)
            elif mode == cockpit.handlers.camera.TRIGGER_BEFORE:
                table.addToggle(exposureStartTime, camera)
            elif mode == cockpit.handlers.camera.TRIGGER_SOFT:
                table.addAction(exposureStartTime, camera, True)
            else:
                raise Exception('%s has no trigger mode set.' % camera)
            self.cameraToImageCount[camera] += 1
        for camera in self.cameras:
            if (camera not in usedCams and camera.getExposureMode()
                    == cockpit.handlers.camera.TRIGGER_AFTER):
                # Camera is a continuous-exposure/frame-transfer camera
                # and therefore saw light it shouldn't have; invalidate it.
                self.cameraToIsReady[camera] = False

        return exposureEndTime