From d26f4f736dde31d0a651a97500c63023578ed862 Mon Sep 17 00:00:00 2001 From: morefigs Date: Wed, 23 Jan 2019 14:24:27 +1100 Subject: simplify file names --- pymba/camera.py | 91 +++++++++++++++++++ pymba/feature.py | 225 +++++++++++++++++++++++++++++++++++++++++++++++ pymba/frame.py | 175 ++++++++++++++++++++++++++++++++++++ pymba/interface.py | 37 ++++++++ pymba/system.py | 9 ++ pymba/vimba.py | 20 ++--- pymba/vimba_c.py | 22 ----- pymba/vimba_camera.py | 91 ------------------- pymba/vimba_feature.py | 225 ----------------------------------------------- pymba/vimba_frame.py | 175 ------------------------------------ pymba/vimba_interface.py | 37 -------- pymba/vimba_object.py | 8 +- pymba/vimba_system.py | 9 -- 13 files changed, 551 insertions(+), 573 deletions(-) create mode 100644 pymba/camera.py create mode 100644 pymba/feature.py create mode 100644 pymba/frame.py create mode 100644 pymba/interface.py create mode 100644 pymba/system.py delete mode 100644 pymba/vimba_camera.py delete mode 100644 pymba/vimba_feature.py delete mode 100644 pymba/vimba_frame.py delete mode 100644 pymba/vimba_interface.py delete mode 100644 pymba/vimba_system.py diff --git a/pymba/camera.py b/pymba/camera.py new file mode 100644 index 0000000..16910fb --- /dev/null +++ b/pymba/camera.py @@ -0,0 +1,91 @@ +from ctypes import byref, sizeof +from typing import Optional + +from .vimba_object import VimbaObject +from .vimba_exception import VimbaException +from .frame import Frame +from . import vimba_c + + +class Camera(VimbaObject): + """ + A Vimba camera object. + """ + + def __init__(self, id_string: str): + self._id_string = id_string.encode() + super().__init__() + self._info = self._get_info() + + @property + def id_string(self) -> str: + return self._id_string.decode() + + def _get_info(self) -> vimba_c.VmbCameraInfo: + """ + Get info of the camera. Does not require the camera to be opened. + """ + vmb_camera_info = vimba_c.VmbCameraInfo() + error = vimba_c.vmb_camera_info_query(self._id_string, + byref(vmb_camera_info), + sizeof(vmb_camera_info)) + if error: + raise VimbaException(error) + + return vmb_camera_info + + 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._id_string, + 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..f81ea6a --- /dev/null +++ b/pymba/feature.py @@ -0,0 +1,225 @@ +from ctypes import byref, sizeof, c_uint32, c_double, c_char_p, c_bool, c_int64, create_string_buffer +from typing import Tuple, List + +from .vimba_exception import VimbaException +from . import vimba_c + + +class Feature: + """ + A feature of a Vimba object. + """ + + ( + _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) + + @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._feature_data_value_funcs[self._info.featureDataType][0]() + + @value.setter + def value(self, val): + self._feature_data_value_funcs[self._info.featureDataType][1](val) + + @property + def range(self): + return self._feature_data_range_funcs[self._info.featureDataType]() + + def __init__(self, name, handle): + self._name = name.encode() + self._handle = handle + + # type functions dict for looking up correct get/set function to use + self._feature_data_value_funcs = { + self._FEATURE_DATA_UNKNOWN: None, + self._FEATURE_DATA_INT: (self._get_int, self._set_int), + self._FEATURE_DATA_FLOAT: (self._get_float, self._set_float), + self._FEATURE_DATA_ENUM: (self._get_enum, self._set_enum), + self._FEATURE_DATA_STRING: (self._get_string, self._set_string), + self._FEATURE_DATA_BOOL: (self._get_bool, self._set_bool), + self._FEATURE_DATA_COMMAND: None, + self._FEATURE_DATA_RAW: None, + self._FEATURE_DATA_NONE: None, + } + + # type functions dict for looking up correct range function to use + self._feature_data_range_funcs = { + self._FEATURE_DATA_UNKNOWN: None, + self._FEATURE_DATA_INT: self._range_query_int, + self._FEATURE_DATA_FLOAT: self._range_query_float, + self._FEATURE_DATA_ENUM: self._range_query_enum, + self._FEATURE_DATA_STRING: None, + self._FEATURE_DATA_BOOL: None, + self._FEATURE_DATA_COMMAND: None, + self._FEATURE_DATA_RAW: None, + self._FEATURE_DATA_NONE: None, + } + + # get info once + self._info = self._get_info() + + def _get_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('\x00' * 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..1e01333 --- /dev/null +++ b/pymba/frame.py @@ -0,0 +1,175 @@ +from ctypes import byref, sizeof, addressof, create_string_buffer, cast, POINTER, c_ubyte, c_void_p +from typing import Optional +import warnings +try: + import numpy as np +except ImportError: + warnings.warn('could not import numpy, some Frame methods may not work.') + +from .camera import Camera +from .vimba_exception import VimbaException +from . import vimba_c + + +# Map pixel formats to bytes per pixel. +PIXEL_FORMATS = { + "Mono8": 1, + "Mono12": 2, + # untested + "Mono12Packed": 1.5, + "Mono14": 2, + "Mono16": 2, + "RGB8": 3, + "RGB8Packed": 3, + "BGR8Packed": 3, + "RGBA8Packed": 4, + "BGRA8Packed": 4, + # untested + "YUV411Packed": 4 / 3.0, + "YUV422Packed": 2, + "YUV444Packed": 3, + "BayerRG8": 1, + "BayerRG12": 2, + "BayerGR8": 1, + "BayerGR12": 2, + # untested + "BayerGR12Packed": 1.5, +} + + +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) + + def __del__(self): + del self._block + + +class Frame: + """ + A Vimba frame. + """ + + def __init__(self, camera: Camera): + self._camera = camera + self._handle = camera.handle + + # get frame sizes + self.payload_size = 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 = vimba_c.VmbFrame() + + self._c_mem = None + + def announce(self): + """ + 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.payload_size) + # set buffer to have length of expected payload size + self._frame.buffer = self._c_mem.block + + # set buffer size to expected payload size + self._frame.bufferSize = self.payload_size + + error = vimba_c.vmb_frame_announce(self._handle, + byref(self._frame), + sizeof(self._frame)) + if error: + raise VimbaException(error) + + def revoke(self): + """ + Revoke a frame from the API. + """ + error = vimba_c.vmb_frame_revoke(self._handle, + byref(self._frame)) + if error: + raise VimbaException(error) + + def queue_capture(self, frame_callback: Optional[bool] = 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(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._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(frame_callback_wrapper) + + error = vimba_c.vmb_capture_frame_queue(self._handle, + byref(self._frame), + self._frame_callback_wrapper_c) + if error: + raise VimbaException(error) + + def wait_capture(self, timeout_ms: Optional[int] = 2000) -> int: + """ + 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._handle, + byref(self._frame), + timeout_ms) + + # error to be processed by the end user for this function. + # Prevents system for breaking for example on a hardware trigger timeout + + # todo raise error instead? + + return error + + def get_buffer_data(self) -> c_ubyte * int: + """ + Retrieve buffer data in a useful format. + """ + # cast frame buffer memory contents to a usable type + data = cast(self._frame.buffer, POINTER(c_ubyte * self.payload_size)) + + # make array of c_ubytes from buffer + image_bytes = int(self.height * self.width * self.pixel_bytes) + return (c_ubyte * image_bytes).from_address(addressof(data.contents)) + + def get_image(self) -> np.ndarray: + """ + Returns the frame's image data as a NumPy array. + """ + data = cast(self._frame.buffer, POINTER(c_ubyte * self._frame.imageSize)) + return np.ndarray(buffer=data.contents, dtype=np.uint8, shape=(self._frame.height, self._frame.width)) + + @property + def timestamp(self) -> int: + return self._frame.timestamp + + @property + def receive_status(self) -> int: + return self._frame.receiveStatus diff --git a/pymba/interface.py b/pymba/interface.py new file mode 100644 index 0000000..a035b0a --- /dev/null +++ b/pymba/interface.py @@ -0,0 +1,37 @@ +from ctypes import byref + +from .vimba_object import VimbaObject +from .vimba_exception import VimbaException +from . import vimba_c + + +class Interface(VimbaObject): + """ + A Vimba interface object. This class provides the minimal access + to Vimba functions required to control the interface. + """ + + def __init__(self, id_string: str): + self._id_string = id_string.encode() + super().__init__() + + @property + def id_string(self): + return self._id_string.decode() + + def open(self): + """ + Open the interface. + """ + error = vimba_c.vmb_interface_open(self._id_string, + 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 0d6c6b5..1174c3d 100644 --- a/pymba/vimba.py +++ b/pymba/vimba.py @@ -2,9 +2,9 @@ from ctypes import byref, sizeof, c_uint32 from typing import List from .vimba_exception import VimbaException -from .vimba_system import VimbaSystem -from .vimba_camera import VimbaCamera -from .vimba_interface import VimbaInterface +from .system import System +from .camera import Camera +from .interface import Interface from . import vimba_c @@ -17,7 +17,7 @@ class Vimba(object): def __init__(self): # create own system singleton object - self._system = VimbaSystem() + self._system = System() self._vmb_interface_infos = None self._interfaces = {} self._cameras = {} @@ -38,7 +38,7 @@ class Vimba(object): self.shutdown() @property - def system(self) -> VimbaSystem: + def system(self) -> System: """ Get the system object. """ @@ -172,7 +172,7 @@ class Vimba(object): raise VimbaException(error) return vmb_camera_info - def get_interface(self, id_string) -> VimbaInterface: + def get_interface(self, id_string) -> Interface: """ Gets interface object based on interface ID string. Will not recreate interface object if it already exists. :param id_string: the ID of the interface. @@ -181,11 +181,11 @@ class Vimba(object): if id_string in self.get_interface_ids(): # create it if it doesn't exist if id_string not in self._interfaces: - self._interfaces[id_string] = VimbaInterface(id_string) + self._interfaces[id_string] = Interface(id_string) return self._interfaces[id_string] raise VimbaException(VimbaException.ERR_INTERFACE_NOT_FOUND) - def get_camera(self, camera_id: str) -> VimbaCamera: + def get_camera(self, camera_id: str) -> Camera: """ Gets camera object based on camera ID string. Will not recreate camera object if it already exists. :param camera_id: the ID of the camera object to get. This can be an ID or e.g. a serial number. Check the Vimba @@ -195,7 +195,7 @@ class Vimba(object): if camera_id in self.get_camera_ids(): # create it if it doesn't exist if camera_id not in self._cameras: - self._cameras[camera_id] = VimbaCamera(camera_id) + self._cameras[camera_id] = Camera(camera_id) return self._cameras[camera_id] else: # the given string might not be a camera ID -> check for other IDs @@ -208,5 +208,5 @@ class Vimba(object): camera_id_string = vmb_camera_info.id_string.decode() if camera_id_string not in self._cameras: - self._cameras[camera_id_string] = VimbaCamera(camera_id_string) + self._cameras[camera_id_string] = Camera(camera_id_string) return self._cameras[camera_id_string] diff --git a/pymba/vimba_c.py b/pymba/vimba_c.py index ef547ae..b996720 100644 --- a/pymba/vimba_c.py +++ b/pymba/vimba_c.py @@ -3,8 +3,6 @@ import platform import os from ctypes import * -from .vimba_exception import VimbaException - if sys_plat == "win32": @@ -75,26 +73,6 @@ else: CALLBACK_FUNCTYPE = CFUNCTYPE -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) - - def __del__(self): - del self._block - - class VmbVersionInfo(Structure): _fields_ = [ ('major', c_uint32), diff --git a/pymba/vimba_camera.py b/pymba/vimba_camera.py deleted file mode 100644 index 27bd5d3..0000000 --- a/pymba/vimba_camera.py +++ /dev/null @@ -1,91 +0,0 @@ -from ctypes import byref, sizeof -from typing import Optional - -from .vimba_object import VimbaObject -from .vimba_exception import VimbaException -from .vimba_frame import VimbaFrame -from . import vimba_c - - -class VimbaCamera(VimbaObject): - """ - A Vimba camera object. - """ - - def __init__(self, id_string: str): - self._id_string = id_string.encode() - super().__init__() - self._info = self._get_info() - - @property - def id_string(self) -> str: - return self._id_string.decode() - - def _get_info(self) -> vimba_c.VmbCameraInfo: - """ - Get info of the camera. Does not require the camera to be opened. - """ - vmb_camera_info = vimba_c.VmbCameraInfo() - error = vimba_c.vmb_camera_info_query(self._id_string, - byref(vmb_camera_info), - sizeof(vmb_camera_info)) - if error: - raise VimbaException(error) - - return vmb_camera_info - - 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._id_string, - 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) -> VimbaFrame: - """ - Creates and returns a new frame object. Multiple frames per camera can therefore be returned. - """ - return VimbaFrame(self) diff --git a/pymba/vimba_feature.py b/pymba/vimba_feature.py deleted file mode 100644 index 6e68bea..0000000 --- a/pymba/vimba_feature.py +++ /dev/null @@ -1,225 +0,0 @@ -from ctypes import byref, sizeof, c_uint32, c_double, c_char_p, c_bool, c_int64, create_string_buffer -from typing import Tuple, List - -from .vimba_exception import VimbaException -from . import vimba_c - - -class VimbaFeature: - """ - A feature of a Vimba object. - """ - - ( - _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) - - @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._feature_data_value_funcs[self._info.featureDataType][0]() - - @value.setter - def value(self, val): - self._feature_data_value_funcs[self._info.featureDataType][1](val) - - @property - def range(self): - return self._feature_data_range_funcs[self._info.featureDataType]() - - def __init__(self, name, handle): - self._name = name.encode() - self._handle = handle - - # type functions dict for looking up correct get/set function to use - self._feature_data_value_funcs = { - self._FEATURE_DATA_UNKNOWN: None, - self._FEATURE_DATA_INT: (self._get_int, self._set_int), - self._FEATURE_DATA_FLOAT: (self._get_float, self._set_float), - self._FEATURE_DATA_ENUM: (self._get_enum, self._set_enum), - self._FEATURE_DATA_STRING: (self._get_string, self._set_string), - self._FEATURE_DATA_BOOL: (self._get_bool, self._set_bool), - self._FEATURE_DATA_COMMAND: None, - self._FEATURE_DATA_RAW: None, - self._FEATURE_DATA_NONE: None, - } - - # type functions dict for looking up correct range function to use - self._feature_data_range_funcs = { - self._FEATURE_DATA_UNKNOWN: None, - self._FEATURE_DATA_INT: self._range_query_int, - self._FEATURE_DATA_FLOAT: self._range_query_float, - self._FEATURE_DATA_ENUM: self._range_query_enum, - self._FEATURE_DATA_STRING: None, - self._FEATURE_DATA_BOOL: None, - self._FEATURE_DATA_COMMAND: None, - self._FEATURE_DATA_RAW: None, - self._FEATURE_DATA_NONE: None, - } - - # get info once - self._info = self._get_info() - - def _get_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('\x00' * 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/vimba_frame.py b/pymba/vimba_frame.py deleted file mode 100644 index 0832429..0000000 --- a/pymba/vimba_frame.py +++ /dev/null @@ -1,175 +0,0 @@ -from ctypes import byref, sizeof, addressof, create_string_buffer, cast, POINTER, c_ubyte, c_void_p -from typing import Optional -import warnings -try: - import numpy as np -except ImportError: - warnings.warn('could not import numpy, some Frame methods may not work.') - -from .vimba_camera import VimbaCamera -from .vimba_exception import VimbaException -from . import vimba_c - - -# Map pixel formats to bytes per pixel. -PIXEL_FORMATS = { - "Mono8": 1, - "Mono12": 2, - # untested - "Mono12Packed": 1.5, - "Mono14": 2, - "Mono16": 2, - "RGB8": 3, - "RGB8Packed": 3, - "BGR8Packed": 3, - "RGBA8Packed": 4, - "BGRA8Packed": 4, - # untested - "YUV411Packed": 4 / 3.0, - "YUV422Packed": 2, - "YUV444Packed": 3, - "BayerRG8": 1, - "BayerRG12": 2, - "BayerGR8": 1, - "BayerGR12": 2, - # untested - "BayerGR12Packed": 1.5, -} - - -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) - - def __del__(self): - del self._block - - -class Frame: - """ - A Vimba frame. - """ - - def __init__(self, camera: VimbaCamera): - self._camera = camera - self._handle = camera.handle - - # get frame sizes - self.payload_size = 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 = vimba_c.VmbFrame() - - self._c_mem = None - - def announce(self): - """ - 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.payload_size) - # set buffer to have length of expected payload size - self._frame.buffer = self._c_mem.block - - # set buffer size to expected payload size - self._frame.bufferSize = self.payload_size - - error = vimba_c.vmb_frame_announce(self._handle, - byref(self._frame), - sizeof(self._frame)) - if error: - raise VimbaException(error) - - def revoke(self): - """ - Revoke a frame from the API. - """ - error = vimba_c.vmb_frame_revoke(self._handle, - byref(self._frame)) - if error: - raise VimbaException(error) - - def queue_capture(self, frame_callback: Optional[bool] = 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(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._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(frame_callback_wrapper) - - error = vimba_c.vmb_capture_frame_queue(self._handle, - byref(self._frame), - self._frame_callback_wrapper_c) - if error: - raise VimbaException(error) - - def wait_capture(self, timeout_ms: Optional[int] = 2000) -> int: - """ - 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._handle, - byref(self._frame), - timeout_ms) - - # error to be processed by the end user for this function. - # Prevents system for breaking for example on a hardware trigger timeout - - # todo raise error instead? - - return error - - def get_buffer_data(self) -> c_ubyte * int: - """ - Retrieve buffer data in a useful format. - """ - # cast frame buffer memory contents to a usable type - data = cast(self._frame.buffer, POINTER(c_ubyte * self.payload_size)) - - # make array of c_ubytes from buffer - image_bytes = int(self.height * self.width * self.pixel_bytes) - return (c_ubyte * image_bytes).from_address(addressof(data.contents)) - - def get_image(self) -> np.ndarray: - """ - Returns the frame's image data as a NumPy array. - """ - data = cast(self._frame.buffer, POINTER(c_ubyte * self._frame.imageSize)) - return np.ndarray(buffer=data.contents, dtype=np.uint8, shape=(self._frame.height, self._frame.width)) - - @property - def timestamp(self) -> int: - return self._frame.timestamp - - @property - def receive_status(self) -> int: - return self._frame.receiveStatus diff --git a/pymba/vimba_interface.py b/pymba/vimba_interface.py deleted file mode 100644 index 647aa44..0000000 --- a/pymba/vimba_interface.py +++ /dev/null @@ -1,37 +0,0 @@ -from ctypes import byref - -from .vimba_object import VimbaObject -from .vimba_exception import VimbaException -from . import vimba_c - - -class VimbaInterface(VimbaObject): - """ - A Vimba interface object. This class provides the minimal access - to Vimba functions required to control the interface. - """ - - def __init__(self, id_string: str): - self._id_string = id_string.encode() - super().__init__() - - @property - def id_string(self): - return self._id_string.decode() - - def open(self): - """ - Open the interface. - """ - error = vimba_c.vmb_interface_open(self._id_string, - 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/vimba_object.py b/pymba/vimba_object.py index 7199e61..f8d7c93 100644 --- a/pymba/vimba_object.py +++ b/pymba/vimba_object.py @@ -2,7 +2,7 @@ from ctypes import byref, sizeof, c_void_p, c_uint32, c_uint64, c_bool from typing import Union, Tuple, List, Optional from .vimba_exception import VimbaException -from .vimba_feature import VimbaFeature +from .feature import Feature from . import vimba_c @@ -35,7 +35,7 @@ class VimbaObject: def __getattr__(self, attr): # if a feature value requested (requires object (camera) open) if attr in self.get_feature_names(): - return VimbaFeature(attr, self._handle).value + return Feature(attr, self._handle).value # otherwise don't know about it raise AttributeError(''.join(["'VimbaObject' has no attribute '", attr, "'"])) @@ -51,7 +51,7 @@ class VimbaObject: # if it's an actual camera feature (requires camera open) elif attr in self.get_feature_names(): - VimbaFeature(attr, self._handle).value = val + Feature(attr, self._handle).value = val # otherwise just set the attribute value as normal else: @@ -125,7 +125,7 @@ class VimbaObject: list -- names of possible enum values (for enum features only). """ # shouldn't cache this - return VimbaFeature(feature_name, self._handle).range + return Feature(feature_name, self._handle).range def run_feature_command(self, feature_name: str) -> None: """ diff --git a/pymba/vimba_system.py b/pymba/vimba_system.py deleted file mode 100644 index 407bef6..0000000 --- a/pymba/vimba_system.py +++ /dev/null @@ -1,9 +0,0 @@ -from .vimba_object import VimbaObject - - -class VimbaSystem(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) -- cgit v1.2.3