class CameraPlot: def __init__(self): self.vimba = Vimba() self.vimba.startup() self.system = self.vimba.getSystem() self.cameraIds = self.vimba.getCameraIds() self.init_win() self.init_camera() def init_win(self): self.win = QtGui.QMainWindow() self.win.show() self.win.resize(600, 400) self.win.setWindowTitle("pymba + pyqtgraph") self.img = pg.ImageView() self.win.setCentralWidget(self.img) def init_camera(self): print("Vimba version:", self.vimba.getVersion()) print("Found {:d} cameras.".format(len(self.cameraIds))) self.cam = self.vimba.getCamera(self.cameraIds[0]) self.cam.openCamera() info = self.cam.getInfo() print("cameraName:", info.cameraName.decode("ascii")) print("interfaceIdString:", info.interfaceIdString.decode("ascii")) print("modelName:", info.modelName.decode("ascii")) def start_camera(self): self.cam.AcquisitionMode = "Continuous" self.cam.IIDCPhyspeed = "S800" self.cam.PixelFormat = "Mono16" self.cam.TriggerMode = "Off" self.cam.AcquisitionFrameRate = 20.0 self.frame = self.cam.getFrame() self.frame.announceFrame() self.cam.startCapture() self.cam.runFeatureCommand("AcquisitionStart") def process_images(self): QtCore.QTimer.singleShot(50, self.process_images) self.frame.queueFrameCapture() self.frame.waitFrameCapture() im = self.frame.getImage().T self.img.setImage(im, autoRange=False, autoLevels=False, autoHistogramRange=False) def stop_camera(self): self.cam.runFeatureCommand("AcquisitionStop") self.cam.endCapture() self.cam.revokeAllFrames() def deinit_camera(self): self.vimba.shutdown()
class VimbaCam(Driver): def initialize(self): self.vimba = Vimba() self.vimba.startup() self.cam = self.vimba.getCamera(self.vimba.getCameraIds()[0]) self.cam.openCamera() self.cam.PixelFormat = 'Mono8' self.frame = self.cam.getFrame() self.frame.announceFrame() self.cam.startCapture() return def finalize(self): self.vimba.shutdown() return @Action() def getFrame(self): try: self.frame.queueFrameCapture() success = True except: success = False self.cam.runFeatureCommand('AcquisitionStart') self.cam.runFeatureCommand('AcquisitionStop') self.frame.waitFrameCapture(0) frame_data = self.frame.getBufferByteData() if success: img_config = { 'buffer': frame_data, 'dtype': np.uint8, 'shape': (self.frame.height, self.frame.width, 1), } img = np.ndarray(**img_config) return img[...,0] else: return None
class AvtCamera(Camera): """Class for controlling an AVT camera. Uses the Vimba interface pymba (module documentation `here <https://github.com/morefigs/pymba>`_). Parameters ---------- Returns ------- """ def __init__(self, camera_id=None, **kwargs): # Set timeout for frame acquisition. Give this as input? self.timeout_ms = 1000 self.camera_id = camera_id super().__init__(**kwargs) try: self.vimba = Vimba() except NameError: raise Exception("The pymba package must be installed to use an AVT camera!") self.frame = None def open_camera(self): """ """ self.vimba.startup() messages = [] # Get available cameras: camera_ids = self.vimba.camera_ids() if self.camera_id is None: camera_index = 0 if len(camera_ids) > 0: messages.append( "I:Multiple cameras detected: {}. {} wiil be used.".format( camera_ids, self.camera_id ) ) else: try: camera_index = camera_ids.index(self.camera_id) except KeyError: raise KeyError( f"Camera id {self.camera_id} is not available (available cameras: {self.camera_ids})" ) messages.append("I:Detected camera {}.".format(camera_ids[camera_index])) self.cam = self.vimba.camera(camera_index) # Start camera: self.cam.open() self.frame = self.cam.new_frame() self.frame.announce() self.cam.start_capture() self.frame.queue_for_capture() self.cam.run_feature_command("AcquisitionStart") return messages def set(self, param, val): """ Parameters ---------- param : val : Returns ------- """ messages = [] try: if param == "exposure": # camera wants exposure in us: self.cam.ExposureTime = int(val * 1000) else: # To set new frame rate for AVT cameras acquisition has to be # interrupted: messages.append("E:" + param + " setting not supported on AVT cameras") except VimbaException: messages.append("E:Invalid value! {} will not be changed.".format(param)) return messages def read(self): """ """ try: self.frame.wait_for_capture(self.timeout_ms) self.frame.queue_for_capture() raw_data = self.frame.buffer_data() frame = np.ndarray( buffer=raw_data, dtype=np.uint8, shape=(self.frame.data.height, self.frame.data.width), ) except VimbaException: frame = None return frame def release(self): """ """ self.frame.wait_for_capture(self.timeout_ms) self.cam.run_feature_command("AcquisitionStop") self.cam.end_capture() self.cam.revoke_all_frames() self.vimba.shutdown()
class Vimba_Camera: def version(): with Vimba() as vimba: return vimba.getVersion() def enumerate_cameras(): # get connected camera ids # otherwise we haven't started yet. Open and close vimba library with Vimba() as vimba: return vimba.getCameraIds() def startup_vimba(self): log.info('Starting vimba.') self.vimba = Vimba() self.vimba.startup() def shutdown_vimba(self): self.vimba.shutdown() def __init__(self, name, vimba=None): # remember that Vimba as a singleton # you can use the camera as a context manager so as to not worry # about opening and closing the libary or the camera. # Otherwise remember to do it manually self.name = name if vimba is None: self.startup_vimba() else: self.vimba = vimba print(f"Received vimba {id(self.vimba)}") cams = self.vimba.getCameraIds() # check if the camera exists if self.name not in cams: raise NameError( f'Camera {name} not found in list of connected cameras.') self.camera = self.vimba.getCamera(self.name) self.camera.openCamera() log.info(f'Initialise camera {name}.') def close(self): # release both camera and vimba handles self.camera.closeCamera() log.info(f'Closing camera.') # self.vimba.shutdown() # log.info(f'Shutting down vimba.') def __enter__(self): log.info('__enter__') # __init__ starts vimba and opens the camera. Don't bother here. return self def __exit__(self, type, value, traceback): self.close() def list_features(self): features = self.camera.getFeatureNames() return [self.camera.getFeatureInfo(feature) for feature in features] def get_feature_range(self, feature): try: return self.camera.getFeatureRange(feature) except VimbaException: pass def get_camera_info(self): return self.camera.getInfo() def print_feature_description(self, feature): try: print(self.camera.getFeatureInfo(feature).description) except VimbaException: print('No description available.') def write_features_and_values_to_file(self): features = self.list_features() info = self.get_camera_info() filename = (info.cameraName.decode('utf8') + info.cameraIdString.decode('utf8') + '_attributes.txt') with open(filename, 'w') as f: for feature in features: name = feature.name.decode('utf-8') try: value = self.camera.__getattr__(name) except (VimbaException, TypeError): value = None # print(name, value) f.write(f"['{name}', ") f.write(f"'{value}'],\n") # delete that last comma f.seek(0, 2) size = f.tell() f.truncate(size - 3) def set_feature(self, name, value): setattr(self.camera, name, value) def set_features(self, _dict): # ideally this would be an ordered dict since some features can only be # set after others, e.g. cannot set Gain Value unless Gain is Manual. for k, v in _dict.items(): self.set_feature(k, v) def set_roi(self, roi): # set the rois with the correct order try: self.set_feature('Height', roi['Height']) self.set_feature('OffsetY', roi['OffsetY']) except VimbaException: self.set_feature('OffsetY', roi['OffsetY']) self.set_feature('Height', roi['Height']) try: self.set_feature('Width', roi['Width']) self.set_feature('OffsetX', roi['OffsetX']) except VimbaException: self.set_feature('OffsetX', roi['OffsetX']) self.set_feature('Width', roi['Width']) def snap(self, trigger=False): self.camera.TriggerMode = 'On' if trigger else 'Off' self.camera.AcquisitionMode = 'SingleFrame' # self.camera.AcquisitionMode = 'MultiFrame' # self.camera.AcquisitionFrameCount = 2 frame = self.camera.getFrame() frame.announceFrame() # capture a camera image self.camera.startCapture() frame.queueFrameCapture() self.camera.runFeatureCommand('AcquisitionStart') # this will never time out while frame.waitFrameCapture() != 0: print('.', end='') # frame.waitFrameCapture(timeout=-1) self.camera.runFeatureCommand('AcquisitionStop') # frame.waitFrameCapture() # clean up after capture self.camera.endCapture() self.camera.revokeAllFrames() data = self._decode_image_data(frame) return data def grab_multiple(self, N=3, trigger=True): self.camera.TriggerMode = 'On' if trigger else 'Off' self.camera.AcquisitionMode = 'MultiFrame' self.camera.AcquisitionFrameCount = N frames = [self.camera.getFrame() for _ in range(N)] for frame in frames: frame.announceFrame() # start capturing self.camera.startCapture() # queue the frames for frame in frames: frame.queueFrameCapture() self.camera.runFeatureCommand('AcquisitionStart') # this will never time out # having it the while loop here means that I can get SIGINT to exit while frames[-1].waitFrameCapture() != 0: print('.', end='') # frames[-1].waitFrameCapture(timeout=-1) self.camera.runFeatureCommand('AcquisitionStop') # frame.waitFrameCapture() # clean up after capture self.camera.endCapture() self.camera.revokeAllFrames() data = [self._decode_image_data(frame) for frame in frames] return np.array(data) def _decode_image_data(self, frame): bitdepths = { 'Mono16': np.uint16, 'Mono12Packed': np.uint16, 'Mono8': np.uint8 } bitdepth = bitdepths[self.camera.PixelFormat] data = np.ndarray(buffer=frame.getBufferByteData(), dtype=bitdepth, shape=(frame.height, frame.width)) return data.copy()
class Controller(ControllerTemplate): """ Camera controller for AVT cameras based on pymba """ def __init__(self): """ Camera controller for AVT camera devices. This implementation uses pymba as backend. """ super(Controller, self).__init__() self.logger = logging.getLogger(__name__) if LOGGING_LEVEL is not None: self.logger.setLevel(LOGGING_LEVEL) self.logger.debug('Starting AVT Camera Controller') self._vimba = Vimba() self._vimba.startup() self.__system = self._vimba.getSystem() self.__system.runFeatureCommand('GeVDiscoveryAllOnce') time.sleep(0.2) def updateDeviceHandles(self): """ Refresh the list of available devices """ self.logger.debug('Searching for AVT camera devices') self.device_handles = [] cams = self._vimba.getCameraIds() for cam_id in cams: tmp = self._vimba.getCamera(cam_id) self.device_handles.append('<AVT {model} (MAC: {mac})>' ''.format(model=tmp._info.modelName, mac=tmp._info.cameraIdString)) def getDevice(self, device_handle): """ Return the corresponding camera object for given device handle Parameters ---------- device_handle : can be IP address, mac address or camera ID (DEV_...) as reported by vimba.getCameraIds Returns ------- cam : Camera object A camera object for AVT devices corresponding to the given device handle """ # Check if device handle is list or tuple, if so: use first entry if isinstance(device_handle, (list, tuple)): device_handle = device_handle[0] self.logger.debug('Opening device {device_handle}' ''.format(device_handle=device_handle)) # Search for mac addresses in form 'DEV_XXXXXXXXXXXX' candidates = re.findall(r'(DEV_[0-9A-Z]{11,13})', device_handle) if len(candidates) == 0: # no mac address found: search for IP candidates = re.findall(r'[0-9]+(?:\.[0-9]+){3}', device_handle) try: return Camera(device_handle=candidates[0], vimba=self._vimba) except Exception as e: self.logger.exception('Failed to open the camera device: {e}' ''.format(e=e)) msg = '<Was not able to open camera with given device handle!!\n' \ 'Handle must be IP or MAC address (DEV_XXXXXXXXXXXXX)>' e.message = msg print(e.message) raise def closeController(self): self._vimba.shutdown() self.logger.info("Vimba Camera Controller shutdown") def __repr__(self): return "<AVT Camera Controller>"
class Camera(CameraTemplate): """ AVT Camera implementation based on pymba Creating this Object automatically opens the camera. It is NOT necessary to call openDevice() !!! This is done to set some settings to put the camera into freerun mode. """ def __init__(self, device_handle, vimba=None): """ Implementation of the AVT camera device Parameters ---------- device_handle : object Unique camera device handle to identify the camera """ if vimba is None: self._vimba = Vimba() self._vimba.startup() self.__system = self._vimba.getSystem() self.__system.runFeatureCommand('GeVDiscoveryAllOnce') time.sleep(0.2) else: self._vimba = vimba super(Camera, self).__init__(device_handle) self.logger = logging.getLogger(__name__) if LOGGING_LEVEL is not None: self.logger.setLevel(LOGGING_LEVEL) self.device = self._vimba.getCamera( self._checkDeviceHandle(device_handle)) self.device_handle = device_handle self.camId = None self.modelName = self.device._info.modelName self.triggerModeSetting = 'off' # Open device and activate freerun mode self.openDevice() # time.sleep(0.2) self.device.TriggerMode = 'Off' self.device.GevSCPSPacketSize = 1500 # Automatic setting not yet implemented in pymba (date: 11.12.17) # Influences framerate, necessary if network bandwidth is not big enough # NOTE: Functions self._setMaxTransferRate, self._setTransferRate and self._setNumberCams may change this value # self.device.StreamBytesPerSecond = 10000000 # 10 Mb/sec (without GigE) self.device.StreamBytesPerSecond = 115000000 # 100 Mb/sec (with GigE) self.maxTransferRate = 115000000 self.numCams = 1 self.isSet = {'rate': False, 'numCams': False} # Register AVT specific functions. # Function to set maximum transfer rate depending on used network specifications self.registerFeature('maxRate', self._setMaxTransferRate) self.registerFeature('bandwidth', self._setMaxTransferRate) self.registerFeature('maximumTransferRate', self._setMaxTransferRate) self.registerFeature('transferRate', self._setTransferRate) # Function to set number of cameras, may affect the available transfer rate per camera self.registerFeature('numCams', self._setNumberCams) self.registerFeature('numberCams', self._setNumberCams) self.registerFeature('numberOfCameras', self._setNumberCams) # Function to set pixel format self.registerFeature('pixelFormat', self.setFormat) self.registerFeature('pixelType', self.setFormat) self.registerFeature('format', self.setFormat) self.framelist = [] self.imgData = [] self._clearQueueAndFrames() # Init data type LUT for each PixelFormat self.imageFormatLUT = {'Mono8': np.uint8, 'Mono12': np.uint16} def __del__(self): # self._cleanUp() self._vimba.shutdown() def _checkDeviceHandle(self, device_handle): """ Return the corresponding camera object for given device handle Parameters ---------- device_handle : can be IP address, mac address or camera ID (DEV_...) as reported by vimba.getCameraIds Returns ------- cam : Camera object A camera object for AVT devices corresponding to the given device handle """ # Check if device handle is list or tuple, if so: use first entry if isinstance(device_handle, (list, tuple)): device_handle = device_handle[0] self.logger.debug('Opening device {device_handle}' ''.format(device_handle=device_handle)) # Search for mac addresses in form 'DEV_XXXXXXXXXXXX' candidates = re.findall(r'([0-9A-Z]{11,13})', device_handle) if len(candidates) == 0: # no mac address found: search for IP candidates = re.findall(r'[0-9]+(?:\.[0-9]+){3}', device_handle) return candidates[0] def _setMaxTransferRate(self, rate=None): """ Sets the transfer rate by changing 'StreamBytesPerSecond'. If passed None, will return actual rate set. Parameters ---------- rate: int Maximum bandwidth available. Typical values: - with GigE : 115000000 - without GigE : 10000000 Returns ------- self.max_bandwidth: int If passed None: returns set bandwidth """ self.logger.debug( "Setting max transfer rate for device {handle} to {rate}" "".format(handle=self.device_handle, rate=rate)) if rate is None: return self.maxTransferRate self.maxTransferRate = rate self.isSet['rate'] = True # Call function if number of cams was set if self.isSet['numCams']: self._setTransferRate() else: self.device.StreamBytesPerSecond = rate return self.maxTransferRate def _setNumberCams(self, num=None): """ Sets the number of AVT cameras used (this will affect the maximum transfer rate for each camera). If passed None, will return actual number of cameras set. Parameters ---------- num: int Number of AVT cameras Returns ------- self.numCams: int Number of AVT cameras set for this object """ self.logger.debug( "Setting number of cameras for device {handle} to {num}" "".format(handle=self.device_handle, num=num)) if num is None: return self.numCams self.numCams = num self.isSet['numCams'] = True if self.isSet['rate']: self._setTransferRate() return self.numCams def _setTransferRate(self): """ Takes maxTransferRate and numCams to compute a viable transfer rate for the device. """ transfer_rate = int(self.maxTransferRate / self.numCams) self.device.StreamBytesPerSecond = transfer_rate self.logger.debug("Setting transfer rate for {device} to {rate}" "".format(device=self.device_handle, rate=transfer_rate)) def _clearQueueAndFrames(self): """ Does some cleanup jobs. Call after whenever you feel like there might be a buffer overflow. Calls: - flushCaptureQueue() - revokeAllFrames() """ self.device.flushCaptureQueue() self.device.revokeAllFrames() def _cleanUp(self): """ Does some cleanup jobs. Call after "AcquisitionStop". Calls: - endCapture() - flushCaptureQueue() - revokeAllFrames() """ self.device.endCapture() self._clearQueueAndFrames() def _frameCallback(self, frame): """ Callback function to fill frames with data Parameters ------- frame : frame object frame created by device.getFrame() """ frame.waitFrameCapture(1000) # Get image data ... singleImg = np.ndarray( buffer=frame.getBufferByteData(), dtype=self.imageFormatLUT[self.device.PixelFormat], shape=(frame.height, frame.width)) self.imgData.append(singleImg) frame.queueFrameCapture(self._frameCallback) def _getCamId(self): """ Creates a cam-specific cam id, which consists of the manufacturer and a 4 digit number. This id makes it possible to identify the virtual object with real object. Returns ------- camId : "unique" cam id """ if self.camId is None: mfr = b'AVT' # mfr = manufacturer id = self.device._info.cameraIdString[-4:] camId = b'_'.join((mfr, id)).decode('utf-8') return camId else: return self.camId @staticmethod def listDevices(): """ List available AVT cameras Returns ------- cams : list list of available AVT devices """ return Controller().listDevices() def openDevice(self): """ Opens a camera device with the stored self.device object """ try: self.logger.debug('Opening camera device') self.device.openCamera() except Exception as e: self.logger.exception('Failed to open the camera device: ' '{e}'.format(e=e)) def closeDevice(self): """ Closes camera device """ try: self.logger.debug('Closing camera device') self.device.closeCamera() del self.device self.device = None except Exception as e: self.logger.exception('Failed to close the camera device: ' '{e}'.format(e=e)) def isOpen(self): """ Check if the device for this instance is currently open and ready to communicate Returns ------- bool True if the camera connection is open, False if it is not """ # AVT cameras do not have any isOpen-function by itself. # Assuming that if there is a device given in self.device, device is opened. if self.device is not None: return True else: return False def getImage(self, *args, **kwargs): """ Get an image from the camera device *args and **kwargs are ignored parameters! !!! Warning: Check transfer rate of your network connection !!! Low transfer-rates may cause incomplete image transfer with missing data Returns ------- img : np.ndarray Current camera image """ self.logger.debug('Creating frame and starting acquisition') # Create new frame for camera frame = self.device.getFrame() # Announce frame frame.announceFrame() # Capture a camera image self.device.startCapture() frame.queueFrameCapture() self.device.runFeatureCommand('AcquisitionStart') frame.waitFrameCapture(1000) self.device.runFeatureCommand('AcquisitionStop') # Get image data ... imgData = np.ndarray( buffer=frame.getBufferByteData(), dtype=self.imageFormatLUT[self.device.PixelFormat], shape=(frame.height, frame.width)) # Do cleanup self._cleanUp() self.logger.debug('Image acquisition finished') return imgData.copy() def prepareRecording(self, num): """ Sets the camera to MultiFrame mode and prepares frames. Use with "record()"-function. Parameters ---------- num : int number of frames to be captured during acquisition """ self._clearQueueAndFrames() self.device.AcquisitionMode = 'MultiFrame' self.device.AcquisitionFrameCount = num # Creating frames self.framelist = [] for _ in range(num): frame = self.device.getFrame() frame.announceFrame() frame.queueFrameCapture(self._frameCallback) self.framelist.append(frame) self.device.startCapture() def record(self): """ Blocking image acquisition, ends acquisition when num frames are captured, where num is set by "prepareRecording(num)". Only use with "prepareRecording(num)". Returns ------- imgData : list List of images """ self.imgData = [] self.device.runFeatureCommand('AcquisitionStart') # Block until num images are captured while len(self.imgData) != len(self.framelist): pass self.device.runFeatureCommand('AcquisitionStop') # Do cleanup self._cleanUp() # Set back to freerun mode self.device.AcquisitionMode = 'Continuous' return copy.deepcopy(self.imgData) # TODO: If grabStart without "num" is needed - implement threading solution with while loop (similar to _liveView()) def grabStart(self, num): """ Prepares num images to be grabbed. This function is not blocking. Calling "grabStop()" will end acquisition. Parameters ---------- num : int Number of images that should be recorded """ self.device.AcquisitionMode = 'MultiFrame' self.device.AcquisitionFrameCount = num # Creating frames self.framelist = [] for _ in range(num): frame = self.device.getFrame() frame.announceFrame() frame.queueFrameCapture(self._frameCallback) self.framelist.append(frame) self.device.startCapture() self.device.runFeatureCommand('AcquisitionStart') def grabStop(self): """ Stop grabbing images and return camera to continuous mode. """ self.device.runFeatureCommand('AcquisitionStop') # Do cleanup self._cleanUp() # Set back to freerun mode self.device.AcquisitionMode = 'Continuous' return copy.deepcopy(self.imgData) def _liveView(self): """ Live image stream an visualization through OpenCV window Leave _liveView by pressing "q" """ cv.startWindowThread() cv.namedWindow("IMG", 2) cv.resizeWindow("IMG", 900, 900) frame = self.device.getFrame() frame.announceFrame() self.device.startCapture() framecount = 0 droppedframes = [] while True: try: frame.queueFrameCapture() success = True except Exception: droppedframes.append(framecount) success = False self.device.runFeatureCommand("AcquisitionStart") self.device.runFeatureCommand("AcquisitionStop") frame.waitFrameCapture(1000) frame_data = frame.getBufferByteData() if success: live_img = np.ndarray( buffer=frame_data, dtype=self.imageFormatLUT[self.device.PixelFormat], shape=(frame.height, frame.width)) cv.imshow("IMG", live_img) framecount += 1 key = cv.waitKey(1) & 0xFF if key == ord("q"): cv.destroyAllWindows() self.logger.info("Frames displayed: %i" % framecount) self.logger.info("Frames dropped: %s" % droppedframes) break # Cleanup self._cleanUp() def listFeatures(self): """ Lists camera features """ try: self.logger.debug('Listing camera features') featureNames = self.device.getFeatureNames() print("Printing feature names: ...\n") print("\n".join(featureNames)) except Exception as e: self.logger.exception('Failed to get feature names: ' '{e}'.format(e=e)) def setExposureMicrons(self, microns=None): """ Set the exposure time to the given value in microseconds or read the current value by passing None Parameters ---------- microns : int Desired exposure time in microseconds that should be set, or None to read the current exposure time Returns ------- microns : int The exposure time in microseconds after applying the passed value """ if microns is not None: self.logger.debug('Setting <ExposureTime> to {microns}' ''.format(microns=microns)) self.device.ExposureTimeAbs = microns return self.device.ExposureTimeAbs def autoExposure(self): """ Automatically sets the exposure time of the camera ONCE. Old exposure setting is lost during the process! Returns ------- exposure : int The exposure time in microseconds after auto exposure """ self.logger.debug("Starting automatic exposure control") self.device.ExposureAuto = "Once" # Save trigger settings and activate acquisition until # auto exposure has settled triggerMode_buffer = self.triggerMode frame = self.device.getFrame() frame.announceFrame() self.device.startCapture() self.triggerMode = "off" max_iter = 100 iter = 0 # Auto exposure gets stuck if the border values are reached, # but further adjustments are necessary limits = (self.device.ExposureAutoMin, self.device.ExposureAutoMax) limit_cnt = 0 last_exposure = -1 self.device.runFeatureCommand("AcquisitionStart") while self.device.ExposureAuto != "Off": if last_exposure in limits: limit_cnt += 1 else: limit_cnt = 0 try: frame.queueFrameCapture() except Exception: pass frame.waitFrameCapture(1000) iter += 1 last_exposure = self.device.ExposureTimeAbs if limit_cnt > 5: self.logger.info( "Auto exposure has run into limits. Continuing with exposure of: {exposure} " .format(exposure=last_exposure)) self.device.ExposureAuto = "Off" if iter >= max_iter: try: raise TimeoutError("Timeout while setting auto exposure!") except NameError: # Python 2 compatible Error raise Exception("Timeout while setting auto exposure!") # Cleanup self.device.runFeatureCommand("AcquisitionStop") self._cleanUp() self.triggerMode = triggerMode_buffer self.logger.debug("Set exposure time to {exposure}" "".format(exposure=self.device.ExposureTimeAbs)) return self.device.ExposureTimeAbs def setResolution(self, resolution=None): """ Set the resolution of the camera to the given values in pixels or read the current resolution by passing None Parameters ---------- resolution : tuple Desired camera resolution in the form (width, height), or None to read the current resolution Returns ------- resolution : tuple The set camera resolution after applying the passed value """ if resolution is not None: self.logger.debug('Setting <Width> to {width}' ''.format(width=resolution[0])) self.device.Width = resolution[0] self.logger.debug('Setting <Height> to {height}' ''.format(height=resolution[1])) self.device.Height = resolution[1] return self.device.Width, self.device.Height def setGain(self, gain=None): """ Set the gain of the camera to the given value or read the current value by passing None Parameters ---------- gain : float Desired gain value in dB to be set, or None to read the current gain value Returns ------- gain : int The gain value after applying the passed value """ if gain is not None: self.logger.debug('Setting <Gain> to {gain}' ''.format(gain=gain)) self.device.Gain = gain return self.device.Gain def setFormat(self, fmt=None): """ Set the image format to the passed setting or read the current format by passing None Parameters ---------- fmt : str String describing the desired image format (e.g. "mono8"), or None to read the current image format. Check camera technical manual for available formats, may differ from model to model. Returns ------- fmt : str The image format after applying the passed value """ if fmt is not None: self.logger.debug('Setting <PixelFormat> to {fmt}' ''.format(fmt=fmt)) self.device.PixelFormat = fmt return self.device.PixelFormat def setTriggerMode(self, mode=None): """ Set the trigger mode of the camera to either "in", "out" or "off", or read the current trigger setting ba passing None Parameters ---------- mode : str The desired trigger mode. "in" means the camera receives a trigger signal, "out" means the camera sends a trigger signal, "off"" means the camera does not react to triggers. To read the current trigger setting pass None Returns ------- mode : str The trigger mode after applying the passed value """ self.logger.debug("Setting trigger mode to: {mode}".format(mode=mode)) if mode is None: return self.triggerModeSetting elif isinstance(mode, str): if mode.lower() == 'in': self.device.TriggerMode = 'On' self.device.TriggerSource = 'Line1' self.device.TriggerSelector = 'FrameStart' self.device.TriggerActivation = "RisingEdge" self.triggerModeSetting = 'in' elif mode.lower() == 'out': # TODO: Implement out trigger for AVT cameras self.triggerModeSetting = 'out' raise NotImplementedError('Sending triggers is not' 'implemented yet!') elif mode.lower() == 'off': self.device.TriggerMode = 'Off' self.device.TriggerSource = 'Freerun' self.device.TriggerSelector = 'FrameStart' self.triggerModeSetting = 'off' else: raise ValueError('Unexpected value in setTriggerMode. ' 'Expected "in", "out", or "off". Got {mode}' ''.format(mode=mode)) return self.triggerModeSetting else: raise TypeError('Trigger Mode should be None, "in", "out", or ' '"off". Got {mode}'.format(mode=mode)) def __repr__(self): return repr(self.device)
class VimbaCamera(FrameSource): """ **SUMMARY** VimbaCamera is a wrapper for the Allied Vision cameras, such as the "manta" series. This requires the 1) Vimba SDK provided from Allied Vision http://www.alliedvisiontec.com/us/products/software/vimba-sdk.html 2) Pyvimba Python library TODO: <INSERT URL> Note that as of time of writing, the VIMBA driver is not available for Mac. All camera properties are directly from the Vimba SDK manual -- if not specified it will default to whatever the camera state is. Cameras can either by **EXAMPLE** >>> cam = VimbaCamera(0, {"width": 656, "height": 492}) >>> >>> img = cam.getImage() >>> img.show() """ def _setupVimba(self): from pymba import Vimba self._vimba = Vimba() self._vimba.startup() system = self._vimba.getSystem() if system.GeVTLIsPresent: system.runFeatureCommand("GeVDiscoveryAllOnce") time.sleep(0.2) def __del__(self): #This function should disconnect from the Vimba Camera if self._camera is not None: if self.threaded: self._thread.stop() time.sleep(0.2) if self._frame is not None: self._frame.revokeFrame() self._frame = None self._camera.closeCamera() self._vimba.shutdown() def shutdown(self): """You must call this function if you are using threaded=true when you are finished to prevent segmentation fault""" # REQUIRED TO PREVENT SEGMENTATION FAULT FOR THREADED=True if (self._camera): self._camera.closeCamera() self._vimba.shutdown() def __init__(self, camera_id = -1, properties = {}, threaded = False): if not VIMBA_ENABLED: raise Exception("You don't seem to have the pymba library installed. This will make it hard to use a AVT Vimba Camera.") self._vimba = None self._setupVimba() camlist = self.listAllCameras() self._camTable = {} self._frame = None self._buffer = None # Buffer to store images self._buffersize = 10 # Number of images to keep in the rolling image buffer for threads self._lastimage = None # Last image loaded into memory self._thread = None self._framerate = 0 self.threaded = False self._properties = {} self._camera = None i = 0 for cam in camlist: self._camTable[i] = {'id': cam.cameraIdString} i += 1 if not len(camlist): raise Exception("Couldn't find any cameras with the Vimba driver. Use VimbaViewer to confirm you have one connected.") if camera_id < 9000: #camera was passed as an index reference if camera_id == -1: #accept -1 for "first camera" camera_id = 0 if (camera_id > len(camlist)): raise Exception("Couldn't find camera at index %d." % camera_id) cam_guid = camlist[camera_id].cameraIdString else: raise Exception("Index %d is too large" % camera_id) self._camera = self._vimba.getCamera(cam_guid) self._camera.openCamera() self.uniqueid = cam_guid self.setProperty("AcquisitionMode","SingleFrame") self.setProperty("TriggerSource","Freerun") # TODO: FIX if properties.get("mode", "RGB") == 'gray': self.setProperty("PixelFormat", "Mono8") else: fmt = "RGB8Packed" # alternatively use BayerRG8 self.setProperty("PixelFormat", "BayerRG8") #give some compatablity with other cameras if properties.get("mode", ""): properties.pop("mode") if properties.get("height", ""): properties["Height"] = properties["height"] properties.pop("height") if properties.get("width", ""): properties["Width"] = properties["width"] properties.pop("width") for p in properties: self.setProperty(p, properties[p]) if threaded: self._thread = VimbaCameraThread(self) self._thread.daemon = True self._buffer = deque(maxlen=self._buffersize) self._thread.start() self.threaded = True self._refreshFrameStats() def restart(self): """ This tries to restart the camera thread """ self._thread.stop() self._thread = VimbaCameraThread(self) self._thread.daemon = True self._buffer = deque(maxlen=self._buffersize) self._thread.start() def listAllCameras(self): """ **SUMMARY** List all cameras attached to the host **RETURNS** List of VimbaCamera objects, otherwise empty list VimbaCamera objects are defined in the pymba module """ cameraIds = self._vimba.getCameraIds() ar = [] for cameraId in cameraIds: ar.append(self._vimba.getCamera(cameraId)) return ar def runCommand(self,command): """ **SUMMARY** Runs a Vimba Command on the camera Valid Commands include: * AcquisitionAbort * AcquisitionStart * AcquisitionStop **RETURNS** 0 on success **EXAMPLE** >>>c = VimbaCamera() >>>c.runCommand("TimeStampReset") """ return self._camera.runFeatureCommand(command) def getProperty(self, name): """ **SUMMARY** This retrieves the value of the Vimba Camera attribute There are around 140 properties for the Vimba Camera, so reference the Vimba Camera pdf that is provided with the SDK for detailed information Throws VimbaException if property is not found or not implemented yet. **EXAMPLE** >>>c = VimbaCamera() >>>print c.getProperty("ExposureMode") """ return self._camera.__getattr__(name) #TODO, implement the PvAttrRange* functions #def getPropertyRange(self, name) def getAllProperties(self): """ **SUMMARY** This returns a dict with the name and current value of the documented Vimba attributes CAVEAT: it addresses each of the properties individually, so this may take time to run if there's network latency **EXAMPLE** >>>c = VimbaCamera(0) >>>props = c.getAllProperties() >>>print props['ExposureMode'] """ from pymba import VimbaException # TODO ar = {} c = self._camera cameraFeatureNames = c.getFeatureNames() for name in cameraFeatureNames: try: ar[name] = c.__getattr__(name) except VimbaException: # Ignore features not yet implemented pass return ar def setProperty(self, name, value, skip_buffer_size_check=False): """ **SUMMARY** This sets the value of the Vimba Camera attribute. There are around 140 properties for the Vimba Camera, so reference the Vimba Camera pdf that is provided with the SDK for detailed information Throws VimbaException if property not found or not yet implemented **Example** >>>c = VimbaCamera() >>>c.setProperty("ExposureAutoRate", 200) >>>c.getImage().show() """ ret = self._camera.__setattr__(name, value) #just to be safe, re-cache the camera metadata if not skip_buffer_size_check: self._refreshFrameStats() return ret def getImage(self): """ **SUMMARY** Extract an Image from the Camera, returning the value. No matter what the image characteristics on the camera, the Image returned will be RGB 8 bit depth, if camera is in greyscale mode it will be 3 identical channels. **EXAMPLE** >>>c = VimbaCamera() >>>c.getImage().show() """ if self.threaded: self._thread.lock.acquire() try: img = self._buffer.pop() self._lastimage = img except IndexError: img = self._lastimage self._thread.lock.release() else: img = self._captureFrame() return img def setupASyncMode(self): self.setProperty('AcquisitionMode','SingleFrame') self.setProperty('TriggerSource','Software') def setupSyncMode(self): self.setProperty('AcquisitionMode','SingleFrame') self.setProperty('TriggerSource','Freerun') def _refreshFrameStats(self): self.width = self.getProperty("Width") self.height = self.getProperty("Height") self.pixelformat = self.getProperty("PixelFormat") self.imgformat = 'RGB' if self.pixelformat == 'Mono8': self.imgformat = 'L' def _getFrame(self): if not self._frame: self._frame = self._camera.getFrame() # creates a frame self._frame.announceFrame() return self._frame def _captureFrame(self, timeout = 5000): try: c = self._camera f = self._getFrame() colorSpace = Factory.Image.BGR if self.pixelformat == 'Mono8': colorSpace = Factory.Image.GRAY c.startCapture() f.queueFrameCapture() c.runFeatureCommand('AcquisitionStart') c.runFeatureCommand('AcquisitionStop') try: f.waitFrameCapture(timeout) except Exception, e: print "Exception waiting for frame: %s: %s" % (e, traceback.format_exc()) raise(e) imgData = f.getBufferByteData() moreUsefulImgData = np.ndarray(buffer = imgData, dtype = np.uint8, shape = (f.height, f.width, 1)) rgb = cv2.cvtColor(moreUsefulImgData, cv2.COLOR_BAYER_RG2RGB) c.endCapture() return Factory.Image(rgb, colorSpace=colorSpace) except Exception, e: print "Exception acquiring frame: %s: %s" % (e, traceback.format_exc()) raise(e)
class AvtCamera(Camera): """Class for controlling an AVT camera. Uses the Vimba interface pymba (module documentation `here <https://github.com/morefigs/pymba>`_). Parameters ---------- Returns ------- """ def __init__(self, **kwargs): # Set timeout for frame acquisition. Give this as input? self.timeout_ms = 1000 super().__init__(**kwargs) try: self.vimba = Vimba() except NameError: raise Exception( "The pymba package must be installed to use an AVT camera!") self.frame = None def open_camera(self): """ """ self.vimba.startup() messages = [] # If there are multiple cameras, only the first one is used (this may # change): camera_ids = self.vimba.getCameraIds() if len(camera_ids) > 1: messages.append( "I:Multiple cameras detected: {}. {} wiil be used.".format( camera_ids, camera_ids[0])) else: messages.append("I:Detected camera {}.".format(camera_ids[0])) self.cam = self.vimba.getCamera(camera_ids[0]) # Start camera: self.cam.openCamera() self.frame = self.cam.getFrame() self.frame.announceFrame() self.cam.startCapture() self.frame.queueFrameCapture() self.cam.runFeatureCommand("AcquisitionStart") return messages def set(self, param, val): """ Parameters ---------- param : val : Returns ------- """ messages = [] try: if param == "exposure": # camera wants exposure in us: self.cam.ExposureTime = int(val * 1000) else: # To set new frame rate for AVT cameras acquisition has to be # interrupted: messages.append("E:" + param + " setting not supported on AVT cameras") except VimbaException: messages.append( "E:Invalid value! {} will not be changed.".format(param)) return messages def read(self): """ """ try: self.frame.waitFrameCapture(self.timeout_ms) self.frame.queueFrameCapture() raw_data = self.frame.getBufferByteData() frame = np.ndarray( buffer=raw_data, dtype=np.uint8, shape=(self.frame.height, self.frame.width), ) except VimbaException: frame = None return frame def release(self): """ """ self.frame.waitFrameCapture(self.timeout_ms) self.cam.runFeatureCommand("AcquisitionStop") self.cam.endCapture() self.cam.revokeAllFrames() self.vimba.shutdown()
class VimbaCamera(FrameSource): """ **SUMMARY** VimbaCamera is a wrapper for the Allied Vision cameras, such as the "manta" series. This requires the 1) Vimba SDK provided from Allied Vision http://www.alliedvisiontec.com/us/products/software/vimba-sdk.html 2) Pyvimba Python library TODO: <INSERT URL> Note that as of time of writing, the VIMBA driver is not available for Mac. All camera properties are directly from the Vimba SDK manual -- if not specified it will default to whatever the camera state is. Cameras can either by **EXAMPLE** >>> cam = VimbaCamera(0, {"width": 656, "height": 492}) >>> >>> img = cam.getImage() >>> img.show() """ def _setupVimba(self): from pymba import Vimba self._vimba = Vimba() self._vimba.startup() system = self._vimba.getSystem() if system.GeVTLIsPresent: system.runFeatureCommand("GeVDiscoveryAllOnce") time.sleep(0.2) def __del__(self): #This function should disconnect from the Vimba Camera if self._camera is not None: if self.threaded: self._thread.stop() time.sleep(0.2) if self._frame is not None: self._frame.revokeFrame() self._frame = None self._camera.closeCamera() self._vimba.shutdown() def shutdown(self): """You must call this function if you are using threaded=true when you are finished to prevent segmentation fault""" # REQUIRED TO PREVENT SEGMENTATION FAULT FOR THREADED=True if (self._camera): self._camera.closeCamera() self._vimba.shutdown() def __init__(self, camera_id=-1, properties={}, threaded=False): if not VIMBA_ENABLED: raise Exception( "You don't seem to have the pymba library installed. This will make it hard to use a AVT Vimba Camera." ) self._vimba = None self._setupVimba() camlist = self.listAllCameras() self._camTable = {} self._frame = None self._buffer = None # Buffer to store images self._buffersize = 10 # Number of images to keep in the rolling image buffer for threads self._lastimage = None # Last image loaded into memory self._thread = None self._framerate = 0 self.threaded = False self._properties = {} self._camera = None i = 0 for cam in camlist: self._camTable[i] = {'id': cam.cameraIdString} i += 1 if not len(camlist): raise Exception( "Couldn't find any cameras with the Vimba driver. Use VimbaViewer to confirm you have one connected." ) if camera_id < 9000: #camera was passed as an index reference if camera_id == -1: #accept -1 for "first camera" camera_id = 0 if (camera_id > len(camlist)): raise Exception("Couldn't find camera at index %d." % camera_id) cam_guid = camlist[camera_id].cameraIdString else: raise Exception("Index %d is too large" % camera_id) self._camera = self._vimba.getCamera(cam_guid) self._camera.openCamera() self.uniqueid = cam_guid self.setProperty("AcquisitionMode", "SingleFrame") self.setProperty("TriggerSource", "Freerun") # TODO: FIX if properties.get("mode", "RGB") == 'gray': self.setProperty("PixelFormat", "Mono8") else: fmt = "RGB8Packed" # alternatively use BayerRG8 self.setProperty("PixelFormat", "BayerRG8") #give some compatablity with other cameras if properties.get("mode", ""): properties.pop("mode") if properties.get("height", ""): properties["Height"] = properties["height"] properties.pop("height") if properties.get("width", ""): properties["Width"] = properties["width"] properties.pop("width") for p in properties: self.setProperty(p, properties[p]) if threaded: self._thread = VimbaCameraThread(self) self._thread.daemon = True self._buffer = deque(maxlen=self._buffersize) self._thread.start() self.threaded = True self._refreshFrameStats() def restart(self): """ This tries to restart the camera thread """ self._thread.stop() self._thread = VimbaCameraThread(self) self._thread.daemon = True self._buffer = deque(maxlen=self._buffersize) self._thread.start() def listAllCameras(self): """ **SUMMARY** List all cameras attached to the host **RETURNS** List of VimbaCamera objects, otherwise empty list VimbaCamera objects are defined in the pymba module """ cameraIds = self._vimba.getCameraIds() ar = [] for cameraId in cameraIds: ar.append(self._vimba.getCamera(cameraId)) return ar def runCommand(self, command): """ **SUMMARY** Runs a Vimba Command on the camera Valid Commands include: * AcquisitionAbort * AcquisitionStart * AcquisitionStop **RETURNS** 0 on success **EXAMPLE** >>>c = VimbaCamera() >>>c.runCommand("TimeStampReset") """ return self._camera.runFeatureCommand(command) def getProperty(self, name): """ **SUMMARY** This retrieves the value of the Vimba Camera attribute There are around 140 properties for the Vimba Camera, so reference the Vimba Camera pdf that is provided with the SDK for detailed information Throws VimbaException if property is not found or not implemented yet. **EXAMPLE** >>>c = VimbaCamera() >>>print c.getProperty("ExposureMode") """ return self._camera.__getattr__(name) #TODO, implement the PvAttrRange* functions #def getPropertyRange(self, name) def getAllProperties(self): """ **SUMMARY** This returns a dict with the name and current value of the documented Vimba attributes CAVEAT: it addresses each of the properties individually, so this may take time to run if there's network latency **EXAMPLE** >>>c = VimbaCamera(0) >>>props = c.getAllProperties() >>>print props['ExposureMode'] """ from pymba import VimbaException # TODO ar = {} c = self._camera cameraFeatureNames = c.getFeatureNames() for name in cameraFeatureNames: try: ar[name] = c.__getattr__(name) except VimbaException: # Ignore features not yet implemented pass return ar def setProperty(self, name, value, skip_buffer_size_check=False): """ **SUMMARY** This sets the value of the Vimba Camera attribute. There are around 140 properties for the Vimba Camera, so reference the Vimba Camera pdf that is provided with the SDK for detailed information Throws VimbaException if property not found or not yet implemented **Example** >>>c = VimbaCamera() >>>c.setProperty("ExposureAutoRate", 200) >>>c.getImage().show() """ ret = self._camera.__setattr__(name, value) #just to be safe, re-cache the camera metadata if not skip_buffer_size_check: self._refreshFrameStats() return ret def getImage(self): """ **SUMMARY** Extract an Image from the Camera, returning the value. No matter what the image characteristics on the camera, the Image returned will be RGB 8 bit depth, if camera is in greyscale mode it will be 3 identical channels. **EXAMPLE** >>>c = VimbaCamera() >>>c.getImage().show() """ if self.threaded: self._thread.lock.acquire() try: img = self._buffer.pop() self._lastimage = img except IndexError: img = self._lastimage self._thread.lock.release() else: img = self._captureFrame() return img def setupASyncMode(self): self.setProperty('AcquisitionMode', 'SingleFrame') self.setProperty('TriggerSource', 'Software') def setupSyncMode(self): self.setProperty('AcquisitionMode', 'SingleFrame') self.setProperty('TriggerSource', 'Freerun') def _refreshFrameStats(self): self.width = self.getProperty("Width") self.height = self.getProperty("Height") self.pixelformat = self.getProperty("PixelFormat") self.imgformat = 'RGB' if self.pixelformat == 'Mono8': self.imgformat = 'L' def _getFrame(self): if not self._frame: self._frame = self._camera.getFrame() # creates a frame self._frame.announceFrame() return self._frame def _captureFrame(self, timeout=5000): try: c = self._camera f = self._getFrame() colorSpace = Factory.Image.BGR if self.pixelformat == 'Mono8': colorSpace = Factory.Image.GRAY c.startCapture() f.queueFrameCapture() c.runFeatureCommand('AcquisitionStart') c.runFeatureCommand('AcquisitionStop') try: f.waitFrameCapture(timeout) except Exception, e: print "Exception waiting for frame: %s: %s" % ( e, traceback.format_exc()) raise (e) imgData = f.getBufferByteData() moreUsefulImgData = np.ndarray(buffer=imgData, dtype=np.uint8, shape=(f.height, f.width, 1)) rgb = cv2.cvtColor(moreUsefulImgData, cv2.COLOR_BAYER_RG2RGB) c.endCapture() return Factory.Image(rgb, colorSpace=colorSpace) except Exception, e: print "Exception acquiring frame: %s: %s" % ( e, traceback.format_exc()) raise (e)
class AvtCamera(Camera): """Class for controlling an AVT camera. Uses the Vimba interface pymba (module documentation `here <https://github.com/morefigs/pymba>`_). Parameters ---------- Returns ------- """ def __init__(self, downsampling=None, **kwargs): # Set timeout for frame acquisition. Give this as input? self.timeout_ms = 1000 super().__init__(**kwargs) try: self.vimba = Vimba() except NameError: print("The pymba package must be installed to use an AVT camera!") self.frame = None def open_camera(self): """ """ self.vimba.startup() # If there are multiple cameras, only the first one is used (this may # change): camera_ids = self.vimba.getCameraIds() if self.debug: if len(camera_ids) > 1: print("Multiple cameras detected: {}. {} wiil be used.".format( camera_ids, camera_ids[0])) else: print("Detected camera {}.".format(camera_ids[0])) self.cam = self.vimba.getCamera(camera_ids[0]) # Start camera: self.cam.openCamera() self.frame = self.cam.getFrame() self.frame.announceFrame() self.cam.startCapture() self.frame.queueFrameCapture() self.cam.runFeatureCommand("AcquisitionStart") def set(self, param, val): """ Parameters ---------- param : val : Returns ------- """ try: if param == "exposure": # camera wants exposure in us: self.cam.ExposureTime = int(val * 1000) if param == "framerate": # To set new frame rate for AVT cameras acquisition has to be # interrupted: # TODO Handle this in a cleaner way if val < 210: # empirically found maximum frame rate to be set self.frame.waitFrameCapture(self.timeout_ms) self.cam.runFeatureCommand("AcquisitionStop") self.cam.endCapture() self.cam.revokeAllFrames() self.cam.AcquisitionFrameRate = val self.cam.startCapture() self.frame.queueFrameCapture() self.cam.runFeatureCommand("AcquisitionStart") except VimbaException: print("Invalid value! The parameter will not be changed.") def read(self): """ """ try: self.frame.waitFrameCapture(self.timeout_ms) self.frame.queueFrameCapture() raw_data = self.frame.getBufferByteData() frame = np.ndarray( buffer=raw_data, dtype=np.uint8, shape=(self.frame.height, self.frame.width), ) except VimbaException: frame = None if self.debug: print("Unable to acquire frame") return frame def release(self): """ """ self.frame.waitFrameCapture(self.timeout_ms) self.cam.runFeatureCommand("AcquisitionStop") self.cam.endCapture() self.cam.revokeAllFrames() self.vimba.shutdown()