diff options
| author | morefigs <morefigs@gmail.com> | 2019-01-30 15:12:13 +1100 |
|---|---|---|
| committer | morefigs <morefigs@gmail.com> | 2019-01-30 15:12:13 +1100 |
| commit | 8001a079833ff96b855cb6f618b1c23a5b05ad7d (patch) | |
| tree | c145667c5e9d32d90655689549d1072c0af1a61b | |
| parent | 87a55df00f138e0b3f5b8469c2a43f868704426c (diff) | |
| parent | 7a915f3af6af7a3a8ef6c9d28aeb87392df3c8b4 (diff) | |
| download | pymba-8001a079833ff96b855cb6f618b1c23a5b05ad7d.tar.gz pymba-8001a079833ff96b855cb6f618b1c23a5b05ad7d.zip | |
v0.2 to master
47 files changed, 1755 insertions, 2347 deletions
@@ -37,3 +37,6 @@ nosetests.xml # PyCharm .idea/ .cache/ + +venv* +scrap/ @@ -1,157 +1,47 @@ # Pymba - - Pymba is a Python wrapper for Allied Vision's Vimba C API. It wraps the VimbaC library file included in the Vimba installation to provide a simple Python interface for Allied Vision cameras. It currently supports most of the functionality provided by Vimba. -## Installation - -Download the Vimba SDK from Allied Vision: https://www.alliedvision.com/en/products/software.html. +## Requirements + +### Vimba SDK + +* Download and run the Vimba SDK installer from Allied Vision from https://www.alliedvision.com/en/products/software.html. +* Select "Custom Selection". +* Select (at least) the following options: + * A transport layer that matches your hardware (e.g. "Vimba USB Transport Layer" for USB cameras) + * Core components + * Register GenICam Path variable + * Vimba SDK + * Core components + * Register environment variables + * C API runtime components + * C API development components + * Driver Installer + * Vimba Viewer +* Run `VimbaDriverInstaller.exe` and install the relevant driver. +* Test the driver installation by running `VimbaViewer.exe`. -Run the AVTDriverInstaller tool and install the AVT Vimba SDK drivers. +## Installation -Install pymba. +Install Pymba via PIP. -## Usage + pip install pymba -### Testing installation +## Testing installation If Vimba and pymba are installed correctly, then the following code examples should give the installed Vimba version. No camera is needed. -Checking the version using a context manager: - - from pymba import * - - with Vimba() as vimba: - print(vimba.getVersion()) - -Or without using a context manager: - - from pymba import * - - vimba = Vimba() - vimba.startup() - print(vimba.getVersion()) - vimba.shutdown() - -### Interacting with cameras - -Discover, open, manipulate, and capture frames from a camera. - - from pymba import * - import time - - # start Vimba - with Vimba() as vimba: - # get system object - system = vimba.getSystem() - - # list available cameras (after enabling discovery for GigE cameras) - if system.GeVTLIsPresent: - system.runFeatureCommand("GeVDiscoveryAllOnce") - time.sleep(0.2) - cameraIds = vimba.getCameraIds() - for cameraId in cameraIds: - print(cameraId) - - # get and open a camera - camera0 = vimba.getCamera(cameraIds[0]) - camera0.openCamera() - - # list camera features - cameraFeatureNames = camera0.getFeatureNames() - for name in cameraFeatureNames: - print(name) - - # get the value of a feature - print(camera0.AcquisitionMode) - - # set the value of a feature - camera0.AcquisitionMode = 'SingleFrame' - - # create new frames for the camera - frame0 = camera0.getFrame() # creates a frame - frame1 = camera0.getFrame() # creates a second frame - - # announce frame - frame0.announceFrame() - - # capture a camera image - camera0.startCapture() - frame0.queueFrameCapture() - camera0.runFeatureCommand('AcquisitionStart') - camera0.runFeatureCommand('AcquisitionStop') - frame0.waitFrameCapture() - - # get image data... - imgData = frame0.getBufferByteData() - - # ...or use NumPy for fast image display (for use with OpenCV, etc) - import numpy as np - moreUsefulImgData = np.ndarray(buffer = frame0.getBufferByteData(), - dtype = np.uint8, - shape = (frame0.height, - frame0.width, - 1)) - - # clean up after capture - camera0.endCapture() - camera0.revokeAllFrames() - - # close camera - -### Interacting with the Vimba system - -Get a reference to the Vimba system object and list available system features. - - from pymba import * - - with Vimba() as vimba: - # get system object - system = vimba.getSystem() - - # list system features - for featureName in system.getFeatureNames(): - print(featureName) - -### Interacting with transport layer interfaces - -Get a reference to an interface object and list available interface features. + from pymba import Vimba - from pymba import * + print(Vimba.version()) - with Vimba() as vimba: - # get list of available interfaces - interfaceIds = vimba.getInterfaceIds() - for interfaceId in interfaceIds: - print(interfaceId) - - # get interface object and open it - interface0 = vimba.getInterface(interfaceIds[0]) - interface0.openInterface() - - # list interface features - interfaceFeatureNames = interface0.getFeatureNames() - for name in interfaceFeatureNames: - print(name) - - # close interface - interface0.closeInterface() - - - -### Handling Vimba exceptions - - from pymba import * - - try: - with Vimba() as vimba: - except VimbaException as e: - print(e.message) +## Usage examples - +Usage examples can be found in [examples/](examples/). ## Known issues -* Not all API functions are wrapped (most are). For full list see vimbadll.py. +* Not all API functions are supported. +* Not all camera pixel formats are currently supported. diff --git a/examples/camera/get_camera_object.py b/examples/camera/get_camera_object.py new file mode 100644 index 0000000..7a830f7 --- /dev/null +++ b/examples/camera/get_camera_object.py @@ -0,0 +1,9 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + # provide camera index or id + camera = vimba.camera(0) + print(camera) diff --git a/examples/camera/list_camera_ids.py b/examples/camera/list_camera_ids.py new file mode 100644 index 0000000..670d71f --- /dev/null +++ b/examples/camera/list_camera_ids.py @@ -0,0 +1,7 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + print(vimba.camera_ids()) diff --git a/examples/camera/list_feature_infos.py b/examples/camera/list_feature_infos.py new file mode 100644 index 0000000..03ad935 --- /dev/null +++ b/examples/camera/list_feature_infos.py @@ -0,0 +1,14 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + for feature_name in camera.feature_names(): + feature = camera.feature(feature_name) + print(feature.info) + + camera.close() diff --git a/examples/camera/list_feature_names.py b/examples/camera/list_feature_names.py new file mode 100644 index 0000000..d3415dc --- /dev/null +++ b/examples/camera/list_feature_names.py @@ -0,0 +1,13 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + for feature_name in camera.feature_names(): + print(feature_name) + + camera.close() diff --git a/examples/camera/list_feature_values_and_ranges.py b/examples/camera/list_feature_values_and_ranges.py new file mode 100644 index 0000000..353d48e --- /dev/null +++ b/examples/camera/list_feature_values_and_ranges.py @@ -0,0 +1,34 @@ +from pymba import Vimba, VimbaException + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + # get feature value via feature object + for feature_name in camera.feature_names(): + feature = camera.feature(feature_name) + + try: + value = feature.value + range_ = feature.range + + # alternatively the feature value can be read as an object attribute + # value = getattr(camera, feature_name) + # or + # value = camera.someFeatureName + + except VimbaException as e: + value = e + range_ = None + + print('\n\t'.join( + str(x) for x in ( + feature_name, + f'value: {value}', + f'range: {range_}') + if x is not None)) + + camera.close() diff --git a/examples/camera/opencv_capture_image.py b/examples/camera/opencv_capture_image.py new file mode 100644 index 0000000..e8bf3d5 --- /dev/null +++ b/examples/camera/opencv_capture_image.py @@ -0,0 +1,34 @@ +import cv2 +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + # setup camera and frame and capture a single image + camera.AcquisitionMode = 'SingleFrame' + frame = camera.create_frame() + frame.announce() + camera.start_capture() + frame.queue_for_capture() + camera.run_feature_command('AcquisitionStart') + camera.run_feature_command('AcquisitionStop') + frame.wait_for_capture() + + # get the image data as a numpy array + image = frame.image_numpy_array() + + # display image + cv2.imshow(camera.camera_id, image) + # waits for user to close image + cv2.waitKey(0) + + # stop capturing and clean up + camera.end_capture() + camera.flush_capture_queue() + camera.revoke_all_frames() + + camera.close() diff --git a/examples/camera/opencv_capture_image_with_callback.py b/examples/camera/opencv_capture_image_with_callback.py new file mode 100644 index 0000000..4d5fa28 --- /dev/null +++ b/examples/camera/opencv_capture_image_with_callback.py @@ -0,0 +1,44 @@ +from time import sleep +import cv2 +from pymba import Vimba +from pymba.frame import Frame + + +def on_callback(completed_frame: Frame): + print('Callback called!') + + # get the image data as a numpy array + image = completed_frame.image_numpy_array() + + # display image + cv2.imshow(camera.camera_id, image) + # waits for user to close image + cv2.waitKey(0) + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + # setup camera and frame and capture a single image + camera.AcquisitionMode = 'SingleFrame' + frame = camera.create_frame() + frame.announce() + camera.start_capture() + frame.queue_for_capture(on_callback) + camera.run_feature_command('AcquisitionStart') + camera.run_feature_command('AcquisitionStop') + + # wait long enough for the frame callback to be called + for _ in range(100): + sleep(0.1) + print('.', end='') + + # stop capturing and clean up + camera.end_capture() + camera.flush_capture_queue() + camera.revoke_all_frames() + + camera.close() diff --git a/examples/camera/write_feature_value.py b/examples/camera/write_feature_value.py new file mode 100644 index 0000000..77f8ce5 --- /dev/null +++ b/examples/camera/write_feature_value.py @@ -0,0 +1,22 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + camera = vimba.camera(0) + camera.open() + + # read a feature value + feature = camera.feature('ExposureAuto') + value = feature.value + + # set the feature value + feature.value = value + + print(feature.name, '=', feature.value) + + # alternatively the feature value can be set as an object attribute + camera.ExposureAuto = feature.value + + camera.close() diff --git a/examples/interface/get_interface_object.py b/examples/interface/get_interface_object.py new file mode 100644 index 0000000..0465223 --- /dev/null +++ b/examples/interface/get_interface_object.py @@ -0,0 +1,9 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + # provide interface index or id + interface = vimba.interface(0) + print(interface) diff --git a/examples/interface/list_feature_infos.py b/examples/interface/list_feature_infos.py new file mode 100644 index 0000000..fefa079 --- /dev/null +++ b/examples/interface/list_feature_infos.py @@ -0,0 +1,14 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + interface = vimba.interface(0) + interface.open() + + for feature_name in interface.feature_names(): + feature = interface.feature(feature_name) + print(feature.info) + + interface.close() diff --git a/examples/interface/list_feature_names.py b/examples/interface/list_feature_names.py new file mode 100644 index 0000000..6f0347d --- /dev/null +++ b/examples/interface/list_feature_names.py @@ -0,0 +1,13 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + interface = vimba.interface(0) + interface.open() + + for feature_name in interface.feature_names(): + print(feature_name) + + interface.close() diff --git a/examples/interface/list_feature_values_and_ranges.py b/examples/interface/list_feature_values_and_ranges.py new file mode 100644 index 0000000..b33c76a --- /dev/null +++ b/examples/interface/list_feature_values_and_ranges.py @@ -0,0 +1,33 @@ +from pymba import Vimba, VimbaException + + +if __name__ == '__main__': + + with Vimba() as vimba: + interface = vimba.interface(0) + interface.open() + + # get feature value via feature object + for feature_name in interface.feature_names(): + feature = interface.feature(feature_name) + try: + value = feature.value + range_ = feature.range + + # alternatively the feature value can be read as an object attribute + # value = getattr(interface, feature_name) + # or + # value = interface.someFeatureName + + except VimbaException as e: + value = e + range_ = None + + print('\n\t'.join( + str(x) for x in ( + feature_name, + f'value: {value}', + f'range: {range_}') + if x is not None)) + + interface.close() diff --git a/examples/interface/list_interface_ids.py b/examples/interface/list_interface_ids.py new file mode 100644 index 0000000..9a7cbec --- /dev/null +++ b/examples/interface/list_interface_ids.py @@ -0,0 +1,7 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + print(vimba.interface_ids()) diff --git a/examples/interface/write_feature_value.py b/examples/interface/write_feature_value.py new file mode 100644 index 0000000..0c71da2 --- /dev/null +++ b/examples/interface/write_feature_value.py @@ -0,0 +1,22 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + interface = vimba.interface(0) + interface.open() + + # set a feature value by feature name + feature = interface.feature('InterfacePingPace') + value = feature.value + + # set the feature value + feature.value = value + + print(feature.name, '=', feature.value) + + # alternatively the feature value can be set as an object attribute + interface.InterfacePingPace = 3 + + interface.close() diff --git a/examples/show_version.py b/examples/show_version.py new file mode 100644 index 0000000..643dc1c --- /dev/null +++ b/examples/show_version.py @@ -0,0 +1,6 @@ +from pymba import Vimba, PYMBA_VERSION + + +if __name__ == '__main__': + print(f'Pymba version: {PYMBA_VERSION}') + print(f'Vimba version: {Vimba.version()}') diff --git a/examples/system/get_system_object.py b/examples/system/get_system_object.py new file mode 100644 index 0000000..2d59001 --- /dev/null +++ b/examples/system/get_system_object.py @@ -0,0 +1,8 @@ +from pymba import Vimba + + +if __name__ == '__main__': + + with Vimba() as vimba: + system = vimba.system() + print(system) diff --git a/examples/system/list_feature_values_and_ranges.py b/examples/system/list_feature_values_and_ranges.py new file mode 100644 index 0000000..ef4da34 --- /dev/null +++ b/examples/system/list_feature_values_and_ranges.py @@ -0,0 +1,30 @@ +from pymba import Vimba, VimbaException + + +if __name__ == '__main__': + + with Vimba() as vimba: + system = vimba.system() + + # get feature value via feature object + for feature_name in system.feature_names(): + feature = system.feature(feature_name) + try: + value = feature.value + range_ = feature.range + + # alternatively the feature value can be read as an object attribute + # value = getattr(system, feature_name) + # or + # value = system.someFeatureName + + except VimbaException as e: + value = e + range_ = None + + print('\n\t'.join( + str(x) for x in ( + feature_name, + f'value: {value}', + f'range: {range_}') + if x is not None)) diff --git a/pymba/__init__.py b/pymba/__init__.py index c21ed07..b067302 100644 --- a/pymba/__init__.py +++ b/pymba/__init__.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from .vimba import Vimba -from .vimba_exception import VimbaException +from .vimba import Vimba, VimbaException + +PYMBA_VERSION = 0.2 diff --git a/pymba/camera.py b/pymba/camera.py new file mode 100644 index 0000000..3bdc16b --- /dev/null +++ b/pymba/camera.py @@ -0,0 +1,161 @@ +from ctypes import byref, sizeof, c_uint32 +from typing import Optional, List + +from .vimba_object import VimbaObject +from .vimba_exception import VimbaException +from .frame import Frame +from . import vimba_c + + +# todo update this to be more like VmbPixelFormatType in VmbCommonTypes.h +# Map pixel formats to bytes per pixel +PIXEL_FORMAT_BYTES = { + "Mono8": 1, + "Mono12": 2, + "Mono12Packed": 1.5, + "Mono14": 2, + "Mono16": 2, + "RGB8": 3, + "RGB8Packed": 3, + "BGR8Packed": 3, + "RGBA8Packed": 4, + "BGRA8Packed": 4, + "YUV411Packed": 4 / 3.0, + "YUV422Packed": 2, + "YUV444Packed": 3, + "BayerRG8": 1, + "BayerRG12": 2, + "BayerGR8": 1, + "BayerGR12": 2, + "BayerGR12Packed": 1.5, +} + + +def _camera_infos() -> List[vimba_c.VmbCameraInfo]: + """ + Gets camera info of all attached cameras. + """ + # call once just to get the number of cameras + vmb_camera_info = vimba_c.VmbCameraInfo() + num_found = c_uint32(-1) + error = vimba_c.vmb_cameras_list(byref(vmb_camera_info), + 0, + byref(num_found), + sizeof(vmb_camera_info)) + if error and error != VimbaException.ERR_DATA_TOO_LARGE: + raise VimbaException(error) + + # call again to get the features + num_cameras = num_found.value + vmb_camera_infos = (vimba_c.VmbCameraInfo * num_cameras)() + error = vimba_c.vmb_cameras_list(vmb_camera_infos, + num_cameras, + byref(num_found), + sizeof(vmb_camera_info)) + if error: + raise VimbaException(error) + return list(vmb_camera_info for vmb_camera_info in vmb_camera_infos) + + +def _camera_info(id_string: str) -> vimba_c.VmbCameraInfo: + """ + Gets camera info object of specified camera. + :param id_string: the ID of the camera object to get. This can be an ID or e.g. a serial number. Check the Vimba + documentation for other possible values. + """ + vmb_camera_info = vimba_c.VmbCameraInfo() + error = vimba_c.vmb_camera_info_query(id_string.encode(), + vmb_camera_info, + sizeof(vmb_camera_info)) + if error: + raise VimbaException(error) + return vmb_camera_info + + +def camera_ids(): + """ + Gets IDs of all available cameras. + """ + return list(vmb_camera_info.cameraIdString.decode() + for vmb_camera_info in _camera_infos()) + + +class Camera(VimbaObject): + """ + A Vimba camera object. + """ + + def __init__(self, camera_id: str): + self._camera_id = camera_id + super().__init__() + + @property + def handle(self): + return self._handle + + @property + def camera_id(self) -> str: + return self._camera_id + + @property + def info(self) -> vimba_c.VmbCameraInfo: + """ + Get info of the camera. Does not require the camera to be opened. + """ + return _camera_info(self.camera_id) + + def open(self, camera_access_mode: Optional[int] = VimbaObject.VMB_ACCESS_MODE_FULL): + """ + Open the camera with requested access mode. + """ + error = vimba_c.vmb_camera_open(self.camera_id.encode(), + camera_access_mode, + byref(self._handle)) + if error: + raise VimbaException(error) + + def close(self): + """ + Close the camera. + """ + error = vimba_c.vmb_camera_close(self._handle) + if error: + raise VimbaException(error) + + def revoke_all_frames(self): + """ + Revoke all frames assigned to the camera. + """ + error = vimba_c.vmb_frame_revoke_all(self._handle) + if error: + raise VimbaException(error) + + def start_capture(self): + """ + Prepare the API for incoming frames. + """ + error = vimba_c.vmb_capture_start(self._handle) + if error: + raise VimbaException(error) + + def end_capture(self): + """ + Stop the API from being able to receive frames. + """ + error = vimba_c.vmb_capture_end(self._handle) + if error: + raise VimbaException(error) + + def flush_capture_queue(self): + """ + Flush the capture queue. + """ + error = vimba_c.vmb_capture_queue_flush(self._handle) + if error: + raise VimbaException(error) + + def create_frame(self) -> Frame: + """ + Creates and returns a new frame object. Multiple frames per camera can therefore be returned. + """ + return Frame(self) diff --git a/pymba/feature.py b/pymba/feature.py new file mode 100644 index 0000000..7ac403d --- /dev/null +++ b/pymba/feature.py @@ -0,0 +1,234 @@ +from ctypes import byref, sizeof, c_uint32, c_double, c_char_p, c_bool, c_int64, create_string_buffer +from typing import Tuple, List, Callable + +from .vimba_exception import VimbaException +from . import vimba_c + + +( + _FEATURE_DATA_UNKNOWN, + _FEATURE_DATA_INT, + _FEATURE_DATA_FLOAT, + _FEATURE_DATA_ENUM, + _FEATURE_DATA_STRING, + _FEATURE_DATA_BOOL, + _FEATURE_DATA_COMMAND, + _FEATURE_DATA_RAW, + _FEATURE_DATA_NONE, +) = range(9) + + +class Feature: + """ + A feature of a Vimba object. + """ + + @property + def name(self): + return self._name.decode() + + @property + def info(self) -> vimba_c.VmbFeatureInfo: + return self._feature_info() + + @property + def value(self): + return self._access_func('get', self.info.featureDataType)() + + @value.setter + def value(self, val): + self._access_func('set', self.info.featureDataType)(val) + + @property + def range(self): + return self._access_func('range', self.info.featureDataType)() + + def __init__(self, name, handle): + self._name = name.encode() + self._handle = handle + + def _access_func(self, func_type: str, data_type: int) -> Callable: + """ + Get the correct function needed to access the feature attribute based on the feature's data type. + :param func_type: One of 'get', 'set', or 'range'. + :param data_type: Data type as defined in VmbFeatureDataType. + """ + # (getter, setter, range) funcs + access_funcs = { + _FEATURE_DATA_UNKNOWN: (), + _FEATURE_DATA_INT: (self._get_int, + self._set_int, + self._range_query_int), + _FEATURE_DATA_FLOAT: (self._get_float, + self._set_float, + self._range_query_float), + _FEATURE_DATA_ENUM: (self._get_enum, + self._set_enum, + self._range_query_enum), + _FEATURE_DATA_STRING: (self._get_string, + self._set_string), + _FEATURE_DATA_BOOL: (self._get_bool, + self._set_bool), + _FEATURE_DATA_COMMAND: (), + _FEATURE_DATA_RAW: (), + _FEATURE_DATA_NONE: (), + } + + access_indices = { + 'get': 0, + 'set': 1, + 'range': 2, + } + + try: + return access_funcs[data_type][access_indices[func_type]] + except IndexError: + raise VimbaException(VimbaException.ERR_NOT_IMPLEMENTED_IN_PYMBA) + + def _feature_info(self) -> vimba_c.VmbFeatureInfo: + vmb_feature_info = vimba_c.VmbFeatureInfo() + error = vimba_c.vmb_feature_info_query(self._handle, + self._name, + byref(vmb_feature_info), + sizeof(vmb_feature_info)) + if error: + raise VimbaException(error) + + return vmb_feature_info + + def _get_int(self) -> int: + value = c_int64() + error = vimba_c.vmb_feature_int_get(self._handle, + self._name, + byref(value)) + if error: + raise VimbaException(error) + + return value.value + + def _set_int(self, value: int) -> None: + error = vimba_c.vmb_feature_int_set(self._handle, + self._name, + value) + if error: + raise VimbaException(error) + + def _get_float(self) -> float: + value = c_double() + error = vimba_c.vmb_feature_float_get(self._handle, + self._name, + byref(value)) + if error: + raise VimbaException(error) + + return value.value + + def _set_float(self, value: float) -> None: + error = vimba_c.vmb_feature_float_set(self._handle, + self._name, + value) + if error: + raise VimbaException(error) + + def _get_enum(self) -> str: + value = c_char_p() + error = vimba_c.vmb_feature_enum_get(self._handle, + self._name, + byref(value)) + if error: + raise VimbaException(error) + + return value.value.decode() + + def _set_enum(self, value: str): + error = vimba_c.vmb_feature_enum_set(self._handle, + self._name, + value.encode()) + if error: + raise VimbaException(error) + + def _get_string(self) -> str: + buffer_size = 256 + value = create_string_buffer(buffer_size) + size_filled = c_uint32() + + error = vimba_c.vmb_feature_string_get(self._handle, + self._name, + value, + buffer_size, + byref(size_filled)) + if error: + raise VimbaException(error) + return value.value.decode() + + def _set_string(self, value: str) -> None: + error = vimba_c.vmb_feature_string_set(self._handle, + self._name, + value.encode()) + if error: + raise VimbaException(error) + + def _get_bool(self) -> bool: + value = c_bool() + error = vimba_c.vmb_feature_bool_get(self._handle, + self._name, + byref(value)) + if error: + raise VimbaException(error) + + return value.value + + def _set_bool(self, value: bool): + error = vimba_c.vmb_feature_bool_set(self._handle, + self._name, + value) + if error: + raise VimbaException(error) + + def _range_query_int(self) -> Tuple[int, int]: + range_min = c_int64() + range_max = c_int64() + error = vimba_c.vmb_feature_int_range_query(self._handle, + self._name, + byref(range_min), + byref(range_max)) + if error: + raise VimbaException(error) + + return int(range_min.value), int(range_max.value) + + def _range_query_float(self) -> Tuple[float, float]: + range_min = c_double() + range_max = c_double() + error = vimba_c.vmb_feature_float_range_query(self._handle, + self._name, + byref(range_min), + byref(range_max)) + if error: + raise VimbaException(error) + + return range_min.value, range_max.value + + def _range_query_enum(self) -> List[str]: + # call once to get number of available enum names + num_found = c_uint32(-1) + error = vimba_c.vmb_feature_enum_range_query(self._handle, + self._name, + None, + 0, + byref(num_found)) + if error: + raise VimbaException(error) + + # call again to get the actual enum names + num_enum_names = num_found.value + enum_names = (c_char_p * num_enum_names)() + error = vimba_c.vmb_feature_enum_range_query(self._handle, + self._name, + enum_names, + num_enum_names, + byref(num_found)) + if error: + raise VimbaException(error) + + return list(enum_name.decode() for enum_name in enum_names) diff --git a/pymba/frame.py b/pymba/frame.py new file mode 100644 index 0000000..5f9bcda --- /dev/null +++ b/pymba/frame.py @@ -0,0 +1,127 @@ +from ctypes import byref, sizeof, addressof, create_string_buffer, cast, POINTER, c_ubyte, c_void_p +from typing import Optional, Callable +import numpy as np + +from . import camera as _camera +from .vimba_exception import VimbaException +from . import vimba_c + + +class MemoryBlock: + """ + A memory block object for dealing neatly with C memory allocations. + """ + + @property + def block(self): + return c_void_p(addressof(self._block)) + + def __init__(self, block_size): + self._block = create_string_buffer(block_size) + + # this seems to be None if too much memory is requested + if self._block is None: + raise VimbaException(VimbaException.ERR_FRAME_BUFFER_MEMORY) + + +class Frame: + """ + A Vimba frame. + """ + + def __init__(self, camera: '_camera.Camera'): + self._camera = camera + + self._vmb_frame = vimba_c.VmbFrame() + + self._c_mem = None + self._frame_callback = None + self._frame_callback_wrapper_c = None + + def announce(self) -> None: + """ + Announce frames to the API that may be queued for frame capturing later. Should be called after the frame is + created. Call startCapture after this method. + """ + # keep this reference to keep block alive for life of frame + self._c_mem = MemoryBlock(self._camera.PayloadSize) + + # set buffer to have length of expected payload size + self._vmb_frame.buffer = self._c_mem.block + + # set buffer size to expected payload size + self._vmb_frame.bufferSize = self._camera.PayloadSize + + error = vimba_c.vmb_frame_announce(self._camera.handle, + byref(self._vmb_frame), + sizeof(self._vmb_frame)) + if error: + raise VimbaException(error) + + def revoke(self) -> None: + """ + Revoke a frame from the API. + """ + error = vimba_c.vmb_frame_revoke(self._camera.handle, + byref(self._vmb_frame)) + if error: + raise VimbaException(error) + + def queue_for_capture(self, frame_callback: Optional[Callable] = None) -> None: + """ + Queue frames that may be filled during frame capturing. Call after announceFrame and startCapture. Callback + must accept argument of type frame. Remember to requeue the frame by calling frame.queue_capture() at the end + of your callback function. + """ + self._frame_callback = frame_callback + + # define a callback wrapper here so it doesn't bind self + def frame_callback_wrapper(camera_handle, frame_ptr): + # call the user's callback with the self bound outside the wrapper + # ignore the frame pointer since we already know the callback refers to this frame + self._frame_callback(self) + + if self._frame_callback is None: + self._frame_callback_wrapper_c = None + else: + # keep a reference to prevent gc issues + self._frame_callback_wrapper_c = vimba_c.vmb_frame_callback_func(frame_callback_wrapper) + + error = vimba_c.vmb_capture_frame_queue(self._camera.handle, + byref(self._vmb_frame), + self._frame_callback_wrapper_c) + if error: + raise VimbaException(error) + + def wait_for_capture(self, timeout_ms: Optional[int] = 2000) -> None: + """ + Wait for a queued frame to be filled (or dequeued). Call after an acquisition command. + :param timeout_ms: time out in milliseconds. + """ + error = vimba_c.vmb_capture_frame_wait(self._camera.handle, + byref(self._vmb_frame), + timeout_ms) + if error: + raise VimbaException(error) + + def image_pointer(self): + """ + Get a pointer to the frame's image data as a ctypes c_ubyte array pointer. + """ + return cast(self._vmb_frame.buffer, POINTER(c_ubyte * self._vmb_frame.bufferSize)) + + def image_buffer(self): + """ + Get a copy of the frame's image data as a ctypes c_ubyte array. + """ + return self.image_pointer().contents + + def image_numpy_array(self) -> np.ndarray: + """ + Get the frame's image data as a NumPy array, which can be used with OpenCV. + """ + # todo pixel formats larger than 8-bit + + return np.ndarray(buffer=self.image_buffer(), + dtype=np.uint8, + shape=(self._vmb_frame.height, self._vmb_frame.width)) diff --git a/pymba/interface.py b/pymba/interface.py new file mode 100644 index 0000000..fdd4675 --- /dev/null +++ b/pymba/interface.py @@ -0,0 +1,92 @@ +from ctypes import byref, sizeof, c_uint32 +from typing import List + +from .vimba_object import VimbaObject +from .vimba_exception import VimbaException +from . import vimba_c + + +def _interface_infos() -> List[vimba_c.VmbInterfaceInfo]: + """ + Gets interface info of all available interfaces. + """ + # call once just to get the number of interfaces + num_found = c_uint32(-1) + error = vimba_c.vmb_interfaces_list(None, + 0, + byref(num_found), + sizeof(vimba_c.VmbInterfaceInfo)) + if error: + raise VimbaException(error) + + # call again to get the features + num_interfaces = num_found.value + vmb_interface_infos = (vimba_c.VmbInterfaceInfo * num_interfaces)() + error = vimba_c.vmb_interfaces_list(vmb_interface_infos, + num_interfaces, + byref(num_found), + sizeof(vimba_c.VmbInterfaceInfo)) + if error: + raise VimbaException(error) + + return list(vmb_interface_info for vmb_interface_info in vmb_interface_infos) + + +def _interface_info(interface_id: str) -> vimba_c.VmbInterfaceInfo: + """ + Gets interface info object of specified interface. + :param interface_id: the ID of the interface object to get. + """ + for vmb_interface_info in _interface_infos(): + if interface_id == vmb_interface_info.interfaceIdString.decode(): + return vmb_interface_info + raise VimbaException(VimbaException.ERR_INSTANCE_NOT_FOUND) + + +def interface_ids() -> List[str]: + """ + Gets IDs of all available interfaces. + """ + return list(vmb_interface_info.interfaceIdString.decode() + for vmb_interface_info in _interface_infos()) + + +class Interface(VimbaObject): + """ + A Vimba interface object. This class provides the minimal access + to Vimba functions required to control the interface. + """ + + def __init__(self, interface_id: str): + if interface_id not in interface_ids(): + raise VimbaException(VimbaException.ERR_INSTANCE_NOT_FOUND) + self._interface_id = interface_id + super().__init__() + + @property + def interface_id(self): + return self._interface_id + + @property + def info(self) -> vimba_c.VmbInterfaceInfo: + """ + Get info of the interface. Does not require the interface to be opened. + """ + return _interface_info(self.interface_id) + + def open(self): + """ + Open the interface. + """ + error = vimba_c.vmb_interface_open(self.interface_id.encode(), + byref(self._handle)) + if error: + raise VimbaException(error) + + def close(self): + """ + Close the interface. + """ + error = vimba_c.vmb_interface_close(self._handle) + if error: + raise VimbaException(error) diff --git a/pymba/system.py b/pymba/system.py new file mode 100644 index 0000000..2cc6870 --- /dev/null +++ b/pymba/system.py @@ -0,0 +1,9 @@ +from .vimba_object import VimbaObject + + +class System(VimbaObject): + """ + A Vimba system object. This class provides the minimal access to Vimba functions required to control the system. + """ + def __init__(self): + super().__init__(handle=1) diff --git a/pymba/vimba.py b/pymba/vimba.py index 5656b7c..02c29c7 100644 --- a/pymba/vimba.py +++ b/pymba/vimba.py @@ -1,49 +1,41 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs -from .vimba_dll import VimbaDLL -from .vimba_exception import VimbaException -from .vimba_system import VimbaSystem -from .vimba_camera import VimbaCamera -from .vimba_interface import VimbaInterface -from ctypes import * +from ctypes import sizeof +from typing import List, Union +from .vimba_exception import VimbaException +from .system import System +from .interface import Interface, interface_ids +from .camera import Camera, camera_ids +from . import vimba_c -class Vimba(object): +class Vimba: """ - An Allied Vision Technology Vimba API. - This API provides access to AVT cameras. + Python wrapper for Allied Vision's Vimba C API. """ - # todo - assign camera info and feature info as own object proeprties + @staticmethod + def version() -> str: + """ + Retrieve the version number of the Vimba C API. + """ + vmb_version_info = vimba_c.VmbVersionInfo() + error = vimba_c.vmb_version_query(vmb_version_info, sizeof(vmb_version_info)) + if error: + raise VimbaException(error) + + return '.'.join(str(x) for x in (vmb_version_info.major, + vmb_version_info.minor, + vmb_version_info.patch)) def __init__(self): - # create own system singleton object - self._system = VimbaSystem() - - # lists of VimbaCameraInfo and VimbaInterfaceInfo objects - # can't be called before startup() so populate later - self._interfaceInfos = None - - # dict of {camera ID : VimbaCamera object} as we don't want to forget - # them - self._cameras = {} - - # dict of {interface ID : VimbaInterface object} as we don't want to - # forget them + self._system = System() self._interfaces = {} + self._cameras = {} def __enter__(self): """ Define vimba context for safe execution. - - The vimba object should be used like this: - # start Vimba - with Vimba() as vimba: - system = vimba.getSystem() - # ... """ self.startup() return self @@ -56,220 +48,66 @@ class Vimba(object): """ self.shutdown() - def _getInterfaceInfos(self): + def startup(self): """ - Gets interface info of all available interfaces. - - :returns: list -- interface info for available interfaces. + Initialize the Vimba C API. """ - if self._interfaceInfos is None: - # args - numFound = c_uint32(-1) - - # call once just to get the number of interfaces - # Vimba DLL will return an error code - errorCode = VimbaDLL.interfacesList(None, - 0, - byref(numFound), - sizeof(structs.VimbaInterfaceInfo)) - if errorCode != 0: - raise VimbaException(errorCode) + error = vimba_c.vmb_startup() + if error: + raise VimbaException(error) - numInterfaces = numFound.value + # automatically check for the presence of a GigE transport layer + if self.system().GeVTLIsPresent: + self.system().run_feature_command('GeVDiscoveryAllOnce') - # args - interfaceInfoArray = (structs.VimbaInterfaceInfo * numInterfaces)() - - # call again to get the features - # Vimba DLL will return an error code - errorCode = VimbaDLL.interfacesList(interfaceInfoArray, - numInterfaces, - byref(numFound), - sizeof(structs.VimbaInterfaceInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - self._interfaceInfos = list( - interfaceInfo for interfaceInfo in interfaceInfoArray) - return self._interfaceInfos - - def _getCameraInfos(self): + @staticmethod + def shutdown(): """ - Gets camera info of all attached cameras. - - :returns: list -- camera info for available cameras. + Perform a shutdown on the API. """ - # args - dummyCameraInfo = structs.VimbaCameraInfo() - numFound = c_uint32(-1) - - # call once just to get the number of cameras - # Vimba DLL will return an error code - errorCode = VimbaDLL.camerasList(byref(dummyCameraInfo), - 0, - byref(numFound), - sizeof(dummyCameraInfo)) - if errorCode != 0 and errorCode != -9: - raise VimbaException(errorCode) - - numCameras = numFound.value - - # args - cameraInfoArray = (structs.VimbaCameraInfo * numCameras)() + vimba_c.vmb_shutdown() - # call again to get the features - # Vimba DLL will return an error code - errorCode = VimbaDLL.camerasList(cameraInfoArray, - numCameras, - byref(numFound), - sizeof(dummyCameraInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - return list(camInfo for camInfo in cameraInfoArray) - - def getSystem(self): + def system(self) -> System: """ - Gets system singleton object. - - :returns: VimbaSystem object -- the system singleton object. + Get the system object. """ return self._system - def getInterfaceIds(self): - """ - Gets IDs of all available interfaces. + @staticmethod + def interface_ids(): + return interface_ids() - :returns: list -- interface IDs for available interfaces. + def interface(self, interface_id: Union[str, int]) -> Interface: """ - return list(interfaceInfo.interfaceIdString for interfaceInfo in self._getInterfaceInfos()) - - def getCameraIds(self): + Gets interface object based on interface ID string or index. Will not recreate interface object if it already exists. + :param interface_id: the ID or the index of the interface. """ - Gets IDs of all available cameras. + # if index is provided, look up the camera id using the index + if isinstance(interface_id, int): + interface_id = interface_ids()[interface_id] - :returns: list -- camera IDs for available cameras. - """ - return list(camInfo.cameraIdString.decode() for camInfo in self._getCameraInfos()) - - def getInterfaceInfo(self, interfaceId): - """ - Gets interface info object of specified interface. + if interface_id in self._interfaces: + return self._interfaces[interface_id] + interface = Interface(interface_id) + self._interfaces[interface_id] = interface + return interface - :param interfaceId: the ID of the interface object to get. + @staticmethod + def camera_ids() -> List[str]: + return camera_ids() - :returns: VimbaInterfaceInfo object -- the interface info object specified. + def camera(self, camera_id: Union[str, int]) -> Camera: """ - # don't do this live as we already have this info - # return info object if it exists - for interfaceInfo in self._getInterfaceInfos(): - if interfaceInfo.interfaceIdString == interfaceId: - return interfaceInfo - # otherwise raise error - raise VimbaException(-54) - - def getCameraInfo(self, cameraId): - """ - Gets camera info object of specified camera. - - :param cameraId: the ID of the camera object to get. - This might not only be a cameraId as returned by getCameraIds() - but also e.g. a serial number. Check the Vimba documentation for - other possible values. - - :returns: VimbaCameraInfo object -- the camera info object specified. - """ - cameraInfo = structs.VimbaCameraInfo() - errorCode = VimbaDLL.cameraInfoQuery(cameraId.encode(), - cameraInfo, - sizeof(cameraInfo)) - if errorCode == 0: - return cameraInfo - - # otherwise raise error - raise VimbaException(-50) - - def getInterface(self, interfaceId): - """ - Gets interface object based on interface ID string. Will not recreate - interface object if it already exists. - - :param interfaceId: the ID of the interface. - - :returns: VimbaInterface object -- the interface object specified. - """ - # check ID is valid - if interfaceId in self.getInterfaceIds(): - # create it if it doesn't exist - if interfaceId not in self._interfaces: - self._interfaces[interfaceId] = VimbaInterface(interfaceId) - return self._interfaces[interfaceId] - raise VimbaException(-54) - - def getCamera(self, cameraId): - """ - Gets camera object based on camera ID string. Will not recreate - camera object if it already exists. - - :param cameraId: the ID of the camera object to get. - This might not only be a cameraId as returned by getCameraIds() - but also e.g. a serial number. Check the Vimba documentation for - other possible values. - - :returns: VimbaCamera object -- the camera object specified. - """ - # check ID is valid - if cameraId in self.getCameraIds(): - # create it if it doesn't exist - if cameraId not in self._cameras: - self._cameras[cameraId] = VimbaCamera(cameraId) - return self._cameras[cameraId] - else: - # the given string might not be a camera ID -> check for other IDs - cameraInfo = structs.VimbaCameraInfo() - errorCode = VimbaDLL.cameraInfoQuery(cameraId.encode(), - cameraInfo, - sizeof(cameraInfo)) - if errorCode != 0: - raise VimbaException(-50) # camera not found - - cameraIdString = cameraInfo.cameraIdString.decode() - if cameraIdString not in self._cameras: - self._cameras[cameraIdString] = VimbaCamera(cameraIdString) - return self._cameras[cameraIdString] - - - def getVersion(self): - """ - Retrieve the version number of VimbaC. - - :returns: string - Vimba API version info. - """ - # args - versionInfo = structs.VimbaVersion() - - # Vimba DLL will return an error code - errorCode = VimbaDLL.versionQuery( - versionInfo, - sizeof(versionInfo) - ) - if errorCode: - raise VimbaException(errorCode) - - versionStr = '.'.join([str(versionInfo.major), - str(versionInfo.minor), - str(versionInfo.patch)]) - return versionStr - - def startup(self): - """ - Initialize the VimbaC API. + Gets camera object based on camera ID string or index. Will not recreate camera object if it already exists. + :param camera_id: the ID or the index of the camera object to get. This can be an ID or e.g. a serial number. + Check the Vimba documentation for other possible values. """ - # Vimba DLL will return an error code - errorCode = VimbaDLL.startup() - if errorCode != 0: - raise VimbaException(errorCode) + # if index is provided, look up the camera id using the index + if isinstance(camera_id, int): + camera_id = camera_ids()[camera_id] - def shutdown(self): - """ - Perform a shutdown on the API. - """ - VimbaDLL.shutdown() + if camera_id in self._cameras: + return self._cameras[camera_id] + camera = Camera(camera_id) + self._cameras[camera_id] = camera + return camera diff --git a/pymba/vimba_c.py b/pymba/vimba_c.py new file mode 100644 index 0000000..034df6e --- /dev/null +++ b/pymba/vimba_c.py @@ -0,0 +1,430 @@ +from sys import platform as sys_plat +import platform +import os +from ctypes import * + + +if sys_plat == "win32": + + def find_win_dll(arch): + """ Finds the highest versioned windows dll for the specified architecture. """ + bases = [ + r'C:\Program Files\Allied Vision Technologies\AVTVimba_%i.%i\VimbaC\Bin\Win%i\VimbaC.dll', + r'C:\Program Files\Allied Vision\Vimba_%i.%i\VimbaC\Bin\Win%i\VimbaC.dll' + ] + dlls = [] + for base in bases: + for major in range(3): + for minor in range(10): + candidate = base % (major, minor, arch) + if os.path.isfile(candidate): + dlls.append(candidate) + if not dlls: + if 'VIMBA_HOME' in os.environ: + candidate = os.environ ['VIMBA_HOME'] + '\VimbaC\Bin\Win%i\VimbaC.dll' % (arch) + if os.path.isfile(candidate): + dlls.append(candidate) + if not dlls: + raise IOError("VimbaC.dll not found.") + return dlls[-1] + + if '64' in platform.architecture()[0]: + vimbaC_path = find_win_dll(64) + else: + vimbaC_path = find_win_dll(32) + dll_loader = windll + +else: + dll_loader = cdll + + if 'x86_64' in os.uname()[4]: + assert os.environ.get( + "GENICAM_GENTL64_PATH"), "you need your GENICAM_GENTL64_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" + tlPath = [p for p in os.environ.get("GENICAM_GENTL64_PATH").split(":") if p][0] + vimba_dir = "/".join(tlPath.split("/")[1:-3]) + vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/x86_64bit/libVimbaC.so" + elif 'x86_32' in os.uname()[4]: + print("Warning: x86_32 reached!") + assert os.environ.get( + "GENICAM_GENTL32_PATH"), "you need your GENICAM_GENTL32_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" + tlPath = [p for p in os.environ.get("GENICAM_GENTL32_PATH").split(":") if p][0] + vimba_dir = "/".join(tlPath.split("/")[1:-3]) + vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/x86_32bit/libVimbaC.so" + elif 'arm' in os.uname()[4]: + assert os.environ.get( + "GENICAM_GENTL32_PATH"), "you need your GENICAM_GENTL32_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" + tlPath = [p for p in os.environ.get("GENICAM_GENTL32_PATH").split(":") if p][0] + vimba_dir = "/".join(tlPath.split("/")[1:-3]) + vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/arm_32bit/libVimbaC.so" + elif 'aarch64' in os.uname()[4]: + assert os.environ.get( + "GENICAM_GENTL64_PATH"), "you need your GENICAM_GENTL64_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" + tlPath = [p for p in os.environ.get("GENICAM_GENTL64_PATH").split(":") if p][0] + vimba_dir = "/".join(tlPath.split("/")[1:-3]) + vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/arm_64bit/libVimbaC.so" + else: + raise ValueError("Pymba currently doesn't support %s" % os.uname()[4]) + + +# Callback function type +if sys_plat == "win32": + CALLBACK_FUNCTYPE = WINFUNCTYPE +else: + CALLBACK_FUNCTYPE = CFUNCTYPE + + +class NiceStructure(Structure): + def __repr__(self): + field_names = (field[0] for field in self._fields_) + return f'{type(self).__name__}(' \ + f'{", ".join("=".join((field, str(getattr(self, field)))) for field in field_names)})' + + +class VmbVersionInfo(NiceStructure): + _fields_ = [ + ('major', c_uint32), + ('minor', c_uint32), + ('patch', c_uint32)] + + +class VmbInterfaceInfo(NiceStructure): + _fields_ = [ + # Unique identifier for each interface + ('interfaceIdString', c_char_p), + # Interface type, see VmbInterfaceType + ('interfaceType', c_uint32), + # Interface name, given by the transport layer + ('interfaceName', c_char_p), + # Serial number + ('serialString', c_char_p), + # Used access mode, see VmbAccessModeType + ('permittedAccess', c_uint32)] + + +class VmbCameraInfo(NiceStructure): + _fields_ = [ + # Unique identifier for each camera + ('cameraIdString', c_char_p), + # Name of the camera + ('cameraName', c_char_p), + # Model name + ('modelName', c_char_p), + # Serial number + ('serialString', c_char_p), + # Used access mode, see VmbAccessModeType + ('permittedAccess', c_uint32), + # Unique value for each interface or bus + ('interfaceIdString', c_char_p)] + + +class VmbFeatureInfo(NiceStructure): + _fields_ = [ + ('name', c_char_p), + ('featureDataType', c_uint32), + ('featureFlags', c_uint32), + ('category', c_char_p), + ('displayName', c_char_p), + ('pollingTime', c_uint32), + ('unit', c_char_p), + ('representation', c_char_p), + ('visibility', c_uint32), + ('tooltip', c_char_p), + ('description', c_char_p), + ('sfncNamespace', c_char_p), + ('isStreamable', c_bool), + ('hasAffectedFeatures', c_bool), + ('hasSelectedFeatures', c_bool)] + + +class VmbFrame(Structure): + _fields_ = [ + # ---- IN ---- + # Comprises image and ancillary data + ('buffer', c_void_p), + # Size of the data buffer + ('bufferSize', c_uint32), + + # User context filled during queuing + ('context', c_void_p * 4), + + # ---- OUT ---- + # Resulting status of the receive operation + ('receiveStatus', c_int32), + # Resulting flags of the receive operation + ('receiveFlags', c_uint32), + + # Size of the image data inside the data buffer + ('imageSize', c_uint32), + # Size of the ancillary data inside the data buffer + ('ancillarySize', c_uint32), + + # Pixel format of the image + ('pixelFormat', c_uint32), + + # Width of an image + ('width', c_uint32), + # Height of an image + ('height', c_uint32), + # Horizontal offset of an image + ('offsetX', c_uint32), + # Vertical offset of an image + ('offsetY', c_uint32), + + # Unique ID of this frame in this stream + ('frameID', c_uint64), + # Timestamp of the data transfer + ('timestamp', c_uint64)] + + +_vimba_lib = dll_loader.LoadLibrary(vimbaC_path) + +# ----- The below function signatures are defined in VimbaC.h ----- + +# callback for frame queue +vmb_frame_callback_func = CALLBACK_FUNCTYPE(c_void_p, + c_void_p, + POINTER(VmbFrame)) + +vmb_version_query = _vimba_lib.VmbVersionQuery +vmb_version_query.restype = c_int32 +vmb_version_query.argtypes = (POINTER(VmbVersionInfo), + c_uint32) + +vmb_startup = _vimba_lib.VmbStartup +vmb_startup.restype = c_int32 + +vmb_shutdown = _vimba_lib.VmbShutdown + +vmb_cameras_list = _vimba_lib.VmbCamerasList +vmb_cameras_list.restype = c_int32 +vmb_cameras_list.argtypes = (POINTER(VmbCameraInfo), + c_uint32, + POINTER(c_uint32), + c_uint32) + +vmb_camera_info_query = _vimba_lib.VmbCameraInfoQuery +vmb_camera_info_query.restype = c_int32 +vmb_camera_info_query.argtypes = (c_char_p, + POINTER(VmbCameraInfo), + c_uint32) + +vmb_camera_open = _vimba_lib.VmbCameraOpen +vmb_camera_open.restype = c_int32 +vmb_camera_open.argtypes = (c_char_p, + c_uint32, + c_void_p) + +vmb_camera_close = _vimba_lib.VmbCameraClose +vmb_camera_close.restype = c_int32 +vmb_camera_close.argtypes = (c_void_p,) + +vmb_features_list = _vimba_lib.VmbFeaturesList +vmb_features_list.restype = c_int32 +vmb_features_list.argtypes = (c_void_p, + POINTER(VmbFeatureInfo), + c_uint32, + POINTER(c_uint32), + c_uint32) + +vmb_feature_info_query = _vimba_lib.VmbFeatureInfoQuery +vmb_feature_info_query.restype = c_int32 +vmb_feature_info_query.argtypes = (c_void_p, + c_char_p, + POINTER(VmbFeatureInfo), + c_uint32) + +# todo VmbFeatureListAffected +# todo VmbFeatureListSelected +# todo VmbFeatureAccessQuery + +vmb_feature_int_get = _vimba_lib.VmbFeatureIntGet +vmb_feature_int_get.restype = c_int32 +vmb_feature_int_get.argtypes = (c_void_p, + c_char_p, + POINTER(c_int64)) + +vmb_feature_int_set = _vimba_lib.VmbFeatureIntSet +vmb_feature_int_set.restype = c_int32 +vmb_feature_int_set.argtypes = (c_void_p, + c_char_p, + c_int64) + +vmb_feature_int_range_query = _vimba_lib.VmbFeatureIntRangeQuery +vmb_feature_int_range_query.restype = c_int32 +vmb_feature_int_range_query.argtypes = (c_void_p, + c_char_p, + POINTER(c_int64), + POINTER(c_int64)) + +# todo VmbFeatureIntIncrementQuery + +vmb_feature_float_get = _vimba_lib.VmbFeatureFloatGet +vmb_feature_float_get.restype = c_int32 +vmb_feature_float_get.argtypes = (c_void_p, + c_char_p, + POINTER(c_double)) + +vmb_feature_float_set = _vimba_lib.VmbFeatureFloatSet +vmb_feature_float_set.restype = c_int32 +vmb_feature_float_set.argtypes = (c_void_p, + c_char_p, + c_double) + +vmb_feature_float_range_query = _vimba_lib.VmbFeatureFloatRangeQuery +vmb_feature_float_range_query.restype = c_int32 +vmb_feature_float_range_query.argtypes = (c_void_p, + c_char_p, + POINTER(c_double), + POINTER(c_double)) + +# todo VmbFeatureFloatIncrementQuery + +vmb_feature_enum_get = _vimba_lib.VmbFeatureEnumGet +vmb_feature_enum_get.restype = c_int32 +vmb_feature_enum_get.argtypes = (c_void_p, + c_char_p, + POINTER(c_char_p)) + +vmb_feature_enum_set = _vimba_lib.VmbFeatureEnumSet +vmb_feature_enum_set.restype = c_int32 +vmb_feature_enum_set.argtypes = (c_void_p, + c_char_p, + c_char_p) + +vmb_feature_enum_range_query = _vimba_lib.VmbFeatureEnumRangeQuery +vmb_feature_enum_range_query.restype = c_int32 +vmb_feature_enum_range_query.argtypes = (c_void_p, + c_char_p, + POINTER(c_char_p), + c_uint32, + POINTER(c_uint32)) + +# todo VmbFeatureEnumIsAvailable +# todo VmbFeatureEnumAsInt +# todo VmbFeatureEnumAsString +# todo VmbFeatureEnumEntryGet + +vmb_feature_string_get = _vimba_lib.VmbFeatureStringGet +vmb_feature_string_get.restype = c_int32 +vmb_feature_string_get.argtypes = (c_void_p, + c_char_p, + c_char_p, + c_uint32, + POINTER(c_uint32)) + +vmb_feature_string_set = _vimba_lib.VmbFeatureStringSet +vmb_feature_string_set.restype = c_int32 +vmb_feature_string_set.argtypes = (c_void_p, + c_char_p, + c_char_p) + +# todo VmbFeatureStringMaxlengthQuery + +vmb_feature_bool_get = _vimba_lib.VmbFeatureBoolGet +vmb_feature_bool_get.restype = c_int32 +vmb_feature_bool_get.argtypes = (c_void_p, + c_char_p, + POINTER(c_bool)) + +vmb_feature_bool_set = _vimba_lib.VmbFeatureBoolSet +vmb_feature_bool_set.restype = c_int32 +vmb_feature_bool_set.argtypes = (c_void_p, + c_char_p, + c_bool) + +vmb_feature_command_run = _vimba_lib.VmbFeatureCommandRun +vmb_feature_command_run.restype = c_int32 +vmb_feature_command_run.argtypes = (c_void_p, + c_char_p) + +vmb_feature_command_is_done = _vimba_lib.VmbFeatureCommandIsDone +vmb_feature_command_is_done.restype = c_int32 +vmb_feature_command_is_done.argtypes = (c_void_p, + c_char_p, + POINTER(c_bool)) + +# todo VmbFeatureRawGet +# todo VmbFeatureRawSet +# todo VmbFeatureRawLengthQuery +# todo VmbFeatureInvalidationRegister +# todo VmbFeatureInvalidationUnregister + +vmb_frame_announce = _vimba_lib.VmbFrameAnnounce +vmb_frame_announce.restype = c_int32 +vmb_frame_announce.argtypes = (c_void_p, + POINTER(VmbFrame), + c_uint32) + +vmb_frame_revoke = _vimba_lib.VmbFrameRevoke +vmb_frame_revoke.restype = c_int32 +vmb_frame_revoke.argtypes = (c_void_p, + POINTER(VmbFrame)) + +vmb_frame_revoke_all = _vimba_lib.VmbFrameRevokeAll +vmb_frame_revoke_all.restype = c_int32 +vmb_frame_revoke_all.argtypes = (c_void_p,) + +vmb_capture_start = _vimba_lib.VmbCaptureStart +vmb_capture_start.restype = c_int32 +vmb_capture_start.argtypes = (c_void_p,) + +vmb_capture_end = _vimba_lib.VmbCaptureEnd +vmb_capture_end.restype = c_int32 +vmb_capture_end.argtypes = (c_void_p,) + +vmb_capture_frame_queue = _vimba_lib.VmbCaptureFrameQueue +vmb_capture_frame_queue.restype = c_int32 +vmb_capture_frame_queue.argtypes = (c_void_p, + POINTER(VmbFrame), + c_void_p) + +vmb_capture_frame_wait = _vimba_lib.VmbCaptureFrameWait +vmb_capture_frame_wait.restype = c_int32 +vmb_capture_frame_wait.argtypes = (c_void_p, + POINTER(VmbFrame), + c_uint32) + +vmb_capture_queue_flush = _vimba_lib.VmbCaptureQueueFlush +vmb_capture_queue_flush.restype = c_int32 +vmb_capture_queue_flush.argtypes = (c_void_p,) + +vmb_interfaces_list = _vimba_lib.VmbInterfacesList +vmb_interfaces_list.restype = c_int32 +vmb_interfaces_list.argtypes = (POINTER(VmbInterfaceInfo), + c_uint32, + POINTER(c_uint32), + c_uint32) + +vmb_interface_open = _vimba_lib.VmbInterfaceOpen +vmb_interface_open.restype = c_int32 +vmb_interface_open.argtypes = (c_char_p, + c_void_p) + +vmb_interface_close = _vimba_lib.VmbInterfaceClose +vmb_interface_close.restype = c_int32 +vmb_interface_close.argtypes = (c_void_p,) + +# todo VmbAncillaryDataOpen +# todo VmbAncillaryDataClose +# todo VmbMemoryRead +# todo VmbMemoryWrite +# todo VmbAncillaryDataOpen + +vmb_registers_read = _vimba_lib.VmbRegistersRead +vmb_registers_read.restype = c_int32 +vmb_registers_read.argtypes = (c_void_p, + c_uint32, + POINTER(c_uint64), + POINTER(c_uint64), + POINTER(c_uint32)) + +vmb_registers_write = _vimba_lib.VmbRegistersWrite +vmb_registers_write.restype = c_int32 +vmb_registers_write.argtypes = (c_void_p, + c_uint32, + POINTER(c_uint64), + POINTER(c_uint64), + POINTER(c_uint32)) + +# todo VmbCameraSettingsSave +# todo VmbCameraSettingsLoad diff --git a/pymba/vimba_camera.py b/pymba/vimba_camera.py deleted file mode 100644 index 5e131a1..0000000 --- a/pymba/vimba_camera.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs -from .vimba_object import VimbaObject -from .vimba_exception import VimbaException -from .vimba_frame import VimbaFrame -from .vimba_dll import VimbaDLL -from ctypes import * - -# camera features are automatically readable as object attributes. - - -class VimbaCamera(VimbaObject): - - """ - A Vimba camera object. This class provides the minimal access - to Vimba functions required to control the camera. - """ - - @property - def cameraIdString(self): - return self._cameraIdString.decode() - - # own handle is inherited as self._handle - def __init__(self, cameraIdString): - - # call super constructor - super(VimbaCamera, self).__init__() - - # set ID - self._cameraIdString = cameraIdString.encode() - - # set own info - self._info = self._getInfo() - - def getInfo(self): - """ - Get info of the camera. Does not require - the camera to be opened. - - :returns: VimbaCameraInfo object -- camera information. - """ - return self._info - - def _getInfo(self): - """ - Get info of the camera. Does not require - the camera to be opened. - - :returns: VimbaCameraInfo object -- camera information. - """ - # args for Vimba call - cameraInfo = structs.VimbaCameraInfo() - - # Vimba DLL will return an error code - errorCode = VimbaDLL.cameraInfoQuery(self._cameraIdString, - byref(cameraInfo), - sizeof(cameraInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - - return cameraInfo - - def openCamera(self, cameraAccessMode=1): - """ - Open the camera with requested access mode - Available access modes: - 0 : VmbAccessModeNone - 1 : VmbAccessModeFull - 2 : VmbAccessModeRead - 3 : VmbAccessModeConfig - 4 : VmbAccessModeLite - """ - # args for Vimba call - errorCode = VimbaDLL.cameraOpen(self._cameraIdString, - cameraAccessMode, - byref(self._handle)) - if errorCode != 0: - raise VimbaException(errorCode) - - def closeCamera(self): - """ - Close the camera. - """ - errorCode = VimbaDLL.cameraClose(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) - - def revokeAllFrames(self): - """ - Revoke all frames assigned to the camera. - """ - errorCode = VimbaDLL.frameRevokeAll(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) - - def startCapture(self): - """ - Prepare the API for incoming frames. - """ - errorCode = VimbaDLL.captureStart(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) - - def endCapture(self): - """ - Stop the API from being able to receive frames. - """ - errorCode = VimbaDLL.captureEnd(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) - - def flushCaptureQueue(self): - """ - Flush the capture queue. - """ - errorCode = VimbaDLL.captureQueueFlush(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) - - # method for easy frame creation - def getFrame(self): - """ - Creates and returns a new frame object. Multiple frames - per camera can therefore be returned. - - :returns: VimbaFrame object -- the new frame. - """ - return VimbaFrame(self) diff --git a/pymba/vimba_dll.py b/pymba/vimba_dll.py deleted file mode 100644 index a62b087..0000000 --- a/pymba/vimba_dll.py +++ /dev/null @@ -1,489 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import - -from sys import platform as sys_plat -import platform -import os -from ctypes import * - -from . import vimba_structure as structs -from .vimba_exception import VimbaException - -if sys_plat == "win32": - - def find_win_dll(arch): - """ Finds the highest versioned windows dll for the specified architecture. """ - bases = [ - r'C:\Program Files\Allied Vision Technologies\AVTVimba_%i.%i\VimbaC\Bin\Win%i\VimbaC.dll', - r'C:\Program Files\Allied Vision\Vimba_%i.%i\VimbaC\Bin\Win%i\VimbaC.dll' - ] - dlls = [] - for base in bases: - for major in range(3): - for minor in range(10): - candidate = base % (major, minor, arch) - if os.path.isfile(candidate): - dlls.append(candidate) - if not dlls: - if 'VIMBA_HOME' in os.environ: - candidate = os.environ ['VIMBA_HOME'] + '\VimbaC\Bin\Win%i\VimbaC.dll' % (arch) - if os.path.isfile(candidate): - dlls.append(candidate) - if not dlls: - raise IOError("VimbaC.dll not found.") - return dlls[-1] - - if '64' in platform.architecture()[0]: - vimbaC_path = find_win_dll(64) - else: - vimbaC_path = find_win_dll(32) - dll_loader = windll -else: - - dll_loader = cdll - - if 'x86_64' in os.uname()[4]: - assert os.environ.get( - "GENICAM_GENTL64_PATH"), "you need your GENICAM_GENTL64_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" - tlPath = [p for p in os.environ.get("GENICAM_GENTL64_PATH").split(":") if p][0] - vimba_dir = "/".join(tlPath.split("/")[1:-3]) - vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/x86_64bit/libVimbaC.so" - elif 'x86_32' in os.uname()[4]: - print("Warning: x86_32 reached!") - assert os.environ.get( - "GENICAM_GENTL32_PATH"), "you need your GENICAM_GENTL32_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" - tlPath = [p for p in os.environ.get("GENICAM_GENTL32_PATH").split(":") if p][0] - vimba_dir = "/".join(tlPath.split("/")[1:-3]) - vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/x86_32bit/libVimbaC.so" - elif 'arm' in os.uname()[4]: - assert os.environ.get( - "GENICAM_GENTL32_PATH"), "you need your GENICAM_GENTL32_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" - tlPath = [p for p in os.environ.get("GENICAM_GENTL32_PATH").split(":") if p][0] - vimba_dir = "/".join(tlPath.split("/")[1:-3]) - vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/arm_32bit/libVimbaC.so" - elif 'aarch64' in os.uname()[4]: - assert os.environ.get( - "GENICAM_GENTL64_PATH"), "you need your GENICAM_GENTL64_PATH environment set. Make sure you have Vimba installed, and you have loaded the /etc/profile.d/ scripts" - tlPath = [p for p in os.environ.get("GENICAM_GENTL64_PATH").split(":") if p][0] - vimba_dir = "/".join(tlPath.split("/")[1:-3]) - vimbaC_path = "/" + vimba_dir + "/VimbaC/DynamicLib/arm_64bit/libVimbaC.so" - else: - raise ValueError("Pymba currently doesn't support %s" % os.uname()[4]) - - -# Callback Function Type -if sys_plat == "win32": - CB_FUNCTYPE = WINFUNCTYPE -else: - # Untested! - CB_FUNCTYPE = CFUNCTYPE - - -class VimbaDLL(object): - - """ - ctypes directives to make the wrapper class work cleanly, - talks to VimbaC.dll - """ - # a full list of Vimba API methods - # (only double dashed methods have been implemented so far) - # - # -- VmbVersionQuery() - # - # -- VmbStartup() - # -- VmbShutdown() - # - # -- VmbCamerasList() - # -- VmbCameraInfoQuery() - # -- VmbCameraOpen() - # -- VmbCameraClose() - # - # -- VmbFeaturesList() - # -- VmbFeatureInfoQuery() - # VmbFeatureListAffected() - # VmbFeatureListSelected() - # VmbFeatureAccessQuery() - # - # -- VmbFeatureIntGet() - # -- VmbFeatureIntSet() - # -- VmbFeatureIntRangeQuery() - # VmbFeatureIntIncrementQuery() - # - # -- VmbFeatureFloatGet() - # -- VmbFeatureFloatSet() - # -- VmbFeatureFloatRangeQuery() - # - # -- VmbFeatureEnumGet() - # -- VmbFeatureEnumSet() - # -- VmbFeatureEnumRangeQuery() - # VmbFeatureEnumIsAvailable() - # VmbFeatureEnumAsInt() - # VmbFeatureEnumAsString() - # VmbFeatureEnumEntryGet() - # - # -- VmbFeatureStringGet() - # -- VmbFeatureStringSet() - # VmbFeatureStringMaxlengthQuery() - # - # -- VmbFeatureBoolGet() - # -- VmbFeatureBoolSet() - # - # -- VmbFeatureCommandRun() - # VmbFeatureCommandIsDone() - # - # VmbFeatureRawGet() - # VmbFeatureRawSet() - # VmbFeatureRawLengthQuery() - # - # VmbFeatureInvalidationRegister() - # VmbFeatureInvalidationUnregister() - # - # -- VmbFrameAnnounce() - # -- VmbFrameRevoke() - # -- VmbFrameRevokeAll() - # -- VmbCaptureStart() - # -- VmbCaptureEnd() - # -- VmbCaptureFrameQueue() - # -- VmbCaptureFrameWait() - # -- VmbCaptureQueueFlush() - # - # -- VmbInterfacesList() - # -- VmbInterfaceOpen() - # -- VmbInterfaceClose() - # - # VmbAncillaryDataOpen() - # VmbAncillaryDataClose() - # - # VmbMemoryRead() - # VmbMemoryWrite() - # -- VmbRegistersRead() - # -- VmbRegistersWrite() - - # Vimba C API DLL - _vimbaDLL = dll_loader.LoadLibrary(vimbaC_path) - - # version query - versionQuery = _vimbaDLL.VmbVersionQuery - # returned error code - versionQuery.restype = c_int32 - versionQuery.argtypes = (POINTER(structs.VimbaVersion), # pointer to version structure - c_uint32) # version structure size - - # startup - startup = _vimbaDLL.VmbStartup - # returned error code - startup.restype = c_int32 - - # shutdown - shutdown = _vimbaDLL.VmbShutdown - - # list cameras - camerasList = _vimbaDLL.VmbCamerasList - # returned error code - camerasList.restype = c_int32 - camerasList.argtypes = (POINTER(structs.VimbaCameraInfo), # pointer to camera info structure - # length of list - c_uint32, - # pointer to number of cameras - POINTER(c_uint32), - c_uint32) # camera info structure size - - # camera info query - cameraInfoQuery = _vimbaDLL.VmbCameraInfoQuery - cameraInfoQuery.restype = c_int32 - cameraInfoQuery.argtypes = (c_char_p, # camera unique id - # pointer to camera info structure - POINTER(structs.VimbaCameraInfo), - c_uint32) # size of structure - - # camera open - cameraOpen = _vimbaDLL.VmbCameraOpen - # returned error code - cameraOpen.restype = c_int32 - cameraOpen.argtypes = (c_char_p, # camera unique id - # access mode - c_uint32, - c_void_p) # camera handle, pointer to a pointer - - # camera close - cameraClose = _vimbaDLL.VmbCameraClose - # returned error code - cameraClose.restype = c_int32 - # camera handle - cameraClose.argtypes = (c_void_p,) - - # list features - featuresList = _vimbaDLL.VmbFeaturesList - featuresList.restype = c_int32 - featuresList.argtypes = (c_void_p, # handle, in this case camera handle - # pointer to feature info structure - POINTER(structs.VimbaFeatureInfo), - # list length - c_uint32, - # pointer to num features found - POINTER(c_uint32), - c_uint32) # feature info size - - # feature info query - featureInfoQuery = _vimbaDLL.VmbFeatureInfoQuery - featureInfoQuery.restype = c_int32 - featureInfoQuery.argtypes = (c_void_p, # handle, in this case camera handle - # name of feature - c_char_p, - # pointer to feature info structure - POINTER(structs.VimbaFeatureInfo), - c_uint32) # size of structure - - # get the int value of a feature - featureIntGet = _vimbaDLL.VmbFeatureIntGet - featureIntGet.restype = c_int32 - featureIntGet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - POINTER(c_int64)) # value to get - - # set the int value of a feature - featureIntSet = _vimbaDLL.VmbFeatureIntSet - featureIntSet.restype = c_int32 - featureIntSet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - c_int64) # value to set # get the value of an integer feature - - # query the range of values of the feature - featureIntRangeQuery = _vimbaDLL.VmbFeatureIntRangeQuery - featureIntRangeQuery.restype = c_int32 - featureIntRangeQuery.argtypes = (c_void_p, # handle - # name of the feature - c_char_p, - # min range - POINTER(c_int64), - POINTER(c_int64)) # max range - - # get the float value of a feature - featureFloatGet = _vimbaDLL.VmbFeatureFloatGet - featureFloatGet.restype = c_int32 - featureFloatGet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - POINTER(c_double)) # value to get - - # set the float value of a feature - featureFloatSet = _vimbaDLL.VmbFeatureFloatSet - featureFloatSet.restype = c_int32 - featureFloatSet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - c_double) # value to set - - # query the range of values of the feature - featureFloatRangeQuery = _vimbaDLL.VmbFeatureFloatRangeQuery - featureFloatRangeQuery.restype = c_int32 - featureFloatRangeQuery.argtypes = (c_void_p, # handle - # name of the feature - c_char_p, - # min range - POINTER(c_double), - POINTER(c_double)) # max range - - # get the enum value of a feature - featureEnumGet = _vimbaDLL.VmbFeatureEnumGet - featureEnumGet.restype = c_int32 - featureEnumGet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - POINTER(c_char_p)) # value to get - - # set the enum value of a feature - featureEnumSet = _vimbaDLL.VmbFeatureEnumSet - featureEnumSet.restype = c_int32 - featureEnumSet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - c_char_p) # value to set - - # query the range of values of the feature - featureEnumRangeQuery = _vimbaDLL.VmbFeatureEnumRangeQuery - featureEnumRangeQuery.restype = c_int32 - featureEnumRangeQuery.argtypes = (c_void_p, # handle - # name of the feature - c_char_p, - # pointer to enum names (array) - POINTER(c_char_p), - # array length - c_uint32, - # pointer to num enum names found - POINTER(c_uint32)) - - # get the string value of a feature - featureStringGet = _vimbaDLL.VmbFeatureStringGet - featureStringGet.restype = c_int32 - featureStringGet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - # string buffer to fill - c_char_p, - # size of the input buffer - c_uint32, - POINTER(c_uint32)) # string buffer to fill - - # set the string value of a feature - featureStringSet = _vimbaDLL.VmbFeatureStringSet - featureStringSet.restype = c_int32 - featureStringSet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - c_char_p) # value to set - - # get the boolean value of a feature - featureBoolGet = _vimbaDLL.VmbFeatureBoolGet - featureBoolGet.restype = c_int32 - featureBoolGet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - POINTER(c_bool)) # value to get - - # set the boolean value of a feature - featureBoolSet = _vimbaDLL.VmbFeatureBoolSet - featureBoolSet.restype = c_int32 - featureBoolSet.argtypes = (c_void_p, # handle, in this case camera handle - # name of the feature - c_char_p, - c_bool) # value to set - - # run a feature command - featureCommandRun = _vimbaDLL.VmbFeatureCommandRun - featureCommandRun.restype = c_int32 - featureCommandRun.argtypes = (c_void_p, # handle for a module that exposes features - c_char_p) # name of the command feature - - # Check if a feature command is done - featureCommandIsDone = _vimbaDLL.VmbFeatureCommandIsDone - featureCommandIsDone.restype = c_int32 - featureCommandIsDone.argtypes = (c_void_p, # handle - c_char_p, # name of the command feature - POINTER(c_bool)) # pointer to a result bool - - # announce frames to the API that may be queued for frame capturing later - frameAnnounce = _vimbaDLL.VmbFrameAnnounce - frameAnnounce.restype = c_int32 - frameAnnounce.argtypes = (c_void_p, # camera handle - # pointer to frame - POINTER(structs.VimbaFrame), - c_uint32) # size of frame - - # callback for frame queue - frameDoneCallback = CB_FUNCTYPE(c_void_p, # Return Type - c_void_p, # Camera Hanlde - POINTER(structs.VimbaFrame)) # Pointer to frame - - # revoke a frame from the API - frameRevoke = _vimbaDLL.VmbFrameRevoke - frameRevoke.restype = c_int32 - frameRevoke.argtypes = (c_void_p, # camera handle - POINTER(structs.VimbaFrame)) # pointer to frame - - # revoke all frames assigned to a certain camera - frameRevokeAll = _vimbaDLL.VmbFrameRevokeAll - frameRevokeAll.restype = c_int32 - # camera handle - frameRevokeAll.argtypes = (c_void_p,) - - # prepare the API for incoming frames - captureStart = _vimbaDLL.VmbCaptureStart - captureStart.restype = c_int32 - # camera handle - captureStart.argtypes = (c_void_p,) - - # stop the API from being able to receive frames - captureEnd = _vimbaDLL.VmbCaptureEnd - captureEnd.restype = c_int32 - # camera handle - captureEnd.argtypes = (c_void_p,) - - # queue frames that may be filled during frame capturing - captureFrameQueue = _vimbaDLL.VmbCaptureFrameQueue - captureFrameQueue.restype = c_int32 - captureFrameQueue.argtypes = (c_void_p, - POINTER(structs.VimbaFrame), - c_void_p) # callback - - # wait for a queued frame to be filled (or dequeued) - captureFrameWait = _vimbaDLL.VmbCaptureFrameWait - captureFrameWait.restype = c_int32 - captureFrameWait.argtypes = (c_void_p, # camera handle - POINTER(structs.VimbaFrame), - c_uint32) # timeout - - # flush the capture queue - captureQueueFlush = _vimbaDLL.VmbCaptureQueueFlush - captureQueueFlush.restype = c_int32 - # camera handle - captureQueueFlush.argtypes = (c_void_p,) - - # list interfaces - interfacesList = _vimbaDLL.VmbInterfacesList - interfacesList.restype = c_int32 - interfacesList.argtypes = (POINTER(structs.VimbaInterfaceInfo), # pointer to interface info structure - # length of list - c_uint32, - # pointer to number of interfaces - POINTER(c_uint32), - c_uint32) - - # open interface - interfaceOpen = _vimbaDLL.VmbInterfaceOpen - interfaceOpen.restype = c_int32 - interfaceOpen.argtypes = (c_char_p, # unique id - c_void_p) # handle - - # close interface - interfaceClose = _vimbaDLL.VmbInterfaceClose - interfaceClose.restype = c_int32 - interfaceClose.argtypes = (c_void_p,) # handle - - # read from register - registersRead = _vimbaDLL.VmbRegistersRead - registersRead.restype = c_int32 - registersRead.argtypes = (c_void_p, # handle - # read count - c_uint32, - # pointer to address array - POINTER(c_uint64), - # pointer to data array - POINTER(c_uint64), - POINTER(c_uint32)) # pointer to num complete reads - - # write to register - registersWrite = _vimbaDLL.VmbRegistersWrite - registersWrite.restype = c_int32 - registersWrite.argtypes = (c_void_p, # handle - # write count - c_uint32, - # pointer to address array - POINTER(c_uint64), - # pointer to data array - POINTER(c_uint64), - POINTER(c_uint32)) # pointer to num complete write - - -class VimbaC_MemoryBlock(object): - - """ - Just a memory block object for dealing - neatly with C memory allocations. - """ - - @property - def block(self): - return c_void_p(addressof(self._block)) - - def __init__(self, blockSize): - self._block = create_string_buffer(blockSize) - - # this seems to be None if too much memory is requested - if self._block is None: - raise VimbaException(-51) - - def __del__(self): - del self._block diff --git a/pymba/vimba_exception.py b/pymba/vimba_exception.py index ac6abee..22f03c2 100644 --- a/pymba/vimba_exception.py +++ b/pymba/vimba_exception.py @@ -1,58 +1,71 @@ class VimbaException(Exception): + ERROR_CODES = ( + # 0 + ERR_NO_ERROR, - """ - An exception for the AVT Vimba API. It contains a message - property which is a string indicating what went wrong. + # -1 to -19 + ERR_UNEXPECTED_FAULT, + ERR_STARTUP_NOT_CALLED, + ERR_INSTANCE_NOT_FOUND, + ERR_HANDLE_INVALID, + ERR_DEVICE_NOT_OPENED, + ERR_OPERATION_INVALID_FOR_ACCESS_MODE, + ERR_PARAMETER_INVALID, + ERR_STRUCT_SIZE_INVALID, + ERR_DATA_TOO_LARGE, + ERR_FEATURE_TYPE_WRONG, + ERR_VALUE_INVALID, + ERR_TIMEOUT, + ERR_OTHER_ERROR, + ERR_RESOURCE_NOT_AVAILABLE, + ERR_CALL_INVALID, + ERR_TRANSPORT_LAYER_NOT_FOUND, + ERR_FEATURE_NOT_IMPLEMENTED, + ERR_FEATURE_NOT_SUPPORTED, + ERR_PARTIAL_REGISTER_ACCESS, - :param errorCode: Error code to be used to look up error message. - """ + # -50 to -56 + ERR_FRAME_BUFFER_MEMORY, + ERR_NOT_IMPLEMENTED_IN_PYMBA, + ERR_UNDEFINED_ERROR_CODE, + ) = tuple(range(0, -20, -1)) + tuple(range(-50, -53, -1)) - @property - def message(self): - return self._errorCodes[self.errorCode] - - @property - def errorCode(self): - return self._errorCode - - _errorCodes = { # Vimba C API specific errors - 0: 'No error.', - -1: 'Unexpected fault in VimbaC or driver.', - -2: 'VmbStartup() was not called before the current command.', - -3: 'The designated instance (camera, feature etc.) cannot be found.', - -4: 'The given handle is not valid, ensure device open.', - -5: 'Device was not opened for usage.', - -6: 'Operation is invalid with the current access mode.', - -7: 'One of the parameters was invalid (usually an illegal pointer).', - -8: 'The given struct size is not valid for this version of the API.', - -9: 'More data was returned in a string/list than space was provided.', - -10: 'The feature type for this access function was wrong.', - -11: 'The value was not valid; either out of bounds or not an increment of the minimum.', - -12: 'Timeout during wait.', - -13: 'Other error.', - -14: 'Resources not available (e.g. memory).', - -15: 'Call is invalid in the current context (e.g. callback).', - -16: 'No transport layers were found.', - -17: 'API feature is not implemented.', - -18: 'API feature is not supported.', - -19: 'A multiple registers read or write was partially completed.', + ERRORS = { + # Vimba C API specific errors + ERR_NO_ERROR: 'No error.', + ERR_UNEXPECTED_FAULT: 'Unexpected fault in VimbaC or driver.', + ERR_STARTUP_NOT_CALLED: 'VmbStartup() was not called before the current command.', + ERR_INSTANCE_NOT_FOUND: 'The designated instance (camera, feature etc.) cannot be found.', + ERR_HANDLE_INVALID: 'The given handle is not valid, ensure device open.', + ERR_DEVICE_NOT_OPENED: 'Device was not opened for usage.', + ERR_OPERATION_INVALID_FOR_ACCESS_MODE: 'Operation is invalid with the current access mode.', + ERR_PARAMETER_INVALID: 'One of the parameters was invalid (usually an illegal pointer).', + ERR_STRUCT_SIZE_INVALID: 'The given struct size is not valid for this version of the API.', + ERR_DATA_TOO_LARGE: 'More data was returned in a string/list than space was provided.', + ERR_FEATURE_TYPE_WRONG: 'The feature type for this access function was wrong.', + ERR_VALUE_INVALID: 'The value was not valid; either out of bounds or not an increment of the minimum.', + ERR_TIMEOUT: 'Timeout during wait.', + ERR_OTHER_ERROR: 'Other error.', + ERR_RESOURCE_NOT_AVAILABLE: 'Resources not available (e.g. memory).', + ERR_CALL_INVALID: 'Call is invalid in the current context (e.g. callback).', + ERR_TRANSPORT_LAYER_NOT_FOUND: 'No transport layers were found.', + ERR_FEATURE_NOT_IMPLEMENTED: 'API feature is not implemented.', + ERR_FEATURE_NOT_SUPPORTED: 'API feature is not supported.', + ERR_PARTIAL_REGISTER_ACCESS: 'A multiple registers read or write was partially completed.', # Custom errors - -50: 'Could not find the specified camera.', - -51: 'Not enough memory to assign frame buffer.', - -52: 'Invalid input.', - -53: 'Could not find the specified feature.', - -54: 'Could not find the specified interface.', + ERR_FRAME_BUFFER_MEMORY: 'Not enough memory to assign frame buffer.', + ERR_NOT_IMPLEMENTED_IN_PYMBA: 'This function is not yet implemented in Pymba', + ERR_UNDEFINED_ERROR_CODE: 'Undefined error code', + } - # Miscellaneous errors - -1000: 'Oops, unknown internal error code!', - -1001: 'Oops, this VimbaFeature function is not yet implemented in pymba!'} + @property + def message(self): + return self.ERRORS[self.error_code] - def __init__(self, errorCode): - # if error code does not match expected codes then assign invalid code - if errorCode in self._errorCodes: - self._errorCode = errorCode - else: - self._errorCode = -1000 + def __init__(self, error_code: int): + if error_code not in self.ERROR_CODES: + error_code = self.ERR_UNDEFINED_ERROR_CODE + self.error_code = error_code - super(VimbaException, self).__init__(self.message) + super().__init__(self.message) diff --git a/pymba/vimba_feature.py b/pymba/vimba_feature.py deleted file mode 100644 index 3e838f0..0000000 --- a/pymba/vimba_feature.py +++ /dev/null @@ -1,341 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs -from .vimba_exception import VimbaException -from .vimba_dll import VimbaDLL -from ctypes import * - -# class may extend a generic Vimba entity class one day... - - -class VimbaFeature(object): - - """ - A feature of a Vimba object. - """ - - @property - def name(self): - return self._name.decode() - - @property - def handle(self): - return self._handle - - # lookup relevant function for feature type and pass to that function - @property - def value(self): - return self._getSetTypeFuncs[self._info.featureDataType][0]() - - @value.setter - def value(self, val): - self._getSetTypeFuncs[self._info.featureDataType][1](val) - - @property - def range(self): - return self._rangeQueryTypeFuncs[self._info.featureDataType]() - - def __init__(self, name, handle): - - # set name and handle - self._name = name.encode() - self._handle = handle - - # set own info - self._info = self._getInfo() - - # type functions dict for looking up correct get/set function to use - self._getSetTypeFuncs = {0: (self._notYetImplemented, self._notYetImplemented), # todo - 1: (self._getIntFeature, self._setIntFeature), - 2: (self._getFloatFeature, self._setFloatFeature), - 3: (self._getEnumFeature, self._setEnumFeature), - 4: (self._getStringFeature, self._setStringFeature), - 5: (self._getBoolFeature, self._setBoolFeature), - # todo - 6: (self._notYetImplemented, self._notYetImplemented), - # todo - 7: (self._notYetImplemented, self._notYetImplemented), - 8: (self._notYetImplemented, self._notYetImplemented)} # todo - - # type functions dict for looking up correct range function to use - self._rangeQueryTypeFuncs = {0: self._unknownRange, - 1: self._rangeQueryIntFeature, - 2: self._rangeQueryFloatFeature, - 3: self._rangeQueryEnumFeature, - 4: self._unknownRange, - 5: self._unknownRange, - 6: self._unknownRange, - 7: self._unknownRange, - 8: self._unknownRange} - - def getInfo(self): - """ - Get info of the feature. - - :returns: VimbaFeatureInfo object -- feature information.. - """ - return self._info - - def _getInfo(self): - """ - Get info of the feature. - - :returns: VimbaFeatureInfo object -- feature information.. - """ - # args for Vimba call - featureInfo = structs.VimbaFeatureInfo() - - # Vimba DLL will return an error code - errorCode = VimbaDLL.featureInfoQuery(self._handle, - self._name, - byref(featureInfo), - sizeof(featureInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - - return featureInfo - - def _notYetImplemented(self, val=None): - """ - Raises exception if feature value type is not yet defined. - """ - raise VimbaException(-1001) - - def _getIntFeature(self): - """ - Get the value of an integer feature. - - :returns: int -- value of the specified feature. - """ - - # create args - valueToGet = c_int64() - - errorCode = VimbaDLL.featureIntGet(self._handle, - self._name, - byref(valueToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return valueToGet.value - - def _setIntFeature(self, valueToSet): - """ - Set the value of an integer feature. - - :param valueToSet: the int value to set for the feature. - """ - - errorCode = VimbaDLL.featureIntSet(self._handle, - self._name, - valueToSet) - if errorCode != 0: - raise VimbaException(errorCode) - - def _getFloatFeature(self): - """ - Get the value of a float feature. - - :returns: float -- value of the specified feature. - """ - - # create args - valueToGet = c_double() - - errorCode = VimbaDLL.featureFloatGet(self._handle, - self._name, - byref(valueToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return valueToGet.value - - def _setFloatFeature(self, valueToSet): - """ - Set the value of a float feature. - - :param valueToSet: the float value to set for the feature. - """ - - errorCode = VimbaDLL.featureFloatSet(self._handle, - self._name, - valueToSet) - if errorCode != 0: - raise VimbaException(errorCode) - - def _getEnumFeature(self): - """ - Get the value of an enum feature. - - :returns: enum -- value of the specified feature. - """ - - # create args - valueToGet = c_char_p() - - errorCode = VimbaDLL.featureEnumGet(self._handle, - self._name, - byref(valueToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return valueToGet.value.decode() - - def _setEnumFeature(self, valueToSet): - """ - Set the value of an enum feature. - - :param valueToSet: the enum value to set for the feature. - """ - - errorCode = VimbaDLL.featureEnumSet(self._handle, - self._name, - valueToSet.encode()) - if errorCode != 0: - raise VimbaException(errorCode) - - def _getStringFeature(self): - """ - Get the value of a string feature. - - :returns: string -- value of the specified feature. - """ - - # create args - bufferSize = 256 - valueToGet = create_string_buffer('\000' * bufferSize) - sizeFilled = c_uint32() - - errorCode = VimbaDLL.featureStringGet(self._handle, - self._name, - valueToGet, - bufferSize, - byref(sizeFilled)) - if errorCode != 0: - raise VimbaException(errorCode) - return valueToGet.value.decode() - - def _setStringFeature(self, valueToSet): - """ - Set the value of a string feature. - - :param valueToSet: the string value to set for the feature. - """ - - errorCode = VimbaDLL.featureStringSet(self._handle, - self._name, - valueToSet.encode()) - if errorCode != 0: - raise VimbaException(errorCode) - - def _getBoolFeature(self): - """ - Get the value of a bool feature. - - :returns: bool -- value of the specified feature. - """ - - # create args - valueToGet = c_bool() - - errorCode = VimbaDLL.featureBoolGet(self._handle, - self._name, - byref(valueToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return valueToGet.value - - def _setBoolFeature(self, valueToSet): - """ - Set the value of a bool feature. - - :param valueToSet: the bool value to set for the feature. - """ - - errorCode = VimbaDLL.featureBoolSet(self._handle, - self._name, - valueToSet) - if errorCode != 0: - raise VimbaException(errorCode) - - def _unknownRange(self): - """ - Returns empty for ranges that have not been implemented. - """ - return '' - - def _rangeQueryIntFeature(self): - """ - Get the range of an int feature. - - :returns: tuple -- min and max range. - """ - - # create args - minToGet = c_int64() - maxToGet = c_int64() - - errorCode = VimbaDLL.featureIntRangeQuery(self._handle, - self._name, - byref(minToGet), - byref(maxToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return int(str(minToGet.value)), int(str(maxToGet.value)) - - def _rangeQueryFloatFeature(self): - """ - Get the range of a float feature. - - :returns: tuple -- min and max range. - """ - - # create args - minToGet = c_double() - maxToGet = c_double() - - errorCode = VimbaDLL.featureFloatRangeQuery(self._handle, - self._name, - byref(minToGet), - byref(maxToGet)) - if errorCode != 0: - raise VimbaException(errorCode) - - return (minToGet.value, maxToGet.value) - - def _rangeQueryEnumFeature(self): - """ - Get the range of an enum feature. - :returns: list -- enum names for the given feature. - """ - - # call once to get number of available enum names - # Vimba DLL will return an error code - numFound = c_uint32(-1) - errorCode = VimbaDLL.featureEnumRangeQuery(self._handle, - self._name, - None, - 0, - byref(numFound)) - if errorCode != 0: - raise VimbaException(errorCode) - - # number of names specified by Vimba - numEnumNames = numFound.value - - # args - enumNamesArray = (c_char_p * numEnumNames)() - - # call again to get the enum names - # Vimba DLL will return an error code - errorCode = VimbaDLL.featureEnumRangeQuery(self._handle, - self._name, - enumNamesArray, - numEnumNames, - byref(numFound)) - if errorCode != 0: - raise VimbaException(errorCode) - - return list(enumName.decode() for enumName in enumNamesArray) diff --git a/pymba/vimba_frame.py b/pymba/vimba_frame.py deleted file mode 100644 index 8cf0c86..0000000 --- a/pymba/vimba_frame.py +++ /dev/null @@ -1,180 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs -from .vimba_exception import VimbaException -from .vimba_dll import VimbaDLL -from .vimba_dll import VimbaC_MemoryBlock -from ctypes import * -import warnings -try: - import numpy as np -except ImportError: - warnings.warn('numpy not found, some VimbaFrame methods will not be available') - - -""" -Map pixel formats to bytes per pixel. - The packed formats marked with "?" have not been tested. -""" -PIXEL_FORMATS = { - "Mono8": 1, - "Mono12": 2, - "Mono12Packed": 1.5, # ? - "Mono14": 2, - "Mono16": 2, - "RGB8": 3, - "RGB8Packed": 3, - "BGR8Packed": 3, - "RGBA8Packed": 4, - "BGRA8Packed": 4, - "YUV411Packed": 4/3.0, # ? - "YUV422Packed": 2, - "YUV444Packed": 3, - "BayerRG8": 1, - "BayerRG12": 2, - "BayerGR8": 1, - "BayerGR12": 2, - "BayerGR12Packed": 1.5, # ? -} - - -class VimbaFrame(object): - """ - A Vimba frame. - """ - def __init__(self, camera): - self._camera = camera - self._handle = camera.handle - - # get frame sizes - self.payloadSize = self._camera.PayloadSize - self.width = self._camera.Width - self.height = self._camera.Height - self.pixel_bytes = PIXEL_FORMATS[self._camera.PixelFormat] - - # frame structure - self._frame = structs.VimbaFrame() - - def announceFrame(self): - """ - Announce frames to the API that may be queued for frame capturing later. - - Runs VmbFrameAnnounce - - Should be called after the frame is created. Call startCapture - after this method. - """ - # size of expected frame - sizeOfFrame = self.payloadSize - - # keep this reference to keep block alive for life of frame - self._cMem = VimbaC_MemoryBlock(sizeOfFrame) - # set buffer to have length of expected payload size - self._frame.buffer = self._cMem.block - - # set buffer size to expected payload size - self._frame.bufferSize = sizeOfFrame - - errorCode = VimbaDLL.frameAnnounce(self._handle, - byref(self._frame), - sizeof(self._frame)) - - if errorCode != 0: - raise VimbaException(errorCode) - - def revokeFrame(self): - """ - Revoke a frame from the API. - """ - errorCode = VimbaDLL.frameRevoke(self._handle, - byref(self._frame)) - - if errorCode != 0: - raise VimbaException(errorCode) - - def queueFrameCapture(self, frameCallback = None): - """ - Queue frames that may be filled during frame capturing. - Runs VmbCaptureFrameQueue - - Call after announceFrame and startCapture - - Callback must accept argument of type frame. Remember to requeue the - frame by calling frame.queueFrameCapture(frameCallback) at the end of - your callback function. - """ - # remember the given callback function - self._frameCallback = frameCallback - - # define a callback wrapper here so it doesn't bind self - def frameCallbackWrapper(cam_handle, p_frame): - # call the user's callback with the self bound outside the wrapper - # ignore the frame pointer since we already know the callback - # refers to this frame - self._frameCallback(self) - - if self._frameCallback is None: - self._frameCallbackWrapper_C = None - else: - # keep a reference to prevent gc issues - self._frameCallbackWrapper_C = VimbaDLL.frameDoneCallback(frameCallbackWrapper) - - errorCode = VimbaDLL.captureFrameQueue(self._handle, - byref(self._frame), - self._frameCallbackWrapper_C) - if errorCode != 0: - raise VimbaException(errorCode) - - def waitFrameCapture(self, timeout=2000): - """ - Wait for a queued frame to be filled (or dequeued). Returns Errorcode - upon completion. - Runs VmbCaptureFrameWait - - timeout - int, milliseconds default(timeout, 2000) - - Call after an acquisition command - """ - errorCode = VimbaDLL.captureFrameWait(self._handle, - byref(self._frame), - timeout) - - # errorCode to be processed by the end user for this function. - # Prevents system for breaking for example on a hardware trigger - # timeout - #if errorCode != 0: - #raise VimbaException(errorCode) - return errorCode - - # custom method for simplified usage - def getBufferByteData(self): - """ - Retrieve buffer data in a useful format. - - :returns: array -- buffer data. - """ - - # cast frame buffer memory contents to a usable type - data = cast(self._frame.buffer, - POINTER(c_ubyte * self.payloadSize)) - - # make array of c_ubytes from buffer - imagebytes = int(self.height * self.width * self.pixel_bytes) - array = (c_ubyte * imagebytes).from_address(addressof(data.contents)) - - return array - - def getImage(self): - cframe = self._frame - data = cast(cframe.buffer, POINTER(c_ubyte * cframe.imageSize)) - try: - return np.ndarray(buffer=data.contents, dtype=np.uint8, shape=(cframe.height, cframe.width)) - except NameError as e: - print('install numpy to use this method or use getBufferByteData instead') - raise e - - def getTimestamp(self): - return self._frame.timestamp - - def getReceiveStatus(self): - return self._frame.receiveStatus diff --git a/pymba/vimba_interface.py b/pymba/vimba_interface.py deleted file mode 100644 index df5acdc..0000000 --- a/pymba/vimba_interface.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs -from .vimba_object import VimbaObject -from .vimba_exception import VimbaException -from .vimba_dll import VimbaDLL -from ctypes import * - -# interface features are automatically readable as object attributes. - - -class VimbaInterface(VimbaObject): - - """ - A Vimba interface object. This class provides the minimal access - to Vimba functions required to control the interface. - """ - - @property - def interfaceIdString(self): - return self._interfaceIdString - - # own handle is inherited as self._handle - def __init__(self, interfaceIdString): - - # call super constructor - super(VimbaInterface, self).__init__() - - # set ID - self._interfaceIdString = interfaceIdString - - def openInterface(self): - """ - Open the interface. - """ - errorCode = VimbaDLL.interfaceOpen(self._interfaceIdString, - byref(self._handle)) - if errorCode != 0: - raise VimbaException(errorCode) - - def closeInterface(self): - """ - Close the interface. - """ - errorCode = VimbaDLL.interfaceClose(self._handle) - if errorCode != 0: - raise VimbaException(errorCode) diff --git a/pymba/vimba_object.py b/pymba/vimba_object.py index 5f1cead..174fe9a 100644 --- a/pymba/vimba_object.py +++ b/pymba/vimba_object.py @@ -1,228 +1,162 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from . import vimba_structure as structs +from ctypes import byref, sizeof, c_void_p, c_uint32, c_uint64, c_bool +from typing import List, Optional + from .vimba_exception import VimbaException -from .vimba_feature import VimbaFeature -from .vimba_dll import VimbaDLL -from ctypes import * +from .feature import Feature +from . import vimba_c -class VimbaObject(object): +class VimbaObject: """ - A Vimba object has a handle and features associated with it. - Objects include System, Camera, Interface and AncillaryData. + A Vimba object has a handle and features associated with it. Objects include System, Camera, Interface and + AncillaryData. Features are automatically readable as instance attributes. """ - @property - def handle(self): - return self._handle - - def __init__(self): - # create own handle - self._handle = c_void_p() - - # list of VimbaFeatureInfo objects can't set yet as the object (e.g. a camera) won't be opened yet, therefore - # no event for object opening so will have it populate by user interaction and blame them if the object is not - # opened then - self._featureInfos = None - - # override getattr for undefined attributes - def __getattr__(self, attr): - # if a feature value requested (requires object (camera) open) - if attr in self.getFeatureNames(): - return VimbaFeature(attr, self._handle).value - - # otherwise don't know about it - raise AttributeError(''.join(["'VimbaObject' has no attribute '", attr, "'"])) - - # override setattr for undefined attributes - def __setattr__(self, attr, val): - - # set privates as normal - # check this first to allow all privates to set normally - # and avoid recursion errors - if attr.startswith('_'): - super(VimbaObject, self).__setattr__(attr, val) - - # if it's an actual camera feature (requires camera open) - elif attr in self.getFeatureNames(): - VimbaFeature(attr, self._handle).value = val - - # otherwise just set the attribute value as normal - else: - super(VimbaObject, self).__setattr__(attr, val) - def _getFeatureInfos(self): - """ - Gets feature info of all available features. Will - cause error if object/camera is not opened. + VMB_ACCESS_MODE_NONE = 0 + VMB_ACCESS_MODE_FULL = 1 + VMB_ACCESS_MODE_READ = 2 + VMB_ACCESS_MODE_CONFIG = 4 + VMB_ACCESS_MODE_LITE = 8 - :returns: list -- feature info for available features. - """ - # check it's populated as can't populate it in __init__ - if self._featureInfos is None: - # args - dummyFeatureInfo = structs.VimbaFeatureInfo() - numFound = c_uint32(-1) - - # call once to get number of available features - # Vimba DLL will return an error code - errorCode = VimbaDLL.featuresList(self._handle, - None, - 0, - byref(numFound), - sizeof(dummyFeatureInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - - # number of features specified by Vimba - numFeatures = numFound.value - - # args - featureInfoArray = (structs.VimbaFeatureInfo * numFeatures)() - - # call again to get the features - # Vimba DLL will return an error code - errorCode = VimbaDLL.featuresList(self._handle, - featureInfoArray, - numFeatures, - byref(numFound), - sizeof(dummyFeatureInfo)) - if errorCode != 0: - raise VimbaException(errorCode) - - self._featureInfos = list( - featInfo for featInfo in featureInfoArray) - return self._featureInfos - - def getFeatureNames(self): - """ - Get names of all available features. + def __init__(self, handle: Optional[int] = None): + self._handle = c_void_p(handle) + self._features = {} - :returns: list -- feature names for available features. - """ - return list(featInfo.name.decode() for featInfo in self._getFeatureInfos()) + def __getattr__(self, item: str): + # allow direct access to feature values as an attribute + if item in self.feature_names(): + return self.feature(item).value - def getFeatureInfo(self, featureName): - """ - Gets feature info object of specified feature. + raise AttributeError(f'{self.__class__.__name__} object has no attribute {item}') + + # allow direct access to feature values as an attribute + def __setattr__(self, item: str, value): + # set privates as normally to avoid recursion errors + if item.startswith('_'): + super().__setattr__(item, value) - :param featureName: the name of the feature. + # allow direct access to feature values as an attribute + elif item in self.feature_names(): + self.feature(item).value = value + + else: + super().__setattr__(item, value) - :returns: VimbaFeatureInfo object -- the feature info object specified. + def _feature_infos(self) -> List[vimba_c.VmbFeatureInfo]: """ - # don't do this live as we already have this info - # return info object, if it exists - for featInfo in self._getFeatureInfos(): - if featInfo.name.decode() == featureName: - return featInfo - # otherwise raise error - raise VimbaException(-53) - - # don't think we ever need to return a feature object... - # def getFeature(self, featureName): - - def getFeatureRange(self, featureName): + Gets feature info of all available features. Will cause error if object/camera/etc is not opened. + """ + # call once to get number of available features + vmb_feature_info = vimba_c.VmbFeatureInfo() + num_found = c_uint32(-1) + error = vimba_c.vmb_features_list(self._handle, + None, + 0, + byref(num_found), + sizeof(vmb_feature_info)) + if error: + raise VimbaException(error) + + # call again to get the features + num_features = num_found.value + vmb_feature_infos = (vimba_c.VmbFeatureInfo * num_features)() + error = vimba_c.vmb_features_list(self._handle, + vmb_feature_infos, + num_features, + byref(num_found), + sizeof(vmb_feature_info)) + if error: + raise VimbaException(error) + + return list(vmb_feature_info for vmb_feature_info in vmb_feature_infos) + + def _feature_info(self, feature_name: str) -> vimba_c.VmbFeatureInfo: + """ + Gets feature info object of specified feature. + :param feature_name: the name of the feature. """ - Get valid range of feature values. + for vmb_feature_info in self._feature_infos(): + if feature_name == vmb_feature_info.name.decode(): + return vmb_feature_info + raise VimbaException(VimbaException.ERR_INSTANCE_NOT_FOUND) - :param featureName: name of the feature to query. + def feature_names(self) -> List[str]: + """ + Get names of all available features. + """ + return list(vmb_feature_info.name.decode() + for vmb_feature_info in self._feature_infos()) - :returns: tuple -- range as (feature min value, feature max value, for int or float features only). - list -- names of possible enum values (for enum features only). + def feature(self, feature_name: str) -> Feature: + """ + Gets feature object by name from the corresponding Vimba object. + :param feature_name: name of the feature to get. """ - # can't cache this, need to look it up live - return VimbaFeature(featureName, self._handle).range + if feature_name in self._features: + return self._features[feature_name] + feature = Feature(feature_name, self._handle) + self._features[feature_name] = feature + return feature - def runFeatureCommand(self, featureName): + def run_feature_command(self, feature_name: str) -> None: """ Run a feature command. - - :param featureName: the name of the feature. + :param feature_name: the name of the feature. """ - # run a command - errorCode = VimbaDLL.featureCommandRun( - self._handle, - featureName.encode() - ) - if errorCode != 0: - raise VimbaException(errorCode) - - def featureCommandIsDone(self, featureName): - isDone = c_bool() - errorCode = VimbaDLL.featureCommandIsDone( - self._handle, - featureName.encode(), - byref(isDone) - ) - - if errorCode != 0: - raise VimbaException(errorCode) - - return isDone.value - - def readRegister(self, address): - # note that the underlying Vimba function allows reading of an array - # of registers, but only one address/value at a time is implemented - # here + error = vimba_c.vmb_feature_command_run(self._handle, + feature_name.encode()) + if error: + raise VimbaException(error) + + def feature_command_is_done(self, feature_name: str) -> bool: + is_done = c_bool() + error = vimba_c.vmb_feature_command_is_done(self._handle, + feature_name.encode(), + byref(is_done)) + if error: + raise VimbaException(error) + + return is_done.value + + # todo test + def read_register(self, address: int) -> int: + # note that the underlying Vimba function allows reading of an array of registers, but only one address/value + # at a time is implemented here """ - Read from a register of the module (camera). - + Read from a register of the module (camera) and return its value. :param address: the address of the register to read. - - :returns: int -- value of register. """ - readCount = 1 - - # check address validity - try: - regAddress = c_uint64(int(address, 16)) - except: - raise VimbaException(-52) - - regData = c_uint64() - numCompleteReads = c_uint32() - - errorCode = VimbaDLL.registersRead(self.handle, - readCount, - byref(regAddress), - byref(regData), - byref(numCompleteReads)) - - if errorCode != 0: - raise VimbaException(errorCode) - - return regData.value - - def writeRegister(self, address, value): - # note that the underlying Vimba function allows writing of an array - # of registers, but only one address/value at a time is implemented - # here + read_count = 1 + reg_address = c_uint64(address) + reg_data = c_uint64() + num_complete_reads = c_uint32() + error = vimba_c.vmb_registers_read(self._handle, + read_count, + byref(reg_address), + byref(reg_data), + byref(num_complete_reads)) + if error: + raise VimbaException(error) + + return reg_data.value + + # todo test + def write_register(self, address: int, value: int) -> None: + # note that the underlying Vimba function allows writing of an array of registers, but only one address/value + # at a time is implemented here """ - Read from a register of the module (camera). - + Write to a register of the module (camera). :param address: the address of the register to read. :param value: the value to set in hex. """ - writeCount = 1 - - # check address validity - try: - regAddress = c_uint64(int(address, 16)) - except: - raise VimbaException(-52) - - # check value validity - try: - regData = c_uint64(int(value, 16)) - except: - raise VimbaException(-52) - - numCompleteWrites = c_uint32() - - errorCode = VimbaDLL.registersWrite(self.handle, - writeCount, - byref(regAddress), - byref(regData), - byref(numCompleteWrites)) - if errorCode != 0: - raise VimbaException(errorCode) + write_count = 1 + reg_address = c_uint64(address) + reg_data = c_uint64(value) + num_complete_writes = c_uint32() + error = vimba_c.vmb_registers_write(self._handle, + write_count, + byref(reg_address), + byref(reg_data), + byref(num_complete_writes)) + if error: + raise VimbaException(error) diff --git a/pymba/vimba_structure.py b/pymba/vimba_structure.py deleted file mode 100644 index 73c4e96..0000000 --- a/pymba/vimba_structure.py +++ /dev/null @@ -1,106 +0,0 @@ -# -*- coding: utf-8 -*- -from ctypes import * - - -class VimbaVersion(Structure): - _fields_ = [('major', c_uint32), - ('minor', c_uint32), - ('patch', c_uint32)] - - -class VimbaInterfaceInfo(Structure): - _fields_ = [('interfaceIdString', c_char_p), # Unique identifier for each interface - # Interface type, see VmbInterfaceType - ('interfaceType', c_uint32), - # Interface name, given by the transport layer - ('interfaceName', c_char_p), - ('serialString', c_char_p), # Serial number - ('permittedAccess', c_uint32)] # Used access mode, see VmbAccessModeType - - def getFieldNames(self): - """ - Get field names. - """ - return [field[0] for field in self._fields_] - - -class VimbaCameraInfo(Structure): - _fields_ = [('cameraIdString', c_char_p), # Unique identifier for each camera - ('cameraName', c_char_p), # Name of the camera - ('modelName', c_char_p), # Model name - ('serialString', c_char_p), # Serial number - # Used access mode, see VmbAccessModeType - ('permittedAccess', c_uint32), - ('interfaceIdString', c_char_p)] # Unique value for each interface or bus - - def getFieldNames(self): - """ - Get field names. - """ - return [field[0] for field in self._fields_] - - -class VimbaFeatureInfo(Structure): - - _fields_ = [('name', c_char_p), - ('featureDataType', c_uint32), - ('featureFlags', c_uint32), - ('category', c_char_p), - ('displayName', c_char_p), - ('pollingTime', c_uint32), - ('unit', c_char_p), - ('representation', c_char_p), - ('visibility', c_uint32), - ('tooltip', c_char_p), - ('description', c_char_p), - ('sfncNamespace', c_char_p), - ('isStreamable', c_bool), - ('hasAffectedFeatures', c_bool), - ('hasSelectedFeatures', c_bool)] - - def getFieldNames(self): - """ - Get field names. - """ - return [field[0] for field in self._fields_] - - -class VimbaFrame(Structure): - - # IN - _fields_ = [('buffer', c_void_p), # Comprises image and ancillary data - ('bufferSize', c_uint32), # Size of the data buffer - - # User context filled during queuing - ('context', c_void_p * 4), - - # OUT - # Resulting status of the receive operation - ('receiveStatus', c_int32), - # Resulting flags of the receive operation - ('receiveFlags', c_uint32), - - # Size of the image data inside the data buffer - ('imageSize', c_uint32), - # Size of the ancillary data inside the data buffer - ('ancillarySize', c_uint32), - - # Pixel format of the image - ('pixelFormat', c_uint32), - - ('width', c_uint32), # Width of an image - ('height', c_uint32), # Height of an image - # Horizontal offset of an image - ('offsetX', c_uint32), - # Vertical offset of an image - ('offsetY', c_uint32), - - # Unique ID of this frame in this stream - ('frameID', c_uint64), - ('timestamp', c_uint64)] # Timestamp of the data transfer - - def getFieldNames(self): - """ - Get field names. - """ - return [field[0] for field in self._fields_] diff --git a/pymba/vimba_system.py b/pymba/vimba_system.py deleted file mode 100644 index f4d0c54..0000000 --- a/pymba/vimba_system.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import -from .vimba_object import VimbaObject -from ctypes import c_void_p - -# system features are automatically readable as attributes. - - -class VimbaSystem(VimbaObject): - - """ - A Vimba system object. This class provides the minimal access - to Vimba functions required to control the system. - """ - - # own handle is inherited as self._handle - - def __init__(self): - super(VimbaSystem, self).__init__() - - # set own handle manually - self._handle = c_void_p(1) @@ -1,30 +1,49 @@ from setuptools import setup +from pymba import PYMBA_VERSION -setup(name='pymba', - version=0.1, - description="Pymba is a Python wrapper for Allied Vision's Vimba SDK.", - long_description="Pymba is a Python wrapper for Allied Vision's Vimba SDK. It uses the Vimba C API included in " - "the Allied Vision Vimba installation to provide a simple Python interface for Allied Vimba " - "cameras.", + +setup(name='Pymba', + version=PYMBA_VERSION, + description="Pymba is a Python wrapper for Allied Vision's Vimba C API.", + long_description="Pymba is a Python wrapper for Allied Vision's Vimba C API. It wraps the VimbaC library file " + "included in the Vimba installation to provide a simple Python interface for Allied Vision " + "cameras. It currently supports most of the functionality provided by Vimba.", + # https://pypi.org/pypi?%3Aaction=list_classifiers classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', + 'Intended Audience :: End Users/Desktop', + 'Intended Audience :: Healthcare Industry', 'Intended Audience :: Manufacturing', - 'License :: OSI Approved :: GPL-3.0 License', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Natural Language :: English', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Topic :: Multimedia :: Graphics :: Capture :: Digital Camera', - 'Topic :: Multimedia :: Graphics :: Graphics Conversion', + 'Topic :: Multimedia :: Video :: Capture', 'Topic :: Scientific/Engineering :: Image Recognition', - 'Topic :: Software Development :: Libraries :: Python Modules'], - keywords='python, opencv, machine vision, computer vision, image recognition, vimba, vimba-sdk, allied vision', + 'Topic :: Scientific/Engineering :: Visualization', + 'Topic :: Software Development :: Libraries :: Python Modules' + ], + keywords='python, python3, opencv, cv, machine vision, computer vision, image recognition, vimba, allied vision', author='morefigs', author_email='morefigs@gmail.com', url='https://github.com/morefigs/pymba', license='GPL-3.0', - packages=['pymba'], + packages=[ + 'pymba', + 'tests', + ], zip_safe=False, - requires=['numpy']) + install_requires=[ + 'numpy', + ], + extras_requires={ + 'dev': [ + 'pytest', + ] + } + ) diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/tests/__init__.py +++ /dev/null diff --git a/tests/opencv_example.py b/tests/opencv_example.py deleted file mode 100644 index 238e8b4..0000000 --- a/tests/opencv_example.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import absolute_import, print_function, division -from pymba import * -import numpy as np -import cv2 -import time - -#very crude example, assumes your camera is PixelMode = BAYERRG8 - -# start Vimba -with Vimba() as vimba: - # get system object - system = vimba.getSystem() - - # list available cameras (after enabling discovery for GigE cameras) - if system.GeVTLIsPresent: - system.runFeatureCommand("GeVDiscoveryAllOnce") - time.sleep(0.2) - cameraIds = vimba.getCameraIds() - for cameraId in cameraIds: - print('Camera ID:', cameraId) - - # get and open a camera - camera0 = vimba.getCamera(cameraIds[0]) - camera0.openCamera() - - # list camera features - cameraFeatureNames = camera0.getFeatureNames() - for name in cameraFeatureNames: - print('Camera feature:', name) - - # read info of a camera feature - #featureInfo = camera0.getFeatureInfo('AcquisitionMode') - #for field in featInfo.getFieldNames(): - # print field, '--', getattr(featInfo, field) - - # get the value of a feature - print(camera0.AcquisitionMode) - - # set the value of a feature - camera0.AcquisitionMode = 'SingleFrame' - - # create new frames for the camera - frame0 = camera0.getFrame() # creates a frame - frame1 = camera0.getFrame() # creates a second frame - - # announce frame - frame0.announceFrame() - - # capture a camera image - count = 0 - while count < 10: - camera0.startCapture() - frame0.queueFrameCapture() - camera0.runFeatureCommand('AcquisitionStart') - camera0.runFeatureCommand('AcquisitionStop') - frame0.waitFrameCapture() - - # get image data... - imgData = frame0.getBufferByteData() - - moreUsefulImgData = np.ndarray(buffer = frame0.getBufferByteData(), - dtype = np.uint8, - shape = (frame0.height, - frame0.width, - 1)) - rgb = cv2.cvtColor(moreUsefulImgData, cv2.COLOR_BAYER_RG2RGB) - cv2.imwrite('foo{}.png'.format(count), rgb) - print("image {} saved".format(count)) - count += 1 - camera0.endCapture() - # clean up after capture - camera0.revokeAllFrames() - - # close camera - camera0.closeCamera() - diff --git a/tests/opencv_liveview_example.py b/tests/opencv_liveview_example.py deleted file mode 100644 index 78b6b67..0000000 --- a/tests/opencv_liveview_example.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Jul 07 14:59:03 2014 - -@author: derricw -""" - -from __future__ import absolute_import, print_function, division -from pymba import * -import numpy as np -import cv2 -import time - -cv2.namedWindow("test") - -with Vimba() as vimba: - system = vimba.getSystem() - - system.runFeatureCommand("GeVDiscoveryAllOnce") - time.sleep(0.2) - - camera_ids = vimba.getCameraIds() - - for cam_id in camera_ids: - print("Camera found: ", cam_id) - - c0 = vimba.getCamera(camera_ids[0]) - c0.openCamera() - - try: - #gigE camera - print(c0.GevSCPSPacketSize) - print(c0.StreamBytesPerSecond) - c0.StreamBytesPerSecond = 100000000 - except: - #not a gigE camera - pass - - #set pixel format - c0.PixelFormat="Mono8" - #c0.ExposureTimeAbs=60000 - - frame = c0.getFrame() - frame.announceFrame() - - c0.startCapture() - - framecount = 0 - droppedframes = [] - - while 1: - try: - frame.queueFrameCapture() - success = True - except: - droppedframes.append(framecount) - success = False - c0.runFeatureCommand("AcquisitionStart") - c0.runFeatureCommand("AcquisitionStop") - frame.waitFrameCapture(1000) - frame_data = frame.getBufferByteData() - if success: - img = np.ndarray(buffer=frame_data, - dtype=np.uint8, - shape=(frame.height,frame.width,1)) - cv2.imshow("test",img) - framecount+=1 - k = cv2.waitKey(1) - if k == 0x1b: - cv2.destroyAllWindows() - print("Frames displayed: %i"%framecount) - print("Frames dropped: %s"%droppedframes) - break - - - c0.endCapture() - c0.revokeAllFrames() - - c0.closeCamera() diff --git a/tests/opencv_liveview_example_color.py b/tests/opencv_liveview_example_color.py deleted file mode 100644 index fd7a819..0000000 --- a/tests/opencv_liveview_example_color.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Jul 07 14:59:03 2014 - -@author: derricw - -Same as the other liveview example, but displays in color. - -Obviously you want to use a camera that has a color mode like BGR8Packed - -OpenCV is expecting color images to be in BGR8Packed by default. It can work - with other formats as well as convert one to the other, but this example - just uses its default behavior. - -""" -from __future__ import absolute_import, print_function, division -from pymba import * -import numpy as np -import cv2 -import time -import sys - -cv2.namedWindow("test") - -with Vimba() as vimba: - system = vimba.getSystem() - - system.runFeatureCommand("GeVDiscoveryAllOnce") - time.sleep(0.2) - - camera_ids = vimba.getCameraIds() - - for cam_id in camera_ids: - print("Camera found: ", cam_id) - - c0 = vimba.getCamera(camera_ids[0]) - c0.openCamera() - - try: - #gigE camera - print("Packet size:", c0.GevSCPSPacketSize) - c0.StreamBytesPerSecond = 100000000 - print("BPS:", c0.StreamBytesPerSecond) - except: - #not a gigE camera - pass - - #set pixel format - c0.PixelFormat = "BGR8Packed" # OPENCV DEFAULT - time.sleep(0.2) - - frame = c0.getFrame() - frame.announceFrame() - - c0.startCapture() - - framecount = 0 - droppedframes = [] - - while 1: - try: - frame.queueFrameCapture() - success = True - except: - droppedframes.append(framecount) - success = False - c0.runFeatureCommand("AcquisitionStart") - c0.runFeatureCommand("AcquisitionStop") - frame.waitFrameCapture(1000) - frame_data = frame.getBufferByteData() - if success: - img = np.ndarray(buffer=frame_data, - dtype=np.uint8, - shape=(frame.height, frame.width, frame.pixel_bytes)) - cv2.imshow("test", img) - framecount += 1 - k = cv2.waitKey(1) - if k == 0x1b: - cv2.destroyAllWindows() - print("Frames displayed: %i" % framecount) - print("Frames dropped: %s" % droppedframes) - break - - - c0.endCapture() - c0.revokeAllFrames() - - c0.closeCamera() - diff --git a/tests/test_cameras.py b/tests/test_cameras.py deleted file mode 100644 index a5a4dd9..0000000 --- a/tests/test_cameras.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/python -from __future__ import absolute_import, print_function, division -from pymba import * -import time - - -def test_cameras(): - # start Vimba - with Vimba() as vimba: - # get system object - system = vimba.getSystem() - - # list available cameras (after enabling discovery for GigE cameras) - if system.GeVTLIsPresent: - system.runFeatureCommand("GeVDiscoveryAllOnce") - time.sleep(0.2) - - cameraIds = vimba.getCameraIds() - for cameraId in cameraIds: - print('Camera ID:', cameraId) - - # get and open a camera - camera0 = vimba.getCamera(cameraIds[0]) - camera0.openCamera() - - # list camera features - cameraFeatureNames = camera0.getFeatureNames() - for name in cameraFeatureNames: - print('Camera feature:', name) - - # get the value of a feature - print(camera0.AcquisitionMode) - - # set the value of a feature - camera0.AcquisitionMode = 'SingleFrame' - - # create new frames for the camera - frame0 = camera0.getFrame() # creates a frame - frame1 = camera0.getFrame() # creates a second frame - - # announce frame - frame0.announceFrame() - - # capture a camera image - camera0.startCapture() - frame0.queueFrameCapture() - camera0.runFeatureCommand('AcquisitionStart') - camera0.runFeatureCommand('AcquisitionStop') - frame0.waitFrameCapture() - - # get image data... - imgData = frame0.getBufferByteData() - - # ...or use NumPy for fast image display (for use with OpenCV, etc) - import numpy as np - - moreUsefulImgData = np.ndarray(buffer=frame0.getBufferByteData(), - dtype=np.uint8, - shape=(frame0.height, - frame0.width, - 1)) - - # clean up after capture - camera0.endCapture() - camera0.revokeAllFrames() - - # close camera - camera0.closeCamera() - - -if __name__ == '__main__': - test_cameras()
\ No newline at end of file diff --git a/tests/test_enumfeature.py b/tests/test_enumfeature.py deleted file mode 100644 index 7f9dd4c..0000000 --- a/tests/test_enumfeature.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/python -from __future__ import absolute_import, print_function, division -from pymba import * - - -def test_enumfeature(): - # get system object - with Vimba() as vimba: - system = vimba.getSystem() - - # get enum value - print ("get enum value (DiscoveryCameraEvent): '%s'" % (system.DiscoveryCameraEvent)) - - # get enum range - range = system.getFeatureRange('DiscoveryCameraEvent') - print ("get enum value range (DiscoveryCameraEvent): '%s'" % (str(range))) - - # set enum value - #print ("setting enum value (DiscoveryCameraEvent)...") - #system.DiscoveryCameraEvent = 'Unreachable' - #print ("enum value (DiscoveryCameraEvent)set to '%s'." % (system.DiscoveryCameraEvent.value)) - - -if __name__ == '__main__': - test_enumfeature()
\ No newline at end of file diff --git a/tests/test_installation.py b/tests/test_installation.py deleted file mode 100644 index 06af7d6..0000000 --- a/tests/test_installation.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/python -from __future__ import absolute_import, print_function, division -from pymba import Vimba - - -def test_installation(): - with Vimba() as vimba: - version = vimba.getVersion() - assert version == '1.2.0' diff --git a/tests/test_interfaces.py b/tests/test_interfaces.py deleted file mode 100644 index 270d42c..0000000 --- a/tests/test_interfaces.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python -from __future__ import absolute_import, print_function, division -from pymba import * -import time - - -def test_interfaces(): - # start Vimba - with Vimba() as vimba: - # get list of available interfaces - interfaceIds = vimba.getInterfaceIds() - for interfaceId in interfaceIds: - print('Interface ID:', interfaceId) - - # get interface object and open it - interface0 = vimba.getInterface(interfaceIds[0]) - interface0.openInterface() - - # list interface features - interfaceFeatureNames = interface0.getFeatureNames() - for name in interfaceFeatureNames: - print('Interface feature:', name) - - # close interface - interface0.closeInterface() - -if __name__ == '__main__': - test_interfaces()
\ No newline at end of file diff --git a/tests/test_systemfeature.py b/tests/test_systemfeature.py deleted file mode 100644 index abb4da7..0000000 --- a/tests/test_systemfeature.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/python -from __future__ import absolute_import, print_function, division -from pymba import * - - -def test_systemfeature(): - # get system object - with Vimba() as vimba: - system = vimba.getSystem() - - # list system features - for featureName in system.getFeatureNames(): - print('System feature:', featureName) - fInfo = system.getFeatureInfo(featureName) - for field in fInfo.getFieldNames(): - print("\t", featureName, ":", field, getattr(fInfo, field)) - - -if __name__ == '__main__': - test_systemfeature()
\ No newline at end of file diff --git a/tests/test_vimba.py b/tests/test_vimba.py new file mode 100644 index 0000000..b1ef987 --- /dev/null +++ b/tests/test_vimba.py @@ -0,0 +1,52 @@ +import pytest + +from pymba import Vimba, VimbaException + + +def test_version(): + version = Vimba().version.split('.') + assert int(version[0]) >= 1 + assert int(version[1]) >= 7 + assert int(version[2]) >= 0 + + +def test_startup_shutdown(): + with pytest.raises(VimbaException) as e: + Vimba().system().feature_names() + assert e.value.error_code == VimbaException.ERR_STARTUP_NOT_CALLED + + # manual + Vimba().startup() + Vimba().system().feature_names() + Vimba().shutdown() + + # context manager + with Vimba() as vmb: + vmb.system().feature_names() + + +@pytest.fixture +def vimba() -> Vimba: + with Vimba() as vimba: + # for ethernet camera discovery + if vimba.system().GeVTLIsPresent: + vimba.system().run_feature_command("GeVDiscoveryAllOnce") + yield vimba + + +def test_interface_camera_ids(vimba: Vimba): + # test id funcs return a list of strings (not bytes) + for func in (vimba.interface_ids, vimba.camera_ids): + ids = func() + assert isinstance(ids, list) + assert ids + for x in ids: + assert isinstance(x, str) + + +def test_interface(vimba: Vimba): + interface = vimba.interface(vimba.interface_ids()[0]) + + +def test_camera(vimba: Vimba): + camera = vimba.camera(vimba.camera_ids()[0]) |
