"""AVT Camera module (:mod:`pymanip.video.avt`)
===============================================
This module implements the :class:`pymanip.video.avt.AVT_Camera` class
using the third-party :mod:`pymba` module.
.. autoclass:: AVT_Camera
:members:
:private-members:
:show-inheritance:
"""
import numpy as np
from pymanip.video import MetadataArray, Camera, CameraTimeout
from pymanip.asynctools import synchronize_generator
from pymba import Vimba
from pymba.vimbaexception import VimbaException
import sys
[docs]class AVT_Camera(Camera):
"""Concrete :class:`pymanip.video.Camera` class for AVT camera.
:param cam_num: camera number, defaults to 0
:type cam_num: int, optional
:param pixelFormat: pixel format to use, e.g. "Mono8", "Mono16". Defaults to "Mono16"
:type pixelFormat: str, optional
"""
# Class attributes
system = None
vimba = None
active_cameras = set()
[docs] @classmethod
def get_camera_list(cls):
"""This methods returns the list of camera numbers connected to
the computer.
:return: camera ids
:rtype: list
"""
if cls.vimba:
return cls.vimba.getCameraIds()
else:
with Vimba() as vimba_:
return vimba_.getCameraIds()
def __init__(self, cam_num=0, pixelFormat="Mono16"):
"""Constructor method
"""
if not AVT_Camera.vimba:
AVT_Camera.vimba = Vimba().__enter__()
if not AVT_Camera.system:
AVT_Camera.system = AVT_Camera.vimba.getSystem()
self.cameraDesc = AVT_Camera.get_camera_list()[cam_num]
# self.info = vimba.getCameraInfo(self.cameraDesc)
self.camera = AVT_Camera.vimba.getCamera(self.cameraDesc)
self.camera.openCamera()
AVT_Camera.active_cameras.add(self)
self.num = cam_num
self.name = "AVT " + str(cam_num)
self.model_name = self.camera.DeviceModelName.decode("ascii")
print("cam" + str(self.num) + ":", self.model_name)
# par défaut, on démarre en Mode 0 avec la résolution maximale à la
# création de l'objet
self.camera.IIDCMode = "Mode0"
# défaut: ROI entier
self.camera.OffsetX = 0
self.camera.OffsetY = 0
self.camera.Width = self.camera.WidthMax
self.camera.Height = self.camera.HeightMax
print(
"cam" + str(self.num) + ": maximum resolution is",
self.camera.WidthMax,
"x",
self.camera.HeightMax,
)
print(
"cam" + str(self.num) + ": maximum framerate at full resolution is",
self.camera_feature_info("AcquisitionFrameRate")["range"][1],
)
self.camera.PixelFormat = pixelFormat.encode("ascii")
[docs] def close(self):
"""This method closes the connection to the camera.
"""
self.camera.closeCamera()
self.camera = None
AVT_Camera.active_cameras.remove(self)
if len(AVT_Camera.active_cameras) == 0:
AVT_Camera.system = None
AVT_Camera.vimba.__exit__(None, None, None)
AVT_Camera.vimba = None
def __exit__(self, type_, value, cb):
"""Context manager exit method
"""
super(AVT_Camera, self).__exit__(type_, value, cb)
self.close()
[docs] def camera_features(self):
"""This methods returns the list of possible camera features.
:return: camera feature
:rtype: list
"""
cameraFeatureNames = self.camera.getFeatureNames()
return [f.decode("ascii") for f in cameraFeatureNames]
[docs] def camera_feature_info(self, featureName):
"""This method queries the camera for the specified feature.
:param featureName: one of the features returned by :meth:`~pymanip.video.avt.AVT_Camera.camera_features`
:type featureName: str
:return: values associated with the specified feature
:rtype: dict
"""
featureInfo = self.camera.getFeatureInfo(featureName)
featDict = {
field.decode("ascii")
if isinstance(field, bytes)
else field: getattr(featureInfo, field)
for field in featureInfo.getFieldNames()
}
featDict["value"] = getattr(self.camera, featureName)
featDict["range"] = self.camera.getFeatureRange(featureName)
featDict["featureDataTypeName"] = {
0: "Unknown feature type",
1: "64 bit integer",
2: "64 bit floating point",
3: "Enumeration feature",
4: "String feature",
5: "Boolean feature",
6: "Command feature",
7: "Raw (direct register access) feature",
8: "Feature with no data",
}[featDict["featureDataType"]]
featDict["featureFlagsStr"] = ""
if featDict["featureFlags"] & 1:
featDict["featureFlagsStr"] += "r" # read access
if featDict["featureFlags"] & 2:
featDict["featureFlagsStr"] += "w" # write access
if featDict["featureFlags"] & 8:
featDict["featureFlagsStr"] += "v" # volatile
if featDict["featureFlags"] & 16:
featDict["featureFlagsStr"] += "m" # may change after write
for k in featDict:
if isinstance(featDict[k], bytes):
featDict[k] = featDict[k].decode("ascii")
return featDict
[docs] def acquisition_oneshot(self):
"""Concrete implementation of :meth:`pymanip.video.Camera.acquisition_oneshot` for the AVT camera.
"""
self.camera.AcquisitionMode = "SingleFrame"
self.frame = self.camera.getFrame()
self.frame.announceFrame()
self.camera.startCapture()
try:
self.frame.queueFrameCapture()
self.camera.runFeatureCommand("AcquisitionStart")
self.camera.runFeatureCommand("AcquisitionStop")
self.frame.waitFrameCapture()
# print('timestamp =', self.frame.timestamp)
# print('pixel_bytes =', self.frame.pixel_bytes)
if self.frame.pixel_bytes == 1:
dt = np.uint8
elif self.frame.pixel_bytes == 2:
dt = np.uint16
else:
raise NotImplementedError
img = MetadataArray(
np.ndarray(
buffer=self.frame.getBufferByteData(),
dtype=dt,
shape=(self.frame.height, self.frame.width),
).copy(),
metadata={"timestamp": self.frame.timestamp * 1e-7},
)
finally:
self.camera.endCapture()
self.camera.revokeAllFrames()
return img
[docs] def set_trigger_mode(self, mode=False):
"""This method sets the trigger mode for the camera.
For external trigger, the method also sets IIDCPacketSizeAuto to 'Maximize'.
:param mode: True if external trigger. False if internal trigger.
:type mode: bool
"""
if mode:
self.camera.TriggerMode = "On"
self.camera.TriggerSource = "InputLines"
self.camera.IIDCPacketSizeAuto = "Maximize"
else:
self.camera.TriggerMode = "Off"
[docs] def set_exposure_time(self, seconds):
"""This method sets the exposure time for the camera.
:param seconds: exposure in seconds. Possible values range from 33.0 µs to 67108895.0 µs.
:type seconds: float
"""
self.camera.ExposureMode = "Timed"
self.camera.ExposureTime = seconds * 1e6
[docs] def set_roi(self, roiX0=0, roiY0=0, roiX1=0, roiY1=0):
"""This mothods sets the position of the upper left corner (X0, Y0) and the lower right (X1, Y1)
corner of the ROI (region of interest) in pixels.
"""
if (roiX1 - roiX0) <= 0 or (roiX1 - roiX0) > self.camera.WidthMax:
raise ValueError("Width must be > 0 and < WidthMax")
if roiX0 < 0:
raise ValueError("X0 must be >= 0")
assert roiX1 >= 0
if (roiY1 - roiY0) <= 0 or (roiY1 - roiY0) > self.camera.HeightMax:
raise ValueError("Height must be > 0 and < HeightMax")
if roiY0 < 0:
raise ValueError("Y0 must be positive")
assert roiY1 >= 0
# On met d'abord l'offset à 0 pour être sûr que la largeur et hauteur est acceptable
self.camera.OffsetX = 0
self.camera.OffsetY = 0
# On change d'abord la largeur et hauteur pour que l'offset soit acceptable
self.camera.Width = roiX1 - roiX0
self.camera.Height = roiY1 - roiY0
# Dernière étape...
self.camera.OffsetX = roiX0
self.camera.OffsetY = roiY0
print(
"cam" + str(self.num) + ": resolution is",
self.camera.Width,
"x",
self.camera.Height,
)
print(
"cam" + str(self.num) + ": maximum framerate is",
self.camera_feature_info("AcquisitionFrameRate")["range"][1],
)
[docs] def acquisition(
self,
num=np.inf,
timeout=1000,
raw=False,
framerate=None,
external_trigger=False,
initialising_cams=None,
raise_on_timeout=True,
):
"""Concrete implementation of :meth:`pymanip.video.Camera.acquisition` for the AVT camera.
"""
yield from synchronize_generator(
self.acquisition_async,
num=num,
timeout=timeout,
raw=raw,
framerate=framerate,
external_trigger=external_trigger,
initialising_cams=initialising_cams,
raise_on_timeout=raise_on_timeout,
)
[docs] async def acquisition_async(
self,
num=np.inf,
timeout=1000,
raw=False,
framerate=None,
external_trigger=False,
initialising_cams=None,
raise_on_timeout=True,
):
"""Concrete implementation of :meth:`pymanip.video.Camera.acquisition_async` for the AVT camera.
"""
self.camera.AcquisitionMode = "Continuous"
if framerate is not None:
# Not usable if HighSNRIImages>0, external triggering or
# IIDCPacketSizeAuto are active
self.camera.AcquisitionFrameRate = framerate
if external_trigger:
self.camera.TriggerMode = "On"
self.camera.TriggerSource = "InputLines"
self.frame = self.camera.getFrame()
self.frame.announceFrame()
self.camera.startCapture()
self.camera.runFeatureCommand("AcquisitionStart")
self.buffer_queued = False
try:
count = 0
while count < num:
if not self.buffer_queued:
self.frame.queueFrameCapture()
self.buffer_queued = True
if (
count == 0
and initialising_cams is not None
and self in initialising_cams
):
initialising_cams.remove(self)
errorCode = await self.frame.waitFrameCapture_async(int(timeout))
if errorCode == -12:
if raise_on_timeout:
raise CameraTimeout("cam" + str(self.num) + " timeout")
else:
stop_signal = yield None
if stop_signal:
break
else:
continue
elif errorCode != 0:
raise VimbaException(errorCode)
if self.frame.pixel_bytes == 1:
dt = np.uint8
elif self.frame.pixel_bytes == 2:
dt = np.uint16
else:
raise NotImplementedError
self.buffer_queued = False
stop_signal = yield MetadataArray(
np.ndarray(
buffer=self.frame.getBufferByteData(),
dtype=dt,
shape=(self.frame.height, self.frame.width),
),
metadata={
"counter": count,
"timestamp": self.frame.timestamp * 1e-7,
},
)
count += 1
if stop_signal:
break
finally:
self.camera.runFeatureCommand("AcquisitionStop")
self.camera.endCapture()
self.camera.revokeAllFrames()
if stop_signal:
yield True
if __name__ == "__main__":
try:
output = open(sys.argv[1], "w")
except IndexError:
output = sys.stdout
list = AVT_Camera.get_camera_list()
for l in list:
print(l.decode("ascii"), file=output)
with AVT_Camera(0) as cam:
# features
for f in cam.camera_features():
print(f, file=output)
print("-" * 8, file=output)
img = cam.acquisition_oneshot()
for feat in [
"PixelFormat",
"AcquisitionFrameRate",
"AcquisitionMode",
"ExposureAuto",
"ExposureMode",
"ExposureTime",
"IIDCMode",
"IIDCIsoChannel",
"IIDCPacketSize",
"IIDCPacketSizeAuto",
# 'IIDCPhyspeed', 'TriggerMode',
# 'TriggerSource', 'TriggerDelay', 'Gain', 'GainAuto', 'GainSelector',
# 'Width', 'WidthMax', 'Height', 'HeightMax', 'HighSNRImages'
]:
featDict = cam.camera_feature_info(feat)
for k, v in featDict.items():
print(k, ":", v, file=output)
print("-" * 8, file=output)
import matplotlib.pyplot as plt
plt.imshow(img, origin="lower", cmap="gray")
plt.show()