AVT相机arm版本SDK

This commit is contained in:
zhangpeng
2025-04-30 09:26:04 +08:00
parent 837c870f18
commit 78a1c63a95
705 changed files with 148770 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
# Suppress 'imported but unused' - Error from static style checker.
# flake8: noqa: F401
__version__ = '1.2.1'
__all__ = [
'Vimba',
'Camera',
'CameraChangeHandler',
'CameraEvent',
'AccessMode',
'PersistType',
'Interface',
'InterfaceType',
'InterfaceChangeHandler',
'InterfaceEvent',
'PixelFormat',
'Frame',
'FeatureTypes',
'FrameHandler',
'FrameStatus',
'AllocationMode',
'Debayer',
'intersect_pixel_formats',
'MONO_PIXEL_FORMATS',
'BAYER_PIXEL_FORMATS',
'RGB_PIXEL_FORMATS',
'RGBA_PIXEL_FORMATS',
'BGR_PIXEL_FORMATS',
'BGRA_PIXEL_FORMATS',
'YUV_PIXEL_FORMATS',
'YCBCR_PIXEL_FORMATS',
'COLOR_PIXEL_FORMATS',
'OPENCV_PIXEL_FORMATS',
'VimbaSystemError',
'VimbaCameraError',
'VimbaInterfaceError',
'VimbaFeatureError',
'VimbaFrameError',
'VimbaTimeout',
'IntFeature',
'FloatFeature',
'StringFeature',
'BoolFeature',
'EnumEntry',
'EnumFeature',
'CommandFeature',
'RawFeature',
'LogLevel',
'LogConfig',
'Log',
'LOG_CONFIG_TRACE_CONSOLE_ONLY',
'LOG_CONFIG_TRACE_FILE_ONLY',
'LOG_CONFIG_TRACE',
'LOG_CONFIG_INFO_CONSOLE_ONLY',
'LOG_CONFIG_INFO_FILE_ONLY',
'LOG_CONFIG_INFO',
'LOG_CONFIG_WARNING_CONSOLE_ONLY',
'LOG_CONFIG_WARNING_FILE_ONLY',
'LOG_CONFIG_WARNING',
'LOG_CONFIG_ERROR_CONSOLE_ONLY',
'LOG_CONFIG_ERROR_FILE_ONLY',
'LOG_CONFIG_ERROR',
'LOG_CONFIG_CRITICAL_CONSOLE_ONLY',
'LOG_CONFIG_CRITICAL_FILE_ONLY',
'LOG_CONFIG_CRITICAL',
'TraceEnable',
'ScopedLogEnable',
'RuntimeTypeCheckEnable'
]
# Import everything exported from the top level module
from .vimba import Vimba
from .camera import AccessMode, PersistType, Camera, CameraChangeHandler, CameraEvent, FrameHandler
from .interface import Interface, InterfaceType, InterfaceChangeHandler, InterfaceEvent
from .frame import PixelFormat, Frame, Debayer, intersect_pixel_formats, MONO_PIXEL_FORMATS, \
BAYER_PIXEL_FORMATS, RGB_PIXEL_FORMATS, RGBA_PIXEL_FORMATS, BGR_PIXEL_FORMATS, \
BGRA_PIXEL_FORMATS, YUV_PIXEL_FORMATS, YCBCR_PIXEL_FORMATS, \
COLOR_PIXEL_FORMATS, OPENCV_PIXEL_FORMATS, FrameStatus, FeatureTypes, \
AllocationMode
from .error import VimbaSystemError, VimbaCameraError, VimbaInterfaceError, VimbaFeatureError, \
VimbaFrameError, VimbaTimeout
from .feature import IntFeature, FloatFeature, StringFeature, BoolFeature, EnumEntry, EnumFeature, \
CommandFeature, RawFeature
from .util import Log, LogLevel, LogConfig, LOG_CONFIG_TRACE_CONSOLE_ONLY, \
LOG_CONFIG_TRACE_FILE_ONLY, LOG_CONFIG_TRACE, LOG_CONFIG_INFO_CONSOLE_ONLY, \
LOG_CONFIG_INFO_FILE_ONLY, LOG_CONFIG_INFO, LOG_CONFIG_WARNING_CONSOLE_ONLY, \
LOG_CONFIG_WARNING_FILE_ONLY, LOG_CONFIG_WARNING, LOG_CONFIG_ERROR_CONSOLE_ONLY, \
LOG_CONFIG_ERROR_FILE_ONLY, LOG_CONFIG_ERROR, LOG_CONFIG_CRITICAL_CONSOLE_ONLY, \
LOG_CONFIG_CRITICAL_FILE_ONLY, LOG_CONFIG_CRITICAL, ScopedLogEnable, \
TraceEnable, RuntimeTypeCheckEnable

View File

@@ -0,0 +1,120 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------
NOTE: Vimba/Vmb naming convention.
VimbaPython is based heavily on VimbaC, this submodule contains all wrapped types and functions
of VimbaC. All VimbaC Types and Functions are prefixed with 'Vmb', this convention is kept for
all python types interfacing with the C - Layer. VimbaC developers should be able to understand
the interface to VimbaC and keeping the name convention helps a lot in that regard.
However prefixing everything with 'Vmb' is not required in VimbaPython, therefore most Types
of the public API have no prefix.
"""
# Suppress 'imported but unused' - Error from static style checker.
# flake8: noqa: F401
__all__ = [
# Exports from vimba_common
'VmbInt8',
'VmbUint8',
'VmbInt16',
'VmbUint16',
'VmbInt32',
'VmbUint32',
'VmbInt64',
'VmbUint64',
'VmbHandle',
'VmbBool',
'VmbUchar',
'VmbDouble',
'VmbError',
'VimbaCError',
'VmbPixelFormat',
'decode_cstr',
'decode_flags',
# Exports from vimba_c
'VmbInterface',
'VmbAccessMode',
'VmbFeatureData',
'VmbFeaturePersist',
'VmbFeatureVisibility',
'VmbFeatureFlags',
'VmbFrameStatus',
'VmbFrameFlags',
'VmbVersionInfo',
'VmbInterfaceInfo',
'VmbCameraInfo',
'VmbFeatureInfo',
'VmbFeatureEnumEntry',
'VmbFrame',
'VmbFeaturePersistSettings',
'G_VIMBA_C_HANDLE',
'VIMBA_C_VERSION',
'EXPECTED_VIMBA_C_VERSION',
'call_vimba_c',
'build_callback_type',
# Exports from vimba_image_transform
'VmbImage',
'VmbImageInfo',
'VmbDebayerMode',
'VmbTransformInfo',
'VIMBA_IMAGE_TRANSFORM_VERSION',
'EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION',
'call_vimba_image_transform',
'PIXEL_FORMAT_TO_LAYOUT',
'LAYOUT_TO_PIXEL_FORMAT',
'PIXEL_FORMAT_CONVERTIBILITY_MAP',
# Exports from ctypes
'byref',
'sizeof',
'create_string_buffer'
]
from .vimba_common import VmbInt8, VmbUint8, VmbInt16, VmbUint16, VmbInt32, VmbUint32, \
VmbInt64, VmbUint64, VmbHandle, VmbBool, VmbUchar, VmbDouble, VmbError, \
VimbaCError, VmbPixelFormat, decode_cstr, decode_flags, \
_select_vimba_home
from .vimba_c import VmbInterface, VmbAccessMode, VmbFeatureData, \
VmbFeaturePersist, VmbFeatureVisibility, VmbFeatureFlags, VmbFrameStatus, \
VmbFrameFlags, VmbVersionInfo, VmbInterfaceInfo, VmbCameraInfo, VmbFeatureInfo, \
VmbFeatureEnumEntry, VmbFrame, VmbFeaturePersistSettings, \
G_VIMBA_C_HANDLE, EXPECTED_VIMBA_C_VERSION, VIMBA_C_VERSION, call_vimba_c, \
build_callback_type
from .vimba_image_transform import VmbImage, VmbImageInfo, VmbDebayerMode, \
VIMBA_IMAGE_TRANSFORM_VERSION, \
EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION, VmbTransformInfo, \
call_vimba_image_transform, PIXEL_FORMAT_TO_LAYOUT, \
LAYOUT_TO_PIXEL_FORMAT, PIXEL_FORMAT_CONVERTIBILITY_MAP
from ctypes import byref, sizeof, create_string_buffer

View File

@@ -0,0 +1,772 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import copy
import ctypes
from typing import Callable, Any, Tuple
from ctypes import c_void_p, c_char_p, byref, sizeof, POINTER as c_ptr, c_char_p as c_str
from ..util import TraceEnable
from ..error import VimbaSystemError
from .vimba_common import Uint32Enum, Int32Enum, VmbInt32, VmbUint32, VmbInt64, VmbUint64, \
VmbHandle, VmbBool, VmbDouble, VmbError, VimbaCError, VmbPixelFormat, \
fmt_enum_repr, fmt_repr, fmt_flags_repr, load_vimba_lib
__version__ = None
__all__ = [
'VmbPixelFormat',
'VmbInterface',
'VmbAccessMode',
'VmbFeatureData',
'VmbFeaturePersist',
'VmbFeatureVisibility',
'VmbFeatureFlags',
'VmbFrameStatus',
'VmbFrameFlags',
'VmbVersionInfo',
'VmbInterfaceInfo',
'VmbCameraInfo',
'VmbFeatureInfo',
'VmbFeatureEnumEntry',
'VmbFrame',
'VmbFeaturePersistSettings',
'G_VIMBA_C_HANDLE',
'VIMBA_C_VERSION',
'EXPECTED_VIMBA_C_VERSION',
'call_vimba_c',
'build_callback_type'
]
# Types
class VmbInterface(Uint32Enum):
"""
Camera Interface Types:
Unknown - Interface is not known to this version of the API
Firewire - 1394
Ethernet - GigE
Usb - USB 3.0
CL - Camera Link
CSI2 - CSI-2
"""
Unknown = 0
Firewire = 1
Ethernet = 2
Usb = 3
CL = 4
CSI2 = 5
def __str__(self):
return self._name_
class VmbAccessMode(Uint32Enum):
"""
Camera Access Mode:
None_ - No access
Full - Read and write access
Read - Read-only access
Config - Configuration access (GeV)
Lite - Read and write access without feature access (only addresses)
"""
None_ = 0
Full = 1
Read = 2
Config = 4
Lite = 8
def __str__(self):
return self._name_
class VmbFeatureData(Uint32Enum):
"""
Feature Data Types
Unknown - Unknown feature type
Int - 64 bit integer feature
Float - 64 bit floating point feature
Enum - Enumeration feature
String - String feature
Bool - Boolean feature
Command - Command feature
Raw - Raw (direct register access) feature
None_ - Feature with no data
"""
Unknown = 0
Int = 1
Float = 2
Enum = 3
String = 4
Bool = 5
Command = 6
Raw = 7
None_ = 8
def __str__(self):
return self._name_
class VmbFeaturePersist(Uint32Enum):
"""
Type of features that are to be saved (persisted) to the XML file
when using VmbCameraSettingsSave
All - Save all features to XML, including look-up tables
Streamable - Save only features marked as streamable, excluding
look-up tables
NoLUT - Save all features except look-up tables (default)
"""
All = 0
Streamable = 1
NoLUT = 2
def __str__(self):
return self._name_
class VmbFeatureVisibility(Uint32Enum):
"""
Feature Visibility
Unknown - Feature visibility is not known
Beginner - Feature is visible in feature list (beginner level)
Expert - Feature is visible in feature list (expert level)
Guru - Feature is visible in feature list (guru level)
Invisible - Feature is not visible in feature list
"""
Unknown = 0
Beginner = 1
Expert = 2
Guru = 3
Invisible = 4
def __str__(self):
return self._name_
class VmbFeatureFlags(Uint32Enum):
"""
Feature Flags
None_ - No additional information is provided
Read - Static info about read access.
Current status depends on access mode, check with
VmbFeatureAccessQuery()
Write - Static info about write access.
Current status depends on access mode, check with
VmbFeatureAccessQuery()
Volatile - Value may change at any time
ModifyWrite - Value may change after a write
"""
None_ = 0
Read = 1
Write = 2
Undocumented = 4
Volatile = 8
ModifyWrite = 16
def __str__(self):
return self._name_
class VmbFrameStatus(Int32Enum):
"""
Frame transfer status
Complete - Frame has been completed without errors
Incomplete - Frame could not be filled to the end
TooSmall - Frame buffer was too small
Invalid - Frame buffer was invalid
"""
Complete = 0
Incomplete = -1
TooSmall = -2
Invalid = -3
def __str__(self):
return self._name_
class VmbFrameFlags(Uint32Enum):
"""
Frame Flags
None_ - No additional information is provided
Dimension - Frame's dimension is provided
Offset - Frame's offset is provided (ROI)
FrameID - Frame's ID is provided
Timestamp - Frame's timestamp is provided
"""
None_ = 0
Dimension = 1
Offset = 2
FrameID = 4
Timestamp = 8
def __str__(self):
return self._name_
class VmbVersionInfo(ctypes.Structure):
"""
Version Information
Fields:
major - Type: VmbUint32, Info: Major version number
minor - Type: VmbUint32, Info: Minor version number
patch - Type: VmbUint32, Info: Patch version number
"""
_fields_ = [
("major", VmbUint32),
("minor", VmbUint32),
("patch", VmbUint32)
]
def __str__(self):
return '{}.{}.{}'.format(self.major, self.minor, self.patch)
def __repr__(self):
rep = 'VmbVersionInfo'
rep += '(major=' + repr(self.major)
rep += ',minor=' + repr(self.minor)
rep += ',patch=' + repr(self.patch)
rep += ')'
return rep
class VmbInterfaceInfo(ctypes.Structure):
"""
Interface information. Holds read-only information about an interface.
Fields:
interfaceIdString - Type: c_char_p
Info: Unique identifier for each interface
interfaceType - Type: VmbInterface (VmbUint32)
Info: Interface type, see VmbInterface
interfaceName - Type: c_char_p
Info: Interface name, given by transport layer
serialString - Type: c_char_p
Info: Serial number
permittedAccess - Type: VmbAccessMode (VmbUint32)
Info: Used access mode, see VmbAccessMode
"""
_fields_ = [
("interfaceIdString", c_char_p),
("interfaceType", VmbUint32),
("interfaceName", c_char_p),
("serialString", c_char_p),
("permittedAccess", VmbUint32)
]
def __repr__(self):
rep = 'VmbInterfaceInfo'
rep += fmt_repr('(interfaceIdString={}', self.interfaceIdString)
rep += fmt_enum_repr(',interfaceType={}', VmbInterface, self.interfaceType)
rep += fmt_repr(',interfaceName={}', self.interfaceName)
rep += fmt_repr(',serialString={}', self.serialString)
rep += fmt_flags_repr(',permittedAccess={}', VmbAccessMode, self.permittedAccess)
rep += ')'
return rep
class VmbCameraInfo(ctypes.Structure):
"""
Camera information. Holds read-only information about a camera.
Fields:
cameraIdString - Type: c_char_p
Info: Unique identifier for each camera
cameraName - Type: c_char_p
Info: Name of the camera
modelName - Type: c_char_p
Info: Model name
serialString - Type: c_char_p
Info: Serial number
permittedAccess - Type: VmbAccessMode (VmbUint32)
Info: Used access mode, see VmbAccessMode
interfaceIdString - Type: c_char_p
Info: Unique value for each interface or bus
"""
_fields_ = [
("cameraIdString", c_char_p),
("cameraName", c_char_p),
("modelName", c_char_p),
("serialString", c_char_p),
("permittedAccess", VmbUint32),
("interfaceIdString", c_char_p)
]
def __repr__(self):
rep = 'VmbCameraInfo'
rep += fmt_repr('(cameraIdString={}', self.cameraIdString)
rep += fmt_repr(',cameraName={}', self.cameraName)
rep += fmt_repr(',modelName={}', self.modelName)
rep += fmt_repr(',serialString={}', self.serialString)
rep += fmt_flags_repr(',permittedAccess={}', VmbAccessMode, self.permittedAccess)
rep += fmt_repr(',interfaceIdString={}', self.interfaceIdString)
rep += ')'
return rep
class VmbFeatureInfo(ctypes.Structure):
"""
Feature information. Holds read-only information about a feature.
Fields:
name - Type: c_char_p
Info: Name used in the API
featureDataType - Type: VmbFeatureData (VmbUint32)
Info: Data type of this feature
featureFlags - Type: VmbFeatureFlags (VmbUint32)
Info: Access flags for this feature
category - Type: c_char_p
Info: Category this feature can be found in
displayName - Type: c_char_p
Info: Feature name to be used in GUIs
pollingTime - Type: VmbUint32
Info: Predefined polling time for volatile
features
unit - Type: c_char_p
Info: Measuring unit as given in the XML file
representation - Type: c_char_p
Info: Representation of a numeric feature
visibility - Type: VmbFeatureVisibility (VmbUint32)
Info: GUI visibility
tooltip - Type: c_char_p
Info: Short description, e.g. for a tooltip
description - Type: c_char_p
Info: Longer description
sfncNamespace - Type: c_char_p
Info: Namespace this feature resides in
isStreamable - Type: VmbBool
Info: Indicates if a feature can be stored
to / loaded from a file
hasAffectedFeatures - Type: VmbBool
Info: Indicates if the feature potentially
affects other features
hasSelectedFeatures - Type: VmbBool
Info: Indicates if the feature selects other
features
"""
_fields_ = [
("name", c_char_p),
("featureDataType", VmbUint32),
("featureFlags", VmbUint32),
("category", c_char_p),
("displayName", c_char_p),
("pollingTime", VmbUint32),
("unit", c_char_p),
("representation", c_char_p),
("visibility", VmbUint32),
("tooltip", c_char_p),
("description", c_char_p),
("sfncNamespace", c_char_p),
("isStreamable", VmbBool),
("hasAffectedFeatures", VmbBool),
("hasSelectedFeatures", VmbBool)
]
def __repr__(self):
rep = 'VmbFeatureInfo'
rep += fmt_repr('(name={}', self.name)
rep += fmt_enum_repr(',featureDataType={}', VmbFeatureData, self.featureDataType)
rep += fmt_flags_repr(',featureFlags={}', VmbFeatureFlags, self.featureFlags)
rep += fmt_repr(',category={}', self.category)
rep += fmt_repr(',displayName={}', self.displayName)
rep += fmt_repr(',pollingTime={}', self.pollingTime)
rep += fmt_repr(',unit={}', self.unit)
rep += fmt_repr(',representation={}', self.representation)
rep += fmt_enum_repr(',visibility={}', VmbFeatureVisibility, self.visibility)
rep += fmt_repr(',tooltip={}', self.tooltip)
rep += fmt_repr(',description={}', self.description)
rep += fmt_repr(',sfncNamespace={}', self.sfncNamespace)
rep += fmt_repr(',isStreamable={}', self.isStreamable)
rep += fmt_repr(',hasAffectedFeatures={}', self.hasAffectedFeatures)
rep += fmt_repr(',hasSelectedFeatures={}', self.hasSelectedFeatures)
rep += ')'
return rep
class VmbFeatureEnumEntry(ctypes.Structure):
"""
Info about possible entries of an enumeration feature:
Fields:
name - Type: c_char_p
Info: Name used in the API
displayName - Type: c_char_p
Info: Enumeration entry name to be used in GUIs
visibility - Type: VmbFeatureVisibility (VmbUint32)
Info: GUI visibility
tooltip - Type: c_char_p
Info: Short description, e.g. for a tooltip
description - Type: c_char_p
Info: Longer description
sfncNamespace - Type: c_char_p
Info: Namespace this feature resides in
intValue - Type: VmbInt64
Info: Integer value of this enumeration entry
"""
_fields_ = [
("name", c_char_p),
("displayName", c_char_p),
("visibility", VmbUint32),
("tooltip", c_char_p),
("description", c_char_p),
("sfncNamespace", c_char_p),
("intValue", VmbInt64)
]
def __repr__(self):
rep = 'VmbFeatureEnumEntry'
rep += fmt_repr('(name={}', self.name)
rep += fmt_repr(',displayName={}', self.displayName)
rep += fmt_enum_repr(',visibility={}', VmbFeatureVisibility, self.visibility)
rep += fmt_repr(',tooltip={}', self.tooltip)
rep += fmt_repr(',description={}', self.description)
rep += fmt_repr(',sfncNamespace={}', self.sfncNamespace)
rep += fmt_repr(',intValue={},', self.intValue)
rep += ')'
return rep
class VmbFrame(ctypes.Structure):
"""
Frame delivered by Camera
Fields (in):
buffer - Type: c_void_p
Info: Comprises image and ancillary data
bufferSize - Type: VmbUint32_t
Info: Size of the data buffer
context - Type: c_void_p[4]
Info: 4 void pointers that can be employed by the user
(e.g. for storing handles)
Fields (out):
receiveStatus - Type: VmbFrameStatus (VmbInt32)
Info: Resulting status of the receive operation
receiveFlags - Type: VmbFrameFlags (VmbUint32)
Info: Flags indicating which additional frame
information is available
imageSize - Type: VmbUint32
Info: Size of the image data inside the data buffer
ancillarySize - Type: VmbUint32
Info: Size of the ancillary data inside the
data buffer
pixelFormat - Type: VmbPixelFormat (VmbUint32)
Info: Pixel format of the image
width - Type: VmbUint32
Info: Width of an image
height - Type: VmbUint32
Info: Height of an image
offsetX - Type: VmbUint32
Info: Horizontal offset of an image
offsetY - Type: VmbUint32
Info: Vertical offset of an image
frameID - Type: VmbUint64
Info: Unique ID of this frame in this stream
timestamp - Type: VmbUint64
Info: Timestamp set by the camera
"""
_fields_ = [
("buffer", c_void_p),
("bufferSize", VmbUint32),
("context", c_void_p * 4),
("receiveStatus", VmbInt32),
("receiveFlags", VmbUint32),
("imageSize", VmbUint32),
("ancillarySize", VmbUint32),
("pixelFormat", VmbUint32),
("width", VmbUint32),
("height", VmbUint32),
("offsetX", VmbUint32),
("offsetY", VmbUint32),
("frameID", VmbUint64),
("timestamp", VmbUint64)
]
def __repr__(self):
rep = 'VmbFrame'
rep += fmt_repr('(buffer={}', self.buffer)
rep += fmt_repr(',bufferSize={}', self.bufferSize)
rep += fmt_repr(',context={}', self.context)
rep += fmt_enum_repr('receiveStatus: {}', VmbFrameStatus, self.receiveStatus)
rep += fmt_flags_repr(',receiveFlags={}', VmbFrameFlags, self.receiveFlags)
rep += fmt_repr(',imageSize={}', self.imageSize)
rep += fmt_repr(',ancillarySize={}', self.ancillarySize)
rep += fmt_enum_repr(',pixelFormat={}', VmbPixelFormat, self.pixelFormat)
rep += fmt_repr(',width={}', self.width)
rep += fmt_repr(',height={}', self.height)
rep += fmt_repr(',offsetX={}', self.offsetX)
rep += fmt_repr(',offsetY={}', self.offsetY)
rep += fmt_repr(',frameID={}', self.frameID)
rep += fmt_repr(',timestamp={}', self.timestamp)
rep += ')'
return rep
def deepcopy_skip_ptr(self, memo):
result = VmbFrame()
memo[id(self)] = result
result.buffer = None
result.bufferSize = 0
result.context = (None, None, None, None)
setattr(result, 'receiveStatus', copy.deepcopy(self.receiveStatus, memo))
setattr(result, 'receiveFlags', copy.deepcopy(self.receiveFlags, memo))
setattr(result, 'imageSize', copy.deepcopy(self.imageSize, memo))
setattr(result, 'ancillarySize', copy.deepcopy(self.ancillarySize, memo))
setattr(result, 'pixelFormat', copy.deepcopy(self.pixelFormat, memo))
setattr(result, 'width', copy.deepcopy(self.width, memo))
setattr(result, 'height', copy.deepcopy(self.height, memo))
setattr(result, 'offsetX', copy.deepcopy(self.offsetX, memo))
setattr(result, 'offsetY', copy.deepcopy(self.offsetY, memo))
setattr(result, 'frameID', copy.deepcopy(self.frameID, memo))
setattr(result, 'timestamp', copy.deepcopy(self.timestamp, memo))
return result
class VmbFeaturePersistSettings(ctypes.Structure):
"""
Parameters determining the operation mode of VmbCameraSettingsSave
and VmbCameraSettingsLoad
Fields:
persistType - Type: VmbFeaturePersist (VmbUint32)
Info: Type of features that are to be saved
maxIterations - Type: VmbUint32
Info: Number of iterations when loading settings
loggingLevel - Type: VmbUint32
Info: Determines level of detail for load/save
settings logging
"""
_fields_ = [
("persistType", VmbUint32),
("maxIterations", VmbUint32),
("loggingLevel", VmbUint32)
]
def __repr__(self):
rep = 'VmbFrame'
rep += fmt_enum_repr('(persistType={}', VmbFeaturePersist, self.persistType)
rep += fmt_repr(',maxIterations={}', self.maxIterations)
rep += fmt_repr(',loggingLevel={}', self.loggingLevel)
rep += ')'
return rep
G_VIMBA_C_HANDLE = VmbHandle(1)
VIMBA_C_VERSION = None
EXPECTED_VIMBA_C_VERSION = '1.9.0'
# For detailed information on the signatures see "VimbaC.h"
# To improve readability, suppress 'E501 line too long (> 100 characters)'
# check of flake8
_SIGNATURES = {
'VmbVersionQuery': (VmbError, [c_ptr(VmbVersionInfo), VmbUint32]),
'VmbStartup': (VmbError, None),
'VmbShutdown': (None, None),
'VmbCamerasList': (VmbError, [c_ptr(VmbCameraInfo), VmbUint32, c_ptr(VmbUint32), VmbUint32]),
'VmbCameraInfoQuery': (VmbError, [c_str, c_ptr(VmbCameraInfo), VmbUint32]),
'VmbCameraOpen': (VmbError, [c_str, VmbAccessMode, c_ptr(VmbHandle)]),
'VmbCameraClose': (VmbError, [VmbHandle]),
'VmbFeaturesList': (VmbError, [VmbHandle, c_ptr(VmbFeatureInfo), VmbUint32, c_ptr(VmbUint32), VmbUint32]), # noqa: E501
'VmbFeatureInfoQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbFeatureInfo), VmbUint32]),
'VmbFeatureListAffected': (VmbError, [VmbHandle, c_str, c_ptr(VmbFeatureInfo), VmbUint32, c_ptr(VmbUint32), VmbUint32]), # noqa: E501
'VmbFeatureListSelected': (VmbError, [VmbHandle, c_str, c_ptr(VmbFeatureInfo), VmbUint32, c_ptr(VmbUint32), VmbUint32]), # noqa: E501
'VmbFeatureAccessQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbBool), c_ptr(VmbBool)]),
'VmbFeatureIntGet': (VmbError, [VmbHandle, c_str, c_ptr(VmbInt64)]),
'VmbFeatureIntSet': (VmbError, [VmbHandle, c_str, VmbInt64]),
'VmbFeatureIntRangeQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbInt64), c_ptr(VmbInt64)]), # noqa: E501
'VmbFeatureIntIncrementQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbInt64)]),
'VmbFeatureFloatGet': (VmbError, [VmbHandle, c_str, c_ptr(VmbDouble)]),
'VmbFeatureFloatSet': (VmbError, [VmbHandle, c_str, VmbDouble]),
'VmbFeatureFloatRangeQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbDouble), c_ptr(VmbDouble)]),
'VmbFeatureFloatIncrementQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbBool), c_ptr(VmbDouble)]), # noqa: E501
'VmbFeatureEnumGet': (VmbError, [VmbHandle, c_str, c_ptr(c_str)]),
'VmbFeatureEnumSet': (VmbError, [VmbHandle, c_str, c_str]),
'VmbFeatureEnumRangeQuery': (VmbError, [VmbHandle, c_str, c_ptr(c_str), VmbUint32, c_ptr(VmbUint32)]), # noqa: E501
'VmbFeatureEnumIsAvailable': (VmbError, [VmbHandle, c_str, c_str, c_ptr(VmbBool)]),
'VmbFeatureEnumAsInt': (VmbError, [VmbHandle, c_str, c_str, c_ptr(VmbInt64)]),
'VmbFeatureEnumAsString': (VmbError, [VmbHandle, c_str, VmbInt64, c_ptr(c_str)]),
'VmbFeatureEnumEntryGet': (VmbError, [VmbHandle, c_str, c_str, c_ptr(VmbFeatureEnumEntry), VmbUint32]), # noqa: E501
'VmbFeatureStringGet': (VmbError, [VmbHandle, c_str, c_str, VmbUint32, c_ptr(VmbUint32)]), # noqa: E501
'VmbFeatureStringSet': (VmbError, [VmbHandle, c_str, c_str]),
'VmbFeatureStringMaxlengthQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbUint32)]),
'VmbFeatureBoolGet': (VmbError, [VmbHandle, c_str, c_ptr(VmbBool)]),
'VmbFeatureBoolSet': (VmbError, [VmbHandle, c_str, VmbBool]),
'VmbFeatureCommandRun': (VmbError, [VmbHandle, c_str]),
'VmbFeatureCommandIsDone': (VmbError, [VmbHandle, c_str, c_ptr(VmbBool)]),
'VmbFeatureRawGet': (VmbError, [VmbHandle, c_str, c_str, VmbUint32, c_ptr(VmbUint32)]),
'VmbFeatureRawSet': (VmbError, [VmbHandle, c_str, c_str, VmbUint32]),
'VmbFeatureRawLengthQuery': (VmbError, [VmbHandle, c_str, c_ptr(VmbUint32)]),
'VmbFeatureInvalidationRegister': (VmbError, [VmbHandle, c_str, c_void_p, c_void_p]), # noqa: E501
'VmbFeatureInvalidationUnregister': (VmbError, [VmbHandle, c_str, c_void_p]),
'VmbFrameAnnounce': (VmbError, [VmbHandle, c_ptr(VmbFrame), VmbUint32]),
'VmbFrameRevoke': (VmbError, [VmbHandle, c_ptr(VmbFrame)]),
'VmbFrameRevokeAll': (VmbError, [VmbHandle]),
'VmbCaptureStart': (VmbError, [VmbHandle]),
'VmbCaptureEnd': (VmbError, [VmbHandle]),
'VmbCaptureFrameQueue': (VmbError, [VmbHandle, c_ptr(VmbFrame), c_void_p]),
'VmbCaptureFrameWait': (VmbError, [VmbHandle, c_ptr(VmbFrame), VmbUint32]),
'VmbCaptureQueueFlush': (VmbError, [VmbHandle]),
'VmbInterfacesList': (VmbError, [c_ptr(VmbInterfaceInfo), VmbUint32, c_ptr(VmbUint32), VmbUint32]), # noqa: E501
'VmbInterfaceOpen': (VmbError, [c_str, c_ptr(VmbHandle)]),
'VmbInterfaceClose': (VmbError, [VmbHandle]),
'VmbAncillaryDataOpen': (VmbError, [c_ptr(VmbFrame), c_ptr(VmbHandle)]),
'VmbAncillaryDataClose': (VmbError, [VmbHandle]),
'VmbMemoryRead': (VmbError, [VmbHandle, VmbUint64, VmbUint32, c_str, c_ptr(VmbUint32)]),
'VmbMemoryWrite': (VmbError, [VmbHandle, VmbUint64, VmbUint32, c_str, c_ptr(VmbUint32)]),
'VmbRegistersRead': (VmbError, [VmbHandle, VmbUint32, c_ptr(VmbUint64), c_ptr(VmbUint64), c_ptr(VmbUint32)]), # noqa: E501
'VmbRegistersWrite': (VmbError, [VmbHandle, VmbUint32, c_ptr(VmbUint64), c_ptr(VmbUint64), c_ptr(VmbUint32)]), # noqa: E501
'VmbCameraSettingsSave': (VmbError, [VmbHandle, c_str, c_ptr(VmbFeaturePersistSettings), VmbUint32]), # noqa: E501
'VmbCameraSettingsLoad': (VmbError, [VmbHandle, c_str, c_ptr(VmbFeaturePersistSettings), VmbUint32]) # noqa: E501
}
def _attach_signatures(lib_handle):
global _SIGNATURES
for function_name, signature in _SIGNATURES.items():
fn = getattr(lib_handle, function_name)
fn.restype, fn.argtypes = signature
fn.errcheck = _eval_vmberror
return lib_handle
def _check_version(lib_handle):
global EXPECTED_VIMBA_C_VERSION
global VIMBA_C_VERSION
v = VmbVersionInfo()
lib_handle.VmbVersionQuery(byref(v), sizeof(v))
VIMBA_C_VERSION = str(v)
loaded_version = (v.major, v.minor, v.patch)
expected_version = tuple(map(int, EXPECTED_VIMBA_C_VERSION.split(".")))
# major and minor version must be equal, patch version may be equal or greater
if not(loaded_version[0:2] == expected_version[0:2] and
loaded_version[2] >= expected_version[2]):
msg = 'Invalid VimbaC Version: Expected: {}, Found:{}'
raise VimbaSystemError(msg.format(EXPECTED_VIMBA_C_VERSION, VIMBA_C_VERSION))
return lib_handle
def _eval_vmberror(result: VmbError, func: Callable[..., Any], *args: Tuple[Any, ...]):
if result not in (VmbError.Success, None):
raise VimbaCError(result)
_lib_instance = _check_version(_attach_signatures(load_vimba_lib('VimbaC')))
@TraceEnable()
def call_vimba_c(func_name: str, *args):
"""This function encapsulates the entire VimbaC access.
For Details on valid function signatures see the 'VimbaC.h'.
Arguments:
func_name: The function name from VimbaC to be called.
args: Varargs passed directly to the underlaying C-Function.
Raises:
TypeError if given are do not match the signature of the function.
AttributeError if func with name 'func_name' does not exist.
VimbaCError if the function call is valid but neither None or VmbError.Success was returned.
The following functions of VimbaC can be executed:
VmbVersionQuery
VmbStartup
VmbShutdown
VmbCamerasList
VmbCameraInfoQuery
VmbCameraOpen
VmbCameraClose
VmbFeaturesList
VmbFeatureInfoQuery
VmbFeatureListAffected
VmbFeatureListSelected
VmbFeatureAccessQuery
VmbFeatureIntGet
VmbFeatureIntSet
VmbFeatureIntRangeQuery
VmbFeatureIntIncrementQuery
VmbFeatureFloatGet
VmbFeatureFloatSet
VmbFeatureFloatRangeQuery
VmbFeatureFloatIncrementQuery
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
VmbCameraSettingsSave
VmbCameraSettingsLoad
"""
global _lib_instance
getattr(_lib_instance, func_name)(*args)
def build_callback_type(*args):
global _lib_instance
lib_type = type(_lib_instance)
if lib_type == ctypes.CDLL:
return ctypes.CFUNCTYPE(*args)
elif lib_type == ctypes.WinDLL:
return ctypes.WINFUNCTYPE(*args)
else:
raise VimbaSystemError('Unknown Library Type. Abort.')

View File

@@ -0,0 +1,611 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import ctypes
import enum
import os
import sys
import platform
import functools
from typing import Tuple, List
from ..error import VimbaSystemError
__all__ = [
'Int32Enum',
'Uint32Enum',
'VmbInt8',
'VmbUint8',
'VmbInt16',
'VmbUint16',
'VmbInt32',
'VmbUint32',
'VmbInt64',
'VmbUint64',
'VmbHandle',
'VmbBool',
'VmbUchar',
'VmbFloat',
'VmbDouble',
'VmbError',
'VimbaCError',
'VmbPixelFormat',
'decode_cstr',
'decode_flags',
'fmt_repr',
'fmt_enum_repr',
'fmt_flags_repr',
'load_vimba_lib'
]
# Types
class Int32Enum(enum.IntEnum):
@classmethod
def from_param(cls, obj):
return ctypes.c_int(obj)
class Uint32Enum(enum.IntEnum):
@classmethod
def from_param(cls, obj):
return ctypes.c_uint(obj)
# Aliases for vmb base types
VmbInt8 = ctypes.c_byte
VmbUint8 = ctypes.c_ubyte
VmbInt16 = ctypes.c_short
VmbUint16 = ctypes.c_ushort
VmbInt32 = ctypes.c_int
VmbUint32 = ctypes.c_uint
VmbInt64 = ctypes.c_longlong
VmbUint64 = ctypes.c_ulonglong
VmbHandle = ctypes.c_void_p
VmbBool = ctypes.c_bool
VmbUchar = ctypes.c_char
VmbFloat = ctypes.c_float
VmbDouble = ctypes.c_double
class VmbError(Int32Enum):
"""
Enum containing error types returned
Success - No error
InternalFault - Unexpected fault in VimbaC or driver
ApiNotStarted - VmbStartup() was not called before the current
command
NotFound - The designated instance (camera, feature etc.)
cannot be found
BadHandle - The given handle is not valid
DeviceNotOpen - Device was not opened for usage
InvalidAccess - Operation is invalid with the current access mode
BadParameter - One of the parameters is invalid (usually an illegal
pointer)
StructSize - The given struct size is not valid for this version
of the API
MoreData - More data available in a string/list than space is
provided
WrongType - Wrong feature type for this access function
InvalidValue - The value is not valid; Either out of bounds or not
an increment of the minimum
Timeout - Timeout during wait
Other - Other error
Resources - Resources not available (e.g. memory)
InvalidCall - Call is invalid in the current context (callback)
NoTL - No transport layers are found
NotImplemented_ - API feature is not implemented
NotSupported - API feature is not supported
Incomplete - A multiple registers read or write is partially
completed
IO - low level IO error in transport layer
"""
Success = 0
InternalFault = -1
ApiNotStarted = -2
NotFound = -3
BadHandle = -4
DeviceNotOpen = -5
InvalidAccess = -6
BadParameter = -7
StructSize = -8
MoreData = -9
WrongType = -10
InvalidValue = -11
Timeout = -12
Other = -13
Resources = -14
InvalidCall = -15
NoTL = -16
NotImplemented_ = -17
NotSupported = -18
Incomplete = -19
IO = -20
def __str__(self):
return self._name_
class _VmbPixel(Uint32Enum):
Mono = 0x01000000
Color = 0x02000000
class _VmbPixelOccupy(Uint32Enum):
Bit8 = 0x00080000
Bit10 = 0x000A0000
Bit12 = 0x000C0000
Bit14 = 0x000E0000
Bit16 = 0x00100000
Bit24 = 0x00180000
Bit32 = 0x00200000
Bit48 = 0x00300000
Bit64 = 0x00400000
class VmbPixelFormat(Uint32Enum):
"""
Enum containing Pixelformats
Mono formats:
Mono8 - Monochrome, 8 bits (PFNC:Mono8)
Mono10 - Monochrome, 10 bits in 16 bits (PFNC:Mono10)
Mono10p - Monochrome, 4x10 bits continuously packed in 40 bits
(PFNC:Mono10p)
Mono12 - Monochrome, 12 bits in 16 bits (PFNC:Mono12)
Mono12Packed - Monochrome, 2x12 bits in 24 bits (GEV:Mono12Packed)
Mono12p - Monochrome, 2x12 bits continuously packed in 24 bits
(PFNC:Mono12p)
Mono14 - Monochrome, 14 bits in 16 bits (PFNC:Mono14)
Mono16 - Monochrome, 16 bits (PFNC:Mono16)
Bayer formats:
BayerGR8 - Bayer-color, 8 bits, starting with GR line
(PFNC:BayerGR8)
BayerRG8 - Bayer-color, 8 bits, starting with RG line
(PFNC:BayerRG8)
BayerGB8 - Bayer-color, 8 bits, starting with GB line
(PFNC:BayerGB8)
BayerBG8 - Bayer-color, 8 bits, starting with BG line
(PFNC:BayerBG8)
BayerGR10 - Bayer-color, 10 bits in 16 bits, starting with GR
line (PFNC:BayerGR10)
BayerRG10 - Bayer-color, 10 bits in 16 bits, starting with RG
line (PFNC:BayerRG10)
BayerGB10 - Bayer-color, 10 bits in 16 bits, starting with GB
line (PFNC:BayerGB10)
BayerBG10 - Bayer-color, 10 bits in 16 bits, starting with BG
line (PFNC:BayerBG10)
BayerGR12 - Bayer-color, 12 bits in 16 bits, starting with GR
line (PFNC:BayerGR12)
BayerRG12 - Bayer-color, 12 bits in 16 bits, starting with RG
line (PFNC:BayerRG12)
BayerGB12 - Bayer-color, 12 bits in 16 bits, starting with GB
line (PFNC:BayerGB12)
BayerBG12 - Bayer-color, 12 bits in 16 bits, starting with BG
line (PFNC:BayerBG12)
BayerGR12Packed - Bayer-color, 2x12 bits in 24 bits, starting with GR
line (GEV:BayerGR12Packed)
BayerRG12Packed - Bayer-color, 2x12 bits in 24 bits, starting with RG
line (GEV:BayerRG12Packed)
BayerGB12Packed - Bayer-color, 2x12 bits in 24 bits, starting with GB
line (GEV:BayerGB12Packed)
BayerBG12Packed - Bayer-color, 2x12 bits in 24 bits, starting with BG
line (GEV:BayerBG12Packed)
BayerGR10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with GR line (PFNC:BayerGR10p)
BayerRG10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with RG line (PFNC:BayerRG10p)
BayerGB10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with GB line (PFNC:BayerGB10p)
BayerBG10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with BG line (PFNC:BayerBG10p)
BayerGR12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with GR line (PFNC:BayerGR12p)
BayerRG12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with RG line (PFNC:BayerRG12p)
BayerGB12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with GB line (PFNC:BayerGB12p)
BayerBG12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with BG line (PFNC:BayerBG12p)
BayerGR16 - Bayer-color, 16 bits, starting with GR line
(PFNC:BayerGR16)
BayerRG16 - Bayer-color, 16 bits, starting with RG line
(PFNC:BayerRG16)
BayerGB16 - Bayer-color, 16 bits, starting with GB line
(PFNC:BayerGB16)
BayerBG16 - Bayer-color, 16 bits, starting with BG line
(PFNC:BayerBG16)
RGB formats:
Rgb8 - RGB, 8 bits x 3 (PFNC:RGB8)
Bgr8 - BGR, 8 bits x 3 (PFNC:Bgr8)
Rgb10 - RGB, 10 bits in 16 bits x 3 (PFNC:RGB10)
Bgr10 - BGR, 10 bits in 16 bits x 3 (PFNC:BGR10)
Rgb12 - RGB, 12 bits in 16 bits x 3 (PFNC:RGB12)
Bgr12 - BGR, 12 bits in 16 bits x 3 (PFNC:BGR12)
Rgb14 - RGB, 14 bits in 16 bits x 3 (PFNC:RGB14)
Bgr14 - BGR, 14 bits in 16 bits x 3 (PFNC:BGR14)
Rgb16 - RGB, 16 bits x 3 (PFNC:RGB16)
Bgr16 - BGR, 16 bits x 3 (PFNC:BGR16)
RGBA formats:
Argb8 - ARGB, 8 bits x 4 (PFNC:RGBa8)
Rgba8 - RGBA, 8 bits x 4, legacy name
Bgra8 - BGRA, 8 bits x 4 (PFNC:BGRa8)
Rgba10 - RGBA, 10 bits in 16 bits x 4
Bgra10 - BGRA, 10 bits in 16 bits x 4
Rgba12 - RGBA, 12 bits in 16 bits x 4
Bgra12 - BGRA, 12 bits in 16 bits x 4
Rgba14 - RGBA, 14 bits in 16 bits x 4
Bgra14 - BGRA, 14 bits in 16 bits x 4
Rgba16 - RGBA, 16 bits x 4
Bgra16 - BGRA, 16 bits x 4
YUV/YCbCr formats:
Yuv411 - YUV 411 with 8 bits (GEV:YUV411Packed)
Yuv422 - YUV 422 with 8 bits (GEV:YUV422Packed)
Yuv444 - YUV 444 with 8 bits (GEV:YUV444Packed)
YCbCr411_8_CbYYCrYY - Y´CbCr 411 with 8 bits
(PFNC:YCbCr411_8_CbYYCrYY) - identical to Yuv411
YCbCr422_8_CbYCrY - Y´CbCr 422 with 8 bits
(PFNC:YCbCr422_8_CbYCrY) - identical to Yuv422
YCbCr8_CbYCr - Y´CbCr 444 with 8 bits
(PFNC:YCbCr8_CbYCr) - identical to Yuv444
"""
None_ = 0
Mono8 = _VmbPixel.Mono | _VmbPixelOccupy.Bit8 | 0x0001
Mono10 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0003
Mono10p = _VmbPixel.Mono | _VmbPixelOccupy.Bit10 | 0x0046
Mono12 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0005
Mono12Packed = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0006
Mono12p = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0047
Mono14 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0025
Mono16 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0007
BayerGR8 = _VmbPixel.Mono | _VmbPixelOccupy.Bit8 | 0x0008
BayerRG8 = _VmbPixel.Mono | _VmbPixelOccupy.Bit8 | 0x0009
BayerGB8 = _VmbPixel.Mono | _VmbPixelOccupy.Bit8 | 0x000A
BayerBG8 = _VmbPixel.Mono | _VmbPixelOccupy.Bit8 | 0x000B
BayerGR10 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x000C
BayerRG10 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x000D
BayerGB10 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x000E
BayerBG10 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x000F
BayerGR12 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0010
BayerRG12 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0011
BayerGB12 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0012
BayerBG12 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0013
BayerGR12Packed = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x002A
BayerRG12Packed = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x002B
BayerGB12Packed = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x002C
BayerBG12Packed = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x002D
BayerGR10p = _VmbPixel.Mono | _VmbPixelOccupy.Bit10 | 0x0056
BayerRG10p = _VmbPixel.Mono | _VmbPixelOccupy.Bit10 | 0x0058
BayerGB10p = _VmbPixel.Mono | _VmbPixelOccupy.Bit10 | 0x0054
BayerBG10p = _VmbPixel.Mono | _VmbPixelOccupy.Bit10 | 0x0052
BayerGR12p = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0057
BayerRG12p = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0059
BayerGB12p = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0055
BayerBG12p = _VmbPixel.Mono | _VmbPixelOccupy.Bit12 | 0x0053
BayerGR16 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x002E
BayerRG16 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x002F
BayerGB16 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0030
BayerBG16 = _VmbPixel.Mono | _VmbPixelOccupy.Bit16 | 0x0031
Rgb8 = _VmbPixel.Color | _VmbPixelOccupy.Bit24 | 0x0014
Bgr8 = _VmbPixel.Color | _VmbPixelOccupy.Bit24 | 0x0015
Rgb10 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x0018
Bgr10 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x0019
Rgb12 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x001A
Bgr12 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x001B
Rgb14 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x005E
Bgr14 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x004A
Rgb16 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x0033
Bgr16 = _VmbPixel.Color | _VmbPixelOccupy.Bit48 | 0x004B
Argb8 = _VmbPixel.Color | _VmbPixelOccupy.Bit32 | 0x0016
Rgba8 = Argb8
Bgra8 = _VmbPixel.Color | _VmbPixelOccupy.Bit32 | 0x0017
Rgba10 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x005F
Bgra10 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x004C
Rgba12 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x0061
Bgra12 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x004E
Rgba14 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x0063
Bgra14 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x0050
Rgba16 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x0064
Bgra16 = _VmbPixel.Color | _VmbPixelOccupy.Bit64 | 0x0051
Yuv411 = _VmbPixel.Color | _VmbPixelOccupy.Bit12 | 0x001E
Yuv422 = _VmbPixel.Color | _VmbPixelOccupy.Bit16 | 0x001F
Yuv444 = _VmbPixel.Color | _VmbPixelOccupy.Bit24 | 0x0020
YCbCr411_8_CbYYCrYY = _VmbPixel.Color | _VmbPixelOccupy.Bit12 | 0x003C
YCbCr422_8_CbYCrY = _VmbPixel.Color | _VmbPixelOccupy.Bit16 | 0x0043
YCbCr8_CbYCr = _VmbPixel.Color | _VmbPixelOccupy.Bit24 | 0x003A
def __str__(self):
return self._name_
class VimbaCError(Exception):
"""Error Type containing an error code from the C-Layer. This error code is highly context
sensitive. All wrapped C-Functions that do not return VmbError.Success or None must
raise a VimbaCError and the surrounding code must deal if the Error is possible.
"""
def __init__(self, c_error: VmbError):
super().__init__(repr(c_error))
self.__c_error = c_error
def __str__(self):
return repr(self)
def __repr__(self):
return 'VimbaCError({})'.format(repr(self.__c_error))
def get_error_code(self) -> VmbError:
""" Get contained Error Code """
return self.__c_error
# Utility Functions
def _split_into_powers_of_two(num: int) -> Tuple[int, ...]:
result = []
for mask in [1 << i for i in range(32)]:
if mask & num:
result.append(mask)
if not result:
result.append(0)
return tuple(result)
def _split_flags_into_enum(num: int, enum_type):
return [enum_type(val) for val in _split_into_powers_of_two(num)]
def _repr_flags_list(enum_type, flag_val: int):
values = _split_flags_into_enum(flag_val, enum_type)
if values:
def fold_func(acc, arg):
return '{} {}'.format(acc, repr(arg))
return functools.reduce(fold_func, values, '')
else:
return '{}'.format(repr(enum_type(0)))
def decode_cstr(val: bytes) -> str:
"""Converts c_char_p stored in interface structures to a str.
Arguments:
val - Byte sequence to convert into str.
Returns:
str represented by 'val'
"""
return val.decode() if val else ''
def decode_flags(enum_type, enum_val: int):
"""Splits C-styled bit mask into a set of flags from a given Enumeration.
Arguments:
enum_val - Bit mask to decode.
enum_type - Enum Type represented within 'enum_val'
Returns:
A set of all values of enum_type occurring in enum_val.
Raises:
Attribute error a set value is not within the given 'enum_type'.
"""
return tuple(_split_flags_into_enum(enum_val, enum_type))
def fmt_repr(fmt: str, val):
"""Append repr to a format string."""
return fmt.format(repr(val))
def fmt_enum_repr(fmt: str, enum_type, enum_val):
"""Append repr of a given enum type to a format string.
Arguments:
fmt - Format string
enum_type - Enum Type to construct.
enum_val - Enum value.
Returns:
formatted string
"""
return fmt.format(repr(enum_type(enum_val)))
def fmt_flags_repr(fmt: str, enum_type, enum_val):
"""Append repr of a c-style flag value in the form of a set containing
all bits set from a given enum_type.
Arguments:
fmt - Format string
enum_type - Enum Type to construct.
enum_val - Enum value.
Returns:
formatted string
"""
return fmt.format(_repr_flags_list(enum_type, enum_val))
def load_vimba_lib(vimba_project: str):
""" Load shared library shipped with the Vimba installation
Arguments:
vimba_project - Library name without prefix or extension
Return:
CDLL or WinDLL Handle on loaded library
Raises:
VimbaSystemError if given library could not be loaded.
"""
platform_handlers = {
'linux': _load_under_linux,
'win32': _load_under_windows
}
if sys.platform not in platform_handlers:
msg = 'Abort. Unsupported Platform ({}) detected.'
raise VimbaSystemError(msg.format(sys.platform))
return platform_handlers[sys.platform](vimba_project)
def _load_under_linux(vimba_project: str):
# Construct VimbaHome based on TL installation paths
path_list: List[str] = []
tl32_path = os.environ.get('GENICAM_GENTL32_PATH', "")
if tl32_path:
path_list += tl32_path.split(':')
tl64_path = os.environ.get('GENICAM_GENTL64_PATH', "")
if tl64_path:
path_list += tl64_path.split(':')
# Remove empty strings from path_list if there are any.
# Necessary because the GENICAM_GENTLXX_PATH variable might start with a :
path_list = [path for path in path_list if path]
# Early return if required variables are not set.
if not path_list:
raise VimbaSystemError('No TL detected. Please verify Vimba installation.')
vimba_home_candidates: List[str] = []
for path in path_list:
vimba_home = os.path.dirname(os.path.dirname(os.path.dirname(path)))
if vimba_home not in vimba_home_candidates:
vimba_home_candidates.append(vimba_home)
# Select the most likely directory from the candidates
vimba_home = _select_vimba_home(vimba_home_candidates)
arch = platform.machine()
# Linux x86 64 Bit (Requires additional interpreter version check)
if arch == 'x86_64':
dir_ = 'x86_64bit' if _is_python_64_bit() else 'x86_32bit'
# Linux x86 32 Bit
elif arch in ('i386', 'i686'):
dir_ = 'x86_32bit'
# Linux arm 64 Bit (Requires additional interpreter version check)
elif arch == 'aarch64':
dir_ = 'arm_64bit' if _is_python_64_bit() else 'arm_32bit'
# Linux arm 32 Bit:
elif arch == 'armv7l':
dir_ = 'arm_32bit'
else:
raise VimbaSystemError('Unknown Architecture \'{}\'. Abort'.format(arch))
lib_name = 'lib{}.so'.format(vimba_project)
lib_path = os.path.join(vimba_home, vimba_project, 'DynamicLib', dir_, lib_name)
try:
lib = ctypes.cdll.LoadLibrary(lib_path)
except OSError as e:
msg = 'Failed to load library \'{}\'. Please verify Vimba installation.'
raise VimbaSystemError(msg.format(lib_path)) from e
return lib
def _load_under_windows(vimba_project: str):
vimba_home = os.environ.get('VIMBA_HOME')
if vimba_home is None:
raise VimbaSystemError('Variable VIMBA_HOME not set. Please verify Vimba installation.')
load_64bit = True if (platform.machine() == 'AMD64') and _is_python_64_bit() else False
lib_name = '{}.dll'.format(vimba_project)
lib_path = os.path.join(vimba_home, vimba_project, 'Bin', 'Win64' if load_64bit else 'Win32',
lib_name)
try:
# Load Library with 64 Bit and use cdecl call convention
if load_64bit:
lib = ctypes.cdll.LoadLibrary(lib_path)
# Load Library with 32 Bit and use stdcall call convention
else:
# Tell mypy to ignore this line to allow type checking on both windows and linux as
# windll is not available on linux and would therefore produce an error there
lib = ctypes.windll.LoadLibrary(lib_path) # type: ignore
except OSError as e:
msg = 'Failed to load library \'{}\'. Please verify Vimba installation.'
raise VimbaSystemError(msg.format(lib_path)) from e
return lib
def _select_vimba_home(candidates: List[str]) -> str:
"""
Select the most likely candidate for VIMBA_HOME from the given list of
candidates
Arguments:
candidates - List of strings pointing to possible vimba home directories
Return:
Path that represents the most likely VIMBA_HOME directory
Raises:
VimbaSystemError if multiple VIMBA_HOME directories were found in candidates
"""
most_likely_candidates = []
for candidate in candidates:
if 'vimba' in candidate.lower():
most_likely_candidates.append(candidate)
if len(most_likely_candidates) == 0:
raise VimbaSystemError('No suitable Vimba installation found. The following paths '
'were considered: {}'.format(candidates))
elif len(most_likely_candidates) > 1:
raise VimbaSystemError('Multiple Vimba installations found. Can\'t decide which to select: '
'{}'.format(most_likely_candidates))
return most_likely_candidates[0]
def _is_python_64_bit() -> bool:
# Query if the currently running python interpreter is build as 64 bit binary.
# The default method of getting this information seems to be rather hacky
# (check if maxint > 2^32) but it seems to be the way to do this....
return True if sys.maxsize > 2**32 else False

View File

@@ -0,0 +1,569 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import ctypes
import sys
from ctypes import byref, sizeof, c_char_p, POINTER as c_ptr
from typing import Callable, Any, Tuple, Dict, List
from ..error import VimbaSystemError
from ..util import TraceEnable
from .vimba_common import Uint32Enum, VmbUint32, VmbInt32, VmbError, VmbFloat, VimbaCError, \
VmbPixelFormat, load_vimba_lib, fmt_repr, fmt_enum_repr
__all__ = [
'VmbBayerPattern',
'VmbEndianness',
'VmbAligment',
'VmbAPIInfo',
'VmbPixelLayout',
'VmbDebayerMode',
'VmbImage',
'VmbImageInfo',
'VmbTransformInfo',
'VIMBA_IMAGE_TRANSFORM_VERSION',
'EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION',
'call_vimba_image_transform',
'PIXEL_FORMAT_TO_LAYOUT',
'LAYOUT_TO_PIXEL_FORMAT',
'PIXEL_FORMAT_CONVERTIBILITY_MAP'
]
class VmbBayerPattern(Uint32Enum):
"""Enum defining BayerPatterns
Values:
RGGB - RGGB pattern, red pixel comes first
GBRG - RGGB pattern, green pixel of blue row comes first
GRBG - RGGB pattern, green pixel of red row comes first
BGGR - RGGB pattern, blue pixel comes first
CYGM - CYGM pattern, cyan pixel comes first in the first row, green in the second row
GMCY - CYGM pattern, green pixel comes first in the first row, cyan in the second row
CYMG - CYGM pattern, cyan pixel comes first in the first row, magenta in the second row
MGCY - CYGM pattern, magenta pixel comes first in the first row, cyan in the second row
LAST - Indicator for end of defined range
"""
RGGB = 0
GBRG = 1
GRBG = 2
BGGR = 3
CYGM = 128
GMCY = 129
CYMG = 130
MGCY = 131
LAST = 255
def __str__(self):
return self._name_
class VmbEndianness(Uint32Enum):
"""Enum defining Endian Formats
Values:
LITTLE - Little Endian
BIG - Big Endian
LAST - Indicator for end of defined range
"""
LITTLE = 0
BIG = 1
LAST = 255
def __str__(self):
return self._name_
class VmbAligment(Uint32Enum):
"""Enum defining image alignment
Values:
MSB - Alignment (pppp pppp pppp ....)
LSB - Alignment (.... pppp pppp pppp)
LAST - Indicator for end of defined range
"""
MSB = 0
LSB = 1
LAST = 255
def __str__(self):
return self._name_
class VmbAPIInfo(Uint32Enum):
"""API Info Types
Values:
ALL - All Infos
PLATFORM - Platform the API was built for
BUILD - Build Types (debug or release)
TECHNOLOGY - Special technology info
LAST - Indicator for end of defined range
"""
ALL = 0
PLATFORM = 1
BUILD = 2
TECHNOLOGY = 3
LAST = 4
def __str__(self):
return self._name_
class VmbPixelLayout(Uint32Enum):
"""Image Pixel Layout Information. C Header offers no further documentation."""
Mono = 0
MonoPacked = 1
Raw = 2
RawPacked = 3
RGB = 4
BGR = 5
RGBA = 6
BGRA = 7
YUV411 = 8
YUV422 = 9
YUV444 = 10
MonoP = 11
MonoPl = 12
RawP = 13
RawPl = 14
YYCbYYCr411 = 15
CbYYCrYY411 = YUV411,
YCbYCr422 = 16
CbYCrY422 = YUV422
YCbCr444 = 17
CbYCr444 = YUV444
LAST = 19
def __str__(self):
return self._name_
class VmbColorSpace(Uint32Enum):
"""Image Color space. C Header offers no further documentation."""
Undefined = 0
ITU_BT709 = 1
ITU_BT601 = 2
def __str__(self):
return self._name_
class VmbDebayerMode(Uint32Enum):
"""Debayer Mode. C Header offers no further documentation."""
Mode_2x2 = 0
Mode_3x3 = 1
Mode_LCAA = 2
Mode_LCAAV = 3
Mode_YUV422 = 4
def __str__(self):
return self._name_
class VmbTransformType(Uint32Enum):
"""TransformType Mode. C Header offers no further documentation."""
None_ = 0
DebayerMode = 1
ColorCorrectionMatrix = 2
GammaCorrection = 3
Offset = 4
Gain = 5
def __str__(self):
return self._name_
class VmbPixelInfo(ctypes.Structure):
"""Structure containing pixel information. Sadly c_header contains no more documentation"""
_fields_ = [
('BitsPerPixel', VmbUint32),
('BitsUsed', VmbUint32),
('Alignment', VmbUint32),
('Endianness', VmbUint32),
('PixelLayout', VmbUint32),
('BayerPattern', VmbUint32),
('Reserved', VmbUint32)
]
def __repr__(self):
rep = 'VmbPixelInfo'
rep += fmt_repr('(BitsPerPixel={}', self.BitsPerPixel)
rep += fmt_repr(',BitsUsed={}', self.BitsUsed)
rep += fmt_enum_repr(',Alignment={}', VmbAligment, self.Alignment)
rep += fmt_enum_repr(',Endianness={}', VmbEndianness, self.Endianness)
rep += fmt_enum_repr(',PixelLayout={}', VmbPixelLayout, self.PixelLayout)
rep += fmt_enum_repr(',BayerPattern={}', VmbBayerPattern, self.BayerPattern)
rep += fmt_enum_repr(',Reserved={}', VmbColorSpace, self.Reserved)
rep += ')'
return rep
class VmbImageInfo(ctypes.Structure):
"""Structure containing image information. Sadly c_header contains no more documentation"""
_fields_ = [
('Width', VmbUint32),
('Height', VmbUint32),
('Stride', VmbInt32),
('PixelInfo', VmbPixelInfo)
]
def __repr__(self):
rep = 'VmbImageInfo'
rep += fmt_repr('(Width={}', self.Width)
rep += fmt_repr(',Height={}', self.Height)
rep += fmt_repr(',Stride={}', self.Stride)
rep += fmt_repr(',PixelInfo={}', self.PixelInfo)
rep += ')'
return rep
class VmbImage(ctypes.Structure):
"""Structure containing image. Sadly c_header contains no more documentation"""
_fields_ = [
('Size', VmbUint32),
('Data', ctypes.c_void_p),
('ImageInfo', VmbImageInfo)
]
def __repr__(self):
rep = 'VmbImage'
rep += fmt_repr('(Size={}', self.Size)
rep += fmt_repr(',Data={}', self.Data)
rep += fmt_repr(',ImageInfo={}', self.ImageInfo)
rep += ')'
return rep
class VmbTransformParameterMatrix3x3(ctypes.Structure):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Matrix', VmbFloat * 9)
]
class VmbTransformParameterGamma(ctypes.Structure):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Gamma', VmbFloat)
]
class VmbTransformParameterDebayer(ctypes.Structure):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Method', VmbUint32)
]
class VmbTransformParameterOffset(ctypes.Structure):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Offset', VmbInt32)
]
class VmbTransformParameterGain(ctypes.Structure):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Gain', VmbUint32)
]
class VmbTransformParameter(ctypes.Union):
"""Sadly c_header contains no more documentation"""
_fields_ = [
('Matrix3x3', VmbTransformParameterMatrix3x3),
('Debayer', VmbTransformParameterDebayer),
('Gamma', VmbTransformParameterGamma),
('Offset', VmbTransformParameterOffset),
('Gain', VmbTransformParameterGain)
]
class VmbTransformInfo(ctypes.Structure):
"""Struct holding transformation information"""
_fields_ = [
('TransformType', VmbUint32),
('Parameter', VmbTransformParameter)
]
# API
VIMBA_IMAGE_TRANSFORM_VERSION = None
if sys.platform == 'linux':
EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION = '1.0'
else:
EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION = '1.6'
# For detailed information on the signatures see "VimbaImageTransform.h"
# To improve readability, suppress 'E501 line too long (> 100 characters)'
# check of flake8
_SIGNATURES = {
'VmbGetVersion': (VmbError, [c_ptr(VmbUint32)]),
'VmbGetErrorInfo': (VmbError, [VmbError, c_char_p, VmbUint32]),
'VmbGetApiInfoString': (VmbError, [VmbAPIInfo, c_char_p, VmbUint32]),
'VmbSetDebayerMode': (VmbError, [VmbDebayerMode, c_ptr(VmbTransformInfo)]),
'VmbSetColorCorrectionMatrix3x3': (VmbError, [c_ptr(VmbFloat), c_ptr(VmbTransformInfo)]),
'VmbSetGammaCorrection': (VmbError, [VmbFloat, c_ptr(VmbTransformInfo)]),
'VmbSetImageInfoFromPixelFormat': (VmbError, [VmbPixelFormat, VmbUint32, VmbUint32, c_ptr(VmbImage)]), # noqa: E501
'VmbSetImageInfoFromString': (VmbError, [c_char_p, VmbUint32, VmbUint32, VmbUint32, c_ptr(VmbImage)]), # noqa: E501
'VmbSetImageInfoFromInputParameters': (VmbError, [VmbPixelFormat, VmbUint32, VmbUint32, VmbPixelLayout, VmbUint32, c_ptr(VmbImage)]), # noqa: E501
'VmbSetImageInfoFromInputImage': (VmbError, [c_ptr(VmbImage), VmbPixelLayout, VmbUint32, c_ptr(VmbImage)]), # noqa: E501
'VmbImageTransform': (VmbError, [c_ptr(VmbImage), c_ptr(VmbImage), c_ptr(VmbTransformInfo), VmbUint32]) # noqa: E501
}
def _attach_signatures(lib_handle):
global _SIGNATURES
for function_name, signature in _SIGNATURES.items():
fn = getattr(lib_handle, function_name)
fn.restype, fn.argtypes = signature
fn.errcheck = _eval_vmberror
return lib_handle
def _check_version(lib_handle):
global EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION
global VIMBA_IMAGE_TRANSFORM_VERSION
v = VmbUint32()
lib_handle.VmbGetVersion(byref(v))
VIMBA_IMAGE_TRANSFORM_VERSION = '{}.{}'.format((v.value >> 24) & 0xff, (v.value >> 16) & 0xff)
loaded_version = tuple(map(int, VIMBA_IMAGE_TRANSFORM_VERSION.split(".")))
expected_version = tuple(map(int, EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION.split(".")))
# Major version must match. minor version may be equal or greater
if not(loaded_version[0] == expected_version[0] and
loaded_version[1] >= expected_version[1]):
msg = 'Invalid VimbaImageTransform Version: Expected: {}, Found:{}'
raise VimbaSystemError(msg.format(EXPECTED_VIMBA_IMAGE_TRANSFORM_VERSION,
VIMBA_IMAGE_TRANSFORM_VERSION))
return lib_handle
def _eval_vmberror(result: VmbError, func: Callable[..., Any], *args: Tuple[Any, ...]):
if result not in (VmbError.Success, None):
raise VimbaCError(result)
_lib_instance = _check_version(_attach_signatures(load_vimba_lib('VimbaImageTransform')))
@TraceEnable()
def call_vimba_image_transform(func_name: str, *args):
"""This function encapsulates the entire VimbaImageTransform access.
For Details on valid function signatures see the 'VimbaImageTransform.h'.
Arguments:
func_name: The function name from VimbaImageTransform to be called.
args: Varargs passed directly to the underlaying C-Function.
Raises:
TypeError if given are do not match the signature of the function.
AttributeError if func with name 'func_name' does not exist.
VimbaCError if the function call is valid but neither None or VmbError.Success was returned.
The following functions of VimbaImageTransform can be executed:
VmbGetVersion
VmbGetTechnoInfo
VmbGetErrorInfo
VmbGetApiInfoString
VmbSetDebayerMode
VmbSetColorCorrectionMatrix3x3
VmbSetGammaCorrection
VmbSetImageInfoFromPixelFormat
VmbSetImageInfoFromString
VmbSetImageInfoFromInputParameters
VmbSetImageInfoFromInputImage
VmbImageTransform
"""
global _lib_instance
getattr(_lib_instance, func_name)(*args)
PIXEL_FORMAT_TO_LAYOUT: Dict[VmbPixelFormat, Tuple[VmbPixelLayout, int]] = {
VmbPixelFormat.Mono8: (VmbPixelLayout.Mono, 8),
VmbPixelFormat.Mono10: (VmbPixelLayout.Mono, 16),
VmbPixelFormat.Mono12: (VmbPixelLayout.Mono, 16),
VmbPixelFormat.Mono14: (VmbPixelLayout.Mono, 16),
VmbPixelFormat.Mono16: (VmbPixelLayout.Mono, 16),
VmbPixelFormat.BayerGR8: (VmbPixelLayout.Raw, 8),
VmbPixelFormat.BayerRG8: (VmbPixelLayout.Raw, 8),
VmbPixelFormat.BayerGB8: (VmbPixelLayout.Raw, 8),
VmbPixelFormat.BayerBG8: (VmbPixelLayout.Raw, 8),
VmbPixelFormat.BayerGR10: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerRG10: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerGB10: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerBG10: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerGR12: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerRG12: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerGB12: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerBG12: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerGR16: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerRG16: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerGB16: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.BayerBG16: (VmbPixelLayout.Raw, 16),
VmbPixelFormat.Rgb8: (VmbPixelLayout.RGB, 8),
VmbPixelFormat.Rgb10: (VmbPixelLayout.RGB, 16),
VmbPixelFormat.Rgb12: (VmbPixelLayout.RGB, 16),
VmbPixelFormat.Rgb14: (VmbPixelLayout.RGB, 16),
VmbPixelFormat.Rgb16: (VmbPixelLayout.RGB, 16),
VmbPixelFormat.Bgr8: (VmbPixelLayout.BGR, 8),
VmbPixelFormat.Bgr10: (VmbPixelLayout.BGR, 16),
VmbPixelFormat.Bgr12: (VmbPixelLayout.BGR, 16),
VmbPixelFormat.Bgr14: (VmbPixelLayout.BGR, 16),
VmbPixelFormat.Bgr16: (VmbPixelLayout.BGR, 16),
VmbPixelFormat.Rgba8: (VmbPixelLayout.RGBA, 8),
VmbPixelFormat.Rgba10: (VmbPixelLayout.RGBA, 16),
VmbPixelFormat.Rgba12: (VmbPixelLayout.RGBA, 16),
VmbPixelFormat.Rgba14: (VmbPixelLayout.RGBA, 16),
VmbPixelFormat.Rgba16: (VmbPixelLayout.RGBA, 16),
VmbPixelFormat.Bgra8: (VmbPixelLayout.BGRA, 8),
VmbPixelFormat.Bgra10: (VmbPixelLayout.BGRA, 16),
VmbPixelFormat.Bgra12: (VmbPixelLayout.BGRA, 16),
VmbPixelFormat.Bgra14: (VmbPixelLayout.BGRA, 16),
VmbPixelFormat.Bgra16: (VmbPixelLayout.BGRA, 16)
}
LAYOUT_TO_PIXEL_FORMAT = dict([(v, k) for k, v in PIXEL_FORMAT_TO_LAYOUT.items()])
def _query_compatibility(pixel_format: VmbPixelFormat) -> Tuple[VmbPixelFormat, ...]:
global LAYOUT_TO_PIXEL_FORMAT
# Query compatible formats from ImageTransform
output_pixel_layouts = (VmbPixelLayout.Mono, VmbPixelLayout.MonoPacked, VmbPixelLayout.Raw,
VmbPixelLayout.RawPacked, VmbPixelLayout.RGB, VmbPixelLayout.BGR,
VmbPixelLayout.RGBA, VmbPixelLayout.BGRA)
output_bits_per_pixel = (8, 16)
output_layouts = tuple([(layouts, bits)
for layouts in output_pixel_layouts
for bits in output_bits_per_pixel])
result: List[VmbPixelFormat] = []
src_image = VmbImage()
src_image.Size = sizeof(src_image)
call_vimba_image_transform('VmbSetImageInfoFromPixelFormat', pixel_format, 0, 0,
byref(src_image))
dst_image = VmbImage()
dst_image.Size = sizeof(dst_image)
for layout, bits in output_layouts:
try:
call_vimba_image_transform('VmbSetImageInfoFromInputImage', byref(src_image), layout,
bits, byref(dst_image))
fmt = LAYOUT_TO_PIXEL_FORMAT[(layout, bits)]
if fmt not in result:
result.append(fmt)
except VimbaCError as e:
if e.get_error_code() not in (VmbError.NotImplemented_, VmbError.BadParameter):
raise e
return tuple(result)
PIXEL_FORMAT_CONVERTIBILITY_MAP: Dict[VmbPixelFormat, Tuple[VmbPixelFormat, ...]] = {
VmbPixelFormat.Mono8: _query_compatibility(VmbPixelFormat.Mono8),
VmbPixelFormat.Mono10: _query_compatibility(VmbPixelFormat.Mono10),
VmbPixelFormat.Mono10p: _query_compatibility(VmbPixelFormat.Mono10p),
VmbPixelFormat.Mono12: _query_compatibility(VmbPixelFormat.Mono12),
VmbPixelFormat.Mono12Packed: _query_compatibility(VmbPixelFormat.Mono12Packed),
VmbPixelFormat.Mono12p: _query_compatibility(VmbPixelFormat.Mono12p),
VmbPixelFormat.Mono14: _query_compatibility(VmbPixelFormat.Mono14),
VmbPixelFormat.Mono16: _query_compatibility(VmbPixelFormat.Mono16),
VmbPixelFormat.BayerGR8: _query_compatibility(VmbPixelFormat.BayerGR8),
VmbPixelFormat.BayerRG8: _query_compatibility(VmbPixelFormat.BayerRG8),
VmbPixelFormat.BayerGB8: _query_compatibility(VmbPixelFormat.BayerGB8),
VmbPixelFormat.BayerBG8: _query_compatibility(VmbPixelFormat.BayerBG8),
VmbPixelFormat.BayerGR10: _query_compatibility(VmbPixelFormat.BayerGR10),
VmbPixelFormat.BayerRG10: _query_compatibility(VmbPixelFormat.BayerRG10),
VmbPixelFormat.BayerGB10: _query_compatibility(VmbPixelFormat.BayerGB10),
VmbPixelFormat.BayerBG10: _query_compatibility(VmbPixelFormat.BayerBG10),
VmbPixelFormat.BayerGR12: _query_compatibility(VmbPixelFormat.BayerGR12),
VmbPixelFormat.BayerRG12: _query_compatibility(VmbPixelFormat.BayerRG12),
VmbPixelFormat.BayerGB12: _query_compatibility(VmbPixelFormat.BayerGB12),
VmbPixelFormat.BayerBG12: _query_compatibility(VmbPixelFormat.BayerBG12),
VmbPixelFormat.BayerGR12Packed: _query_compatibility(VmbPixelFormat.BayerGR12Packed),
VmbPixelFormat.BayerRG12Packed: _query_compatibility(VmbPixelFormat.BayerRG12Packed),
VmbPixelFormat.BayerGB12Packed: _query_compatibility(VmbPixelFormat.BayerGB12Packed),
VmbPixelFormat.BayerBG12Packed: _query_compatibility(VmbPixelFormat.BayerBG12Packed),
VmbPixelFormat.BayerGR10p: _query_compatibility(VmbPixelFormat.BayerGR10p),
VmbPixelFormat.BayerRG10p: _query_compatibility(VmbPixelFormat.BayerRG10p),
VmbPixelFormat.BayerGB10p: _query_compatibility(VmbPixelFormat.BayerGB10p),
VmbPixelFormat.BayerBG10p: _query_compatibility(VmbPixelFormat.BayerBG10p),
VmbPixelFormat.BayerGR12p: _query_compatibility(VmbPixelFormat.BayerGR12p),
VmbPixelFormat.BayerRG12p: _query_compatibility(VmbPixelFormat.BayerRG12p),
VmbPixelFormat.BayerGB12p: _query_compatibility(VmbPixelFormat.BayerGB12p),
VmbPixelFormat.BayerBG12p: _query_compatibility(VmbPixelFormat.BayerBG12p),
VmbPixelFormat.BayerGR16: _query_compatibility(VmbPixelFormat.BayerGR16),
VmbPixelFormat.BayerRG16: _query_compatibility(VmbPixelFormat.BayerRG16),
VmbPixelFormat.BayerGB16: _query_compatibility(VmbPixelFormat.BayerGB16),
VmbPixelFormat.BayerBG16: _query_compatibility(VmbPixelFormat.BayerBG16),
VmbPixelFormat.Rgb8: _query_compatibility(VmbPixelFormat.Rgb8),
VmbPixelFormat.Bgr8: _query_compatibility(VmbPixelFormat.Bgr8),
VmbPixelFormat.Rgb10: _query_compatibility(VmbPixelFormat.Rgb10),
VmbPixelFormat.Bgr10: _query_compatibility(VmbPixelFormat.Bgr10),
VmbPixelFormat.Rgb12: _query_compatibility(VmbPixelFormat.Rgb12),
VmbPixelFormat.Bgr12: _query_compatibility(VmbPixelFormat.Bgr12),
VmbPixelFormat.Rgb14: _query_compatibility(VmbPixelFormat.Rgb14),
VmbPixelFormat.Bgr14: _query_compatibility(VmbPixelFormat.Bgr14),
VmbPixelFormat.Rgb16: _query_compatibility(VmbPixelFormat.Rgb16),
VmbPixelFormat.Bgr16: _query_compatibility(VmbPixelFormat.Bgr16),
VmbPixelFormat.Argb8: _query_compatibility(VmbPixelFormat.Argb8),
VmbPixelFormat.Rgba8: _query_compatibility(VmbPixelFormat.Rgba8),
VmbPixelFormat.Bgra8: _query_compatibility(VmbPixelFormat.Bgra8),
VmbPixelFormat.Rgba10: _query_compatibility(VmbPixelFormat.Rgba10),
VmbPixelFormat.Bgra10: _query_compatibility(VmbPixelFormat.Bgra10),
VmbPixelFormat.Rgba12: _query_compatibility(VmbPixelFormat.Rgba12),
VmbPixelFormat.Bgra12: _query_compatibility(VmbPixelFormat.Bgra12),
VmbPixelFormat.Rgba14: _query_compatibility(VmbPixelFormat.Rgba14),
VmbPixelFormat.Bgra14: _query_compatibility(VmbPixelFormat.Bgra14),
VmbPixelFormat.Rgba16: _query_compatibility(VmbPixelFormat.Rgba16),
VmbPixelFormat.Bgra16: _query_compatibility(VmbPixelFormat.Bgra16),
VmbPixelFormat.Yuv411: _query_compatibility(VmbPixelFormat.Yuv411),
VmbPixelFormat.Yuv422: _query_compatibility(VmbPixelFormat.Yuv422),
VmbPixelFormat.Yuv444: _query_compatibility(VmbPixelFormat.Yuv444),
VmbPixelFormat.YCbCr411_8_CbYYCrYY: _query_compatibility(VmbPixelFormat.YCbCr411_8_CbYYCrYY),
VmbPixelFormat.YCbCr422_8_CbYCrY: _query_compatibility(VmbPixelFormat.YCbCr422_8_CbYCrY),
VmbPixelFormat.YCbCr8_CbYCr: _query_compatibility(VmbPixelFormat.YCbCr8_CbYCr)
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
from .util import Log
__all__ = [
'VimbaSystemError',
'VimbaCameraError',
'VimbaInterfaceError',
'VimbaFeatureError',
'VimbaFrameError',
'VimbaTimeout'
]
class _LoggedError(Exception):
def __init__(self, msg: str):
super().__init__(msg)
Log.get_instance().error(msg)
class VimbaSystemError(_LoggedError):
"""Errors related to the underlying Vimba System
Error type to indicate system-wide errors like:
- Incomplete Vimba installation
- Incompatible version of the underlying C-Layer
- An unsupported OS
"""
pass
class VimbaCameraError(_LoggedError):
"""Errors related to cameras
Error Type to indicated camera-related errors like:
- Access of a disconnected Camera object
- Lookup of non-existing cameras
"""
pass
class VimbaInterfaceError(_LoggedError):
"""Errors related to Interfaces
Error Type to indicated interface-related errors like:
- Access on a disconnected Interface object
- Lookup of a non-existing Interface
"""
pass
class VimbaFeatureError(_LoggedError):
"""Error related to Feature access.
Error type to indicate invalid Feature access like:
- Invalid access mode on Feature access.
- Out of range values upon setting a value.
- Failed lookup of features.
"""
pass
class VimbaFrameError(_LoggedError):
"""Error related to Frame data"""
pass
class VimbaTimeout(_LoggedError):
"""Indicates that an operation timed out."""
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,923 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import enum
import ctypes
import copy
import functools
from typing import Optional, Tuple
from .c_binding import byref, sizeof, decode_flags
from .c_binding import call_vimba_c, call_vimba_image_transform, VmbFrameStatus, VmbFrameFlags, \
VmbFrame, VmbHandle, VmbPixelFormat, VmbImage, VmbDebayerMode, \
VmbTransformInfo, PIXEL_FORMAT_CONVERTIBILITY_MAP, PIXEL_FORMAT_TO_LAYOUT
from .feature import FeaturesTuple, FeatureTypes, FeatureTypeTypes, discover_features
from .shared import filter_features_by_name, filter_features_by_type, filter_features_by_category, \
attach_feature_accessors, remove_feature_accessors
from .util import TraceEnable, RuntimeTypeCheckEnable, EnterContextOnCall, LeaveContextOnCall, \
RaiseIfOutsideContext
from .error import VimbaFrameError, VimbaFeatureError
try:
import numpy # type: ignore
except ModuleNotFoundError:
numpy = None # type: ignore
__all__ = [
'PixelFormat',
'MONO_PIXEL_FORMATS',
'BAYER_PIXEL_FORMATS',
'RGB_PIXEL_FORMATS',
'RGBA_PIXEL_FORMATS',
'BGR_PIXEL_FORMATS',
'BGRA_PIXEL_FORMATS',
'YUV_PIXEL_FORMATS',
'YCBCR_PIXEL_FORMATS',
'COLOR_PIXEL_FORMATS',
'OPENCV_PIXEL_FORMATS',
'FrameStatus',
'Debayer',
'Frame',
'FrameTuple',
'FormatTuple',
'intersect_pixel_formats'
]
# Forward declarations
FrameTuple = Tuple['Frame', ...]
FormatTuple = Tuple['PixelFormat', ...]
class PixelFormat(enum.IntEnum):
"""Enum specifying all PixelFormats. Note: Not all Cameras support all Pixelformats.
Mono formats:
Mono8 - Monochrome, 8 bits (PFNC:Mono8)
Mono10 - Monochrome, 10 bits in 16 bits (PFNC:Mono10)
Mono10p - Monochrome, 4x10 bits continuously packed in 40 bits
(PFNC:Mono10p)
Mono12 - Monochrome, 12 bits in 16 bits (PFNC:Mono12)
Mono12Packed - Monochrome, 2x12 bits in 24 bits (GEV:Mono12Packed)
Mono12p - Monochrome, 2x12 bits continuously packed in 24 bits
(PFNC:Mono12p)
Mono14 - Monochrome, 14 bits in 16 bits (PFNC:Mono14)
Mono16 - Monochrome, 16 bits (PFNC:Mono16)
Bayer formats:
BayerGR8 - Bayer-color, 8 bits, starting with GR line
(PFNC:BayerGR8)
BayerRG8 - Bayer-color, 8 bits, starting with RG line
(PFNC:BayerRG8)
BayerGB8 - Bayer-color, 8 bits, starting with GB line
(PFNC:BayerGB8)
BayerBG8 - Bayer-color, 8 bits, starting with BG line
(PFNC:BayerBG8)
BayerGR10 - Bayer-color, 10 bits in 16 bits, starting with GR
line (PFNC:BayerGR10)
BayerRG10 - Bayer-color, 10 bits in 16 bits, starting with RG
line (PFNC:BayerRG10)
BayerGB10 - Bayer-color, 10 bits in 16 bits, starting with GB
line (PFNC:BayerGB10)
BayerBG10 - Bayer-color, 10 bits in 16 bits, starting with BG
line (PFNC:BayerBG10)
BayerGR12 - Bayer-color, 12 bits in 16 bits, starting with GR
line (PFNC:BayerGR12)
BayerRG12 - Bayer-color, 12 bits in 16 bits, starting with RG
line (PFNC:BayerRG12)
BayerGB12 - Bayer-color, 12 bits in 16 bits, starting with GB
line (PFNC:BayerGB12)
BayerBG12 - Bayer-color, 12 bits in 16 bits, starting with BG
line (PFNC:BayerBG12)
BayerGR12Packed - Bayer-color, 2x12 bits in 24 bits, starting with GR
line (GEV:BayerGR12Packed)
BayerRG12Packed - Bayer-color, 2x12 bits in 24 bits, starting with RG
line (GEV:BayerRG12Packed)
BayerGB12Packed - Bayer-color, 2x12 bits in 24 bits, starting with GB
line (GEV:BayerGB12Packed)
BayerBG12Packed - Bayer-color, 2x12 bits in 24 bits, starting with BG
line (GEV:BayerBG12Packed)
BayerGR10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with GR line (PFNC:BayerGR10p)
BayerRG10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with RG line (PFNC:BayerRG10p)
BayerGB10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with GB line (PFNC:BayerGB10p)
BayerBG10p - Bayer-color, 4x10 bits continuously packed in 40
bits, starting with BG line (PFNC:BayerBG10p)
BayerGR12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with GR line (PFNC:BayerGR12p)
BayerRG12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with RG line (PFNC:BayerRG12p)
BayerGB12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with GB line (PFNC:BayerGB12p)
BayerBG12p - Bayer-color, 2x12 bits continuously packed in 24
bits, starting with BG line (PFNC:BayerBG12p)
BayerGR16 - Bayer-color, 16 bits, starting with GR line
(PFNC:BayerGR16)
BayerRG16 - Bayer-color, 16 bits, starting with RG line
(PFNC:BayerRG16)
BayerGB16 - Bayer-color, 16 bits, starting with GB line
(PFNC:BayerGB16)
BayerBG16 - Bayer-color, 16 bits, starting with BG line
(PFNC:BayerBG16)
RGB formats:
Rgb8 - RGB, 8 bits x 3 (PFNC:RGB8)
Bgr8 - BGR, 8 bits x 3 (PFNC:Bgr8)
Rgb10 - RGB, 10 bits in 16 bits x 3 (PFNC:RGB10)
Bgr10 - BGR, 10 bits in 16 bits x 3 (PFNC:BGR10)
Rgb12 - RGB, 12 bits in 16 bits x 3 (PFNC:RGB12)
Bgr12 - BGR, 12 bits in 16 bits x 3 (PFNC:BGR12)
Rgb14 - RGB, 14 bits in 16 bits x 3 (PFNC:RGB14)
Bgr14 - BGR, 14 bits in 16 bits x 3 (PFNC:BGR14)
Rgb16 - RGB, 16 bits x 3 (PFNC:RGB16)
Bgr16 - BGR, 16 bits x 3 (PFNC:BGR16)
RGBA formats:
Argb8 - ARGB, 8 bits x 4 (PFNC:RGBa8)
Rgba8 - RGBA, 8 bits x 4, legacy name
Bgra8 - BGRA, 8 bits x 4 (PFNC:BGRa8)
Rgba10 - RGBA, 10 bits in 16 bits x 4
Bgra10 - BGRA, 10 bits in 16 bits x 4
Rgba12 - RGBA, 12 bits in 16 bits x 4
Bgra12 - BGRA, 12 bits in 16 bits x 4
Rgba14 - RGBA, 14 bits in 16 bits x 4
Bgra14 - BGRA, 14 bits in 16 bits x 4
Rgba16 - RGBA, 16 bits x 4
Bgra16 - BGRA, 16 bits x 4
YUV/YCbCr formats:
Yuv411 - YUV 411 with 8 bits (GEV:YUV411Packed)
Yuv422 - YUV 422 with 8 bits (GEV:YUV422Packed)
Yuv444 - YUV 444 with 8 bits (GEV:YUV444Packed)
YCbCr411_8_CbYYCrYY - Y´CbCr 411 with 8 bits
(PFNC:YCbCr411_8_CbYYCrYY) - identical to Yuv411
YCbCr422_8_CbYCrY - Y´CbCr 422 with 8 bits
(PFNC:YCbCr422_8_CbYCrY) - identical to Yuv422
YCbCr8_CbYCr - Y´CbCr 444 with 8 bits
(PFNC:YCbCr8_CbYCr) - identical to Yuv444
"""
# Mono Formats
Mono8 = VmbPixelFormat.Mono8
Mono10 = VmbPixelFormat.Mono10
Mono10p = VmbPixelFormat.Mono10p
Mono12 = VmbPixelFormat.Mono12
Mono12Packed = VmbPixelFormat.Mono12Packed
Mono12p = VmbPixelFormat.Mono12p
Mono14 = VmbPixelFormat.Mono14
Mono16 = VmbPixelFormat.Mono16
# Bayer Formats
BayerGR8 = VmbPixelFormat.BayerGR8
BayerRG8 = VmbPixelFormat.BayerRG8
BayerGB8 = VmbPixelFormat.BayerGB8
BayerBG8 = VmbPixelFormat.BayerBG8
BayerGR10 = VmbPixelFormat.BayerGR10
BayerRG10 = VmbPixelFormat.BayerRG10
BayerGB10 = VmbPixelFormat.BayerGB10
BayerBG10 = VmbPixelFormat.BayerBG10
BayerGR12 = VmbPixelFormat.BayerGR12
BayerRG12 = VmbPixelFormat.BayerRG12
BayerGB12 = VmbPixelFormat.BayerGB12
BayerBG12 = VmbPixelFormat.BayerBG12
BayerGR12Packed = VmbPixelFormat.BayerGR12Packed
BayerRG12Packed = VmbPixelFormat.BayerRG12Packed
BayerGB12Packed = VmbPixelFormat.BayerGB12Packed
BayerBG12Packed = VmbPixelFormat.BayerBG12Packed
BayerGR10p = VmbPixelFormat.BayerGR10p
BayerRG10p = VmbPixelFormat.BayerRG10p
BayerGB10p = VmbPixelFormat.BayerGB10p
BayerBG10p = VmbPixelFormat.BayerBG10p
BayerGR12p = VmbPixelFormat.BayerGR12p
BayerRG12p = VmbPixelFormat.BayerRG12p
BayerGB12p = VmbPixelFormat.BayerGB12p
BayerBG12p = VmbPixelFormat.BayerBG12p
BayerGR16 = VmbPixelFormat.BayerGR16
BayerRG16 = VmbPixelFormat.BayerRG16
BayerGB16 = VmbPixelFormat.BayerGB16
BayerBG16 = VmbPixelFormat.BayerBG16
# RGB Formats
Rgb8 = VmbPixelFormat.Rgb8
Bgr8 = VmbPixelFormat.Bgr8
Rgb10 = VmbPixelFormat.Rgb10
Bgr10 = VmbPixelFormat.Bgr10
Rgb12 = VmbPixelFormat.Rgb12
Bgr12 = VmbPixelFormat.Bgr12
Rgb14 = VmbPixelFormat.Rgb14
Bgr14 = VmbPixelFormat.Bgr14
Rgb16 = VmbPixelFormat.Rgb16
Bgr16 = VmbPixelFormat.Bgr16
# RGBA Formats
Rgba8 = VmbPixelFormat.Rgba8
Bgra8 = VmbPixelFormat.Bgra8
Argb8 = VmbPixelFormat.Argb8
Rgba10 = VmbPixelFormat.Rgba10
Bgra10 = VmbPixelFormat.Bgra10
Rgba12 = VmbPixelFormat.Rgba12
Bgra12 = VmbPixelFormat.Bgra12
Rgba14 = VmbPixelFormat.Rgba14
Bgra14 = VmbPixelFormat.Bgra14
Rgba16 = VmbPixelFormat.Rgba16
Bgra16 = VmbPixelFormat.Bgra16
Yuv411 = VmbPixelFormat.Yuv411
Yuv422 = VmbPixelFormat.Yuv422
Yuv444 = VmbPixelFormat.Yuv444
# YCbCr Formats
YCbCr411_8_CbYYCrYY = VmbPixelFormat.YCbCr411_8_CbYYCrYY
YCbCr422_8_CbYCrY = VmbPixelFormat.YCbCr422_8_CbYCrY
YCbCr8_CbYCr = VmbPixelFormat.YCbCr8_CbYCr
def __str__(self):
return self._name_
def __repr__(self):
return 'PixelFormat.{}'.format(str(self))
def get_convertible_formats(self) -> Tuple['PixelFormat', ...]:
formats = PIXEL_FORMAT_CONVERTIBILITY_MAP[VmbPixelFormat(self)]
return tuple([PixelFormat(fmt) for fmt in formats])
MONO_PIXEL_FORMATS = (
PixelFormat.Mono8,
PixelFormat.Mono10,
PixelFormat.Mono10p,
PixelFormat.Mono12,
PixelFormat.Mono12Packed,
PixelFormat.Mono12p,
PixelFormat.Mono14,
PixelFormat.Mono16
)
BAYER_PIXEL_FORMATS = (
PixelFormat.BayerGR8,
PixelFormat.BayerRG8,
PixelFormat.BayerGB8,
PixelFormat.BayerBG8,
PixelFormat.BayerGR10,
PixelFormat.BayerRG10,
PixelFormat.BayerGB10,
PixelFormat.BayerBG10,
PixelFormat.BayerGR12,
PixelFormat.BayerRG12,
PixelFormat.BayerGB12,
PixelFormat.BayerBG12,
PixelFormat.BayerGR12Packed,
PixelFormat.BayerRG12Packed,
PixelFormat.BayerGB12Packed,
PixelFormat.BayerBG12Packed,
PixelFormat.BayerGR10p,
PixelFormat.BayerRG10p,
PixelFormat.BayerGB10p,
PixelFormat.BayerBG10p,
PixelFormat.BayerGR12p,
PixelFormat.BayerRG12p,
PixelFormat.BayerGB12p,
PixelFormat.BayerBG12p,
PixelFormat.BayerGR16,
PixelFormat.BayerRG16,
PixelFormat.BayerGB16,
PixelFormat.BayerBG16
)
RGB_PIXEL_FORMATS = (
PixelFormat.Rgb8,
PixelFormat.Rgb10,
PixelFormat.Rgb12,
PixelFormat.Rgb14,
PixelFormat.Rgb16
)
RGBA_PIXEL_FORMATS = (
PixelFormat.Rgba8,
PixelFormat.Argb8,
PixelFormat.Rgba10,
PixelFormat.Rgba12,
PixelFormat.Rgba14,
PixelFormat.Rgba16
)
BGR_PIXEL_FORMATS = (
PixelFormat.Bgr8,
PixelFormat.Bgr10,
PixelFormat.Bgr12,
PixelFormat.Bgr14,
PixelFormat.Bgr16
)
BGRA_PIXEL_FORMATS = (
PixelFormat.Bgra8,
PixelFormat.Bgra10,
PixelFormat.Bgra12,
PixelFormat.Bgra14,
PixelFormat.Bgra16
)
YUV_PIXEL_FORMATS = (
PixelFormat.Yuv411,
PixelFormat.Yuv422,
PixelFormat.Yuv444
)
YCBCR_PIXEL_FORMATS = (
PixelFormat.YCbCr411_8_CbYYCrYY,
PixelFormat.YCbCr422_8_CbYCrY,
PixelFormat.YCbCr8_CbYCr
)
COLOR_PIXEL_FORMATS = BAYER_PIXEL_FORMATS + RGB_PIXEL_FORMATS + RGBA_PIXEL_FORMATS + \
BGR_PIXEL_FORMATS + BGRA_PIXEL_FORMATS + YUV_PIXEL_FORMATS + \
YCBCR_PIXEL_FORMATS
OPENCV_PIXEL_FORMATS = (
PixelFormat.Mono8,
PixelFormat.Bgr8,
PixelFormat.Bgra8,
PixelFormat.Mono16,
PixelFormat.Bgr16,
PixelFormat.Bgra16
)
class Debayer(enum.IntEnum):
"""Enum specifying debayer modes.
Enum values:
Mode2x2 - 2x2 with green averaging (this is the default if no debayering algorithm
is added as transformation option).
Mode3x3 - 3x3 with equal green weighting per line (8-bit images only).
ModeLCAA - Debayering with horizontal local color anti-aliasing (8-bit images only).
ModeLCAAV - Debayering with horizontal and vertical local color anti-aliasing
( 8-bit images only).
ModeYuv422 - Debayering with YUV422-alike sub-sampling (8-bit images only).
"""
Mode2x2 = VmbDebayerMode.Mode_2x2
Mode3x3 = VmbDebayerMode.Mode_3x3
ModeLCAA = VmbDebayerMode.Mode_LCAA
ModeLCAAV = VmbDebayerMode.Mode_LCAAV
ModeYuv422 = VmbDebayerMode.Mode_YUV422
def __str__(self):
return 'DebayerMode.{}'.format(self._name_)
def __repr__(self):
return str(self)
class FrameStatus(enum.IntEnum):
"""Enum specifying the current status of internal Frame data.
Enum values:
Complete - Frame data is complete without errors.
Incomplete - Frame could not be filled to the end.
TooSmall - Frame buffer was too small.
Invalid - Frame buffer was invalid.
"""
Complete = VmbFrameStatus.Complete
Incomplete = VmbFrameStatus.Incomplete
TooSmall = VmbFrameStatus.TooSmall
Invalid = VmbFrameStatus.Invalid
class AllocationMode(enum.IntEnum):
"""Enum specifying the supported frame allocation modes.
Enum values:
AnnounceFrame - The buffer is allocated by VimbaPython
AllocAndAnnounceFrame - The buffer is allocated by the Transport Layer
"""
AnnounceFrame = 0
AllocAndAnnounceFrame = 1
class AncillaryData:
"""Ancillary Data are created after enabling a Cameras 'ChunkModeActive' Feature.
Ancillary Data are Features stored within a Frame.
"""
@TraceEnable()
@LeaveContextOnCall()
def __init__(self, handle: VmbFrame):
"""Do not call directly. Get Object via Frame access method"""
self.__handle: VmbFrame = handle
self.__data_handle: VmbHandle = VmbHandle()
self.__feats: FeaturesTuple = ()
self.__context_cnt: int = 0
@TraceEnable()
def __enter__(self):
if not self.__context_cnt:
self._open()
self.__context_cnt += 1
return self
@TraceEnable()
def __exit__(self, exc_type, exc_value, exc_traceback):
self.__context_cnt -= 1
if not self.__context_cnt:
self._close()
@RaiseIfOutsideContext()
def get_all_features(self) -> FeaturesTuple:
"""Get all features in ancillary data.
Returns:
A set of all currently features stored in Ancillary Data.
Raises:
RuntimeError then called outside of "with" - statement.
"""
return self.__feats
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_type(self, feat_type: FeatureTypeTypes) -> FeaturesTuple:
"""Get all features in ancillary data of a specific type.
Valid FeatureTypes are: IntFeature, FloatFeature, StringFeature, BoolFeature,
EnumFeature, CommandFeature, RawFeature
Arguments:
feat_type - FeatureType used find features of that type.
Returns:
A all features of type 'feat_type'.
Raises:
RuntimeError then called outside of "with" - statement.
TypeError if parameters do not match their type hint.
"""
return filter_features_by_type(self.__feats, feat_type)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_category(self, category: str) -> FeaturesTuple:
"""Get all features in ancillary data of a specific category.
Arguments:
category - Category that should be used for filtering.
Returns:
A all features of category 'category'.
Raises:
RuntimeError then called outside of "with" - statement.
TypeError if parameters do not match their type hint.
"""
return filter_features_by_category(self.__feats, category)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_feature_by_name(self, feat_name: str) -> FeatureTypes:
"""Get a features in ancillary data by its name.
Arguments:
feat_name - Name used to find a feature.
Returns:
Feature with the associated name.
Raises:
RuntimeError then called outside of "with" - statement.
TypeError if parameters do not match their type hint.
VimbaFeatureError if no feature is associated with 'feat_name'.
"""
feat = filter_features_by_name(self.__feats, feat_name)
if not feat:
raise VimbaFeatureError('Feature \'{}\' not found.'.format(feat_name))
return feat
@TraceEnable()
@EnterContextOnCall()
def _open(self):
call_vimba_c('VmbAncillaryDataOpen', byref(self.__handle), byref(self.__data_handle))
self.__feats = _replace_invalid_feature_calls(discover_features(self.__data_handle))
attach_feature_accessors(self, self.__feats)
@TraceEnable()
@LeaveContextOnCall()
def _close(self):
remove_feature_accessors(self, self.__feats)
self.__feats = ()
call_vimba_c('VmbAncillaryDataClose', self.__data_handle)
self.__data_handle = VmbHandle()
def _replace_invalid_feature_calls(feats: FeaturesTuple) -> FeaturesTuple:
# AncillaryData are basically "lightweight" features. Calling most feature related
# Functions with a AncillaryData - Handle leads to VimbaC Errors. This method decorates
# all Methods that are unsafe to call with a decorator raising a RuntimeError.
to_wrap = [
'get_access_mode',
'is_readable',
'is_writeable',
'register_change_handler',
'get_increment',
'get_range',
'set'
]
# Decorator raising a RuntimeError instead of delegating call to inner function.
def invalid_call(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
msg = 'Calling \'{}\' is invalid for AncillaryData Features.'
raise RuntimeError(msg.format(func.__name__))
return wrapper
# Replace original implementation by injecting a surrounding decorator and
# binding the resulting function as a method to the Feature instance.
for f, a in [(f, a) for f in feats for a in to_wrap]:
try:
fn = invalid_call(getattr(f, a))
setattr(f, a, fn.__get__(f))
except AttributeError:
pass
return feats
class Frame:
"""This class allows access to Frames acquired by a camera. The Frame is basically
a buffer that wraps image data and some metadata.
"""
def __init__(self, buffer_size: int, allocation_mode: AllocationMode):
"""Do not call directly. Create Frames via Camera methods instead."""
self._allocation_mode = allocation_mode
# Allocation is not necessary for the AllocAndAnnounce case. In that case the Transport
# Layer will take care of buffer allocation. The self._buffer variable will be updated after
# the frame is announced and memory has been allocated.
if self._allocation_mode == AllocationMode.AnnounceFrame:
self._buffer = (ctypes.c_ubyte * buffer_size)()
self._frame: VmbFrame = VmbFrame()
# Setup underlaying Frame
if self._allocation_mode == AllocationMode.AnnounceFrame:
self._frame.buffer = ctypes.cast(self._buffer, ctypes.c_void_p)
self._frame.bufferSize = sizeof(self._buffer)
elif self._allocation_mode == AllocationMode.AllocAndAnnounceFrame:
# Set buffer pointer to NULL and inform Transport Layer of size it should allocate
self._frame.buffer = None
self._frame.bufferSize = buffer_size
def __str__(self):
msg = 'Frame(id={}, status={}, buffer={})'
return msg.format(self._frame.frameID, str(FrameStatus(self._frame.receiveStatus)),
hex(self._frame.buffer))
def __deepcopy__(self, memo):
cls = self.__class__
result = cls.__new__(cls)
memo[id(self)] = result
# VmbFrame contains Pointers and ctypes.Structure with Pointers can't be copied.
# As a workaround VmbFrame contains a deepcopy-like Method performing deep copy of all
# Attributes except PointerTypes. Those must be set manually after the copy operation.
setattr(result, '_buffer', copy.deepcopy(self._buffer, memo))
setattr(result, '_frame', self._frame.deepcopy_skip_ptr(memo))
result._frame.buffer = ctypes.cast(result._buffer, ctypes.c_void_p)
result._frame.bufferSize = sizeof(result._buffer)
return result
def _set_buffer(self, buffer: ctypes.c_void_p):
"""Set self._buffer to memory pointed to by passed buffer pointer
Useful if frames were allocated with AllocationMode.AllocAndAnnounce
"""
self._buffer = ctypes.cast(buffer,
ctypes.POINTER(ctypes.c_ubyte * self._frame.bufferSize)).contents
def get_buffer(self) -> ctypes.Array:
"""Get internal buffer object containing image data."""
return self._buffer
def get_buffer_size(self) -> int:
"""Get byte size of internal buffer."""
return self._frame.bufferSize
def get_image_size(self) -> int:
"""Get byte size of image data stored in buffer."""
return self._frame.imageSize
def get_ancillary_data(self) -> Optional[AncillaryData]:
"""Get AncillaryData.
Frames acquired with cameras where Feature ChunkModeActive is enabled can contain
ancillary data within the image data.
Returns:
None if Frame contains no ancillary data.
AncillaryData if Frame contains ancillary data.
"""
if not self._frame.ancillarySize:
return None
return AncillaryData(self._frame)
def get_status(self) -> FrameStatus:
"""Returns current frame status."""
return FrameStatus(self._frame.receiveStatus)
def get_pixel_format(self) -> PixelFormat:
"""Get format of the acquired image data"""
return PixelFormat(self._frame.pixelFormat)
def get_height(self) -> Optional[int]:
"""Get image height in pixels.
Returns:
Image height in pixels if dimension data is provided by the camera.
None if dimension data is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.Dimension not in flags:
return None
return self._frame.height
def get_width(self) -> Optional[int]:
"""Get image width in pixels.
Returns:
Image width in pixels if dimension data is provided by the camera.
None if dimension data is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.Dimension not in flags:
return None
return self._frame.width
def get_offset_x(self) -> Optional[int]:
"""Get horizontal offset in pixels.
Returns:
Horizontal offset in pixel if offset data is provided by the camera.
None if offset data is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.Offset not in flags:
return None
return self._frame.offsetX
def get_offset_y(self) -> Optional[int]:
"""Get vertical offset in pixels.
Returns:
Vertical offset in pixels if offset data is provided by the camera.
None if offset data is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.Offset not in flags:
return None
return self._frame.offsetY
def get_id(self) -> Optional[int]:
"""Get Frame ID.
Returns:
Frame ID if the id is provided by the camera.
None if frame id is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.FrameID not in flags:
return None
return self._frame.frameID
def get_timestamp(self) -> Optional[int]:
"""Get Frame timestamp.
Returns:
Timestamp if provided by the camera.
None if timestamp is not provided by the camera.
"""
flags = decode_flags(VmbFrameFlags, self._frame.receiveFlags)
if VmbFrameFlags.Timestamp not in flags:
return None
return self._frame.timestamp
@RuntimeTypeCheckEnable()
def convert_pixel_format(self, target_fmt: PixelFormat,
debayer_mode: Optional[Debayer] = None):
"""Convert internal pixel format to given format.
Note: This method allocates a new buffer for internal image data leading to some
runtime overhead. For performance reasons, it might be better to set the value
of the camera's 'PixelFormat' feature instead. In addition, a non-default debayer mode
can be specified.
Arguments:
target_fmt - PixelFormat to convert to.
debayer_mode - Non-default algorithm used to debayer images in Bayer Formats. If
no mode is specified, default debayering mode 'Mode2x2' is applied. If
the current format is no Bayer format, this parameter is silently
ignored.
Raises:
TypeError if parameters do not match their type hint.
ValueError if the current format can't be converted into 'target_fmt'. Convertible
Formats can be queried via get_convertible_formats() of PixelFormat.
AssertionError if image width or height can't be determined.
"""
global BAYER_PIXEL_FORMATS
# 1) Perform sanity checking
fmt = self.get_pixel_format()
if fmt == target_fmt:
return
if target_fmt not in fmt.get_convertible_formats():
raise ValueError('Current PixelFormat can\'t be converted into given format.')
# 2) Specify Transformation Input Image
height = self._frame.height
width = self._frame.width
c_src_image = VmbImage()
c_src_image.Size = sizeof(c_src_image)
c_src_image.Data = ctypes.cast(self._buffer, ctypes.c_void_p)
call_vimba_image_transform('VmbSetImageInfoFromPixelFormat', fmt, width, height,
byref(c_src_image))
# 3) Specify Transformation Output Image
c_dst_image = VmbImage()
c_dst_image.Size = sizeof(c_dst_image)
layout, bits = PIXEL_FORMAT_TO_LAYOUT[VmbPixelFormat(target_fmt)]
call_vimba_image_transform('VmbSetImageInfoFromInputImage', byref(c_src_image), layout,
bits, byref(c_dst_image))
# 4) Allocate Buffer and perform transformation
img_size = int(height * width * c_dst_image.ImageInfo.PixelInfo.BitsPerPixel / 8)
anc_size = self._frame.ancillarySize
buf = (ctypes.c_ubyte * (img_size + anc_size))()
c_dst_image.Data = ctypes.cast(buf, ctypes.c_void_p)
# 5) Setup Debayering mode if given.
transform_info = VmbTransformInfo()
if debayer_mode and (fmt in BAYER_PIXEL_FORMATS):
call_vimba_image_transform('VmbSetDebayerMode', VmbDebayerMode(debayer_mode),
byref(transform_info))
# 6) Perform Transformation
call_vimba_image_transform('VmbImageTransform', byref(c_src_image), byref(c_dst_image),
byref(transform_info), 1)
# 7) Copy ancillary data if existing
if anc_size:
src = ctypes.addressof(self._buffer) + self._frame.imageSize
dst = ctypes.addressof(buf) + img_size
ctypes.memmove(dst, src, anc_size)
# 8) Update frame metadata
self._buffer = buf
self._frame.buffer = ctypes.cast(self._buffer, ctypes.c_void_p)
self._frame.bufferSize = sizeof(self._buffer)
self._frame.imageSize = img_size
self._frame.pixelFormat = target_fmt
def as_numpy_ndarray(self) -> 'numpy.ndarray':
"""Construct numpy.ndarray view on VimbaFrame.
Returns:
numpy.ndarray on internal image buffer.
Raises:
ImportError if numpy is not installed.
VimbaFrameError if current PixelFormat can't be converted to a numpy.ndarray.
"""
if numpy is None:
raise ImportError('\'Frame.as_opencv_image()\' requires module \'numpy\'.')
# Construct numpy overlay on underlaying image buffer
height = self._frame.height
width = self._frame.width
fmt = self._frame.pixelFormat
c_image = VmbImage()
c_image.Size = sizeof(c_image)
call_vimba_image_transform('VmbSetImageInfoFromPixelFormat', fmt, width, height,
byref(c_image))
layout = PIXEL_FORMAT_TO_LAYOUT.get(fmt)
if not layout:
msg = 'Can\'t construct numpy.ndarray for Pixelformat {}. ' \
'Use \'frame.convert_pixel_format()\' to convert to a different Pixelformat.'
raise VimbaFrameError(msg.format(str(self.get_pixel_format())))
bits_per_channel = layout[1]
channels_per_pixel = c_image.ImageInfo.PixelInfo.BitsPerPixel // bits_per_channel
return numpy.ndarray(shape=(height, width, channels_per_pixel),
buffer=self._buffer, # type: ignore
dtype=numpy.uint8 if bits_per_channel == 8 else numpy.uint16)
def as_opencv_image(self) -> 'numpy.ndarray':
"""Construct OpenCV compatible view on VimbaFrame.
Returns:
OpenCV compatible numpy.ndarray
Raises:
ImportError if numpy is not installed.
ValueError if current pixel format is not compatible with opencv. Compatible
formats are in OPENCV_PIXEL_FORMATS.
"""
global OPENCV_PIXEL_FORMATS
if numpy is None:
raise ImportError('\'Frame.as_opencv_image()\' requires module \'numpy\'.')
fmt = self._frame.pixelFormat
if fmt not in OPENCV_PIXEL_FORMATS:
raise ValueError('Current Format \'{}\' is not in OPENCV_PIXEL_FORMATS'.format(
str(PixelFormat(self._frame.pixelFormat))))
return self.as_numpy_ndarray()
@TraceEnable()
@RuntimeTypeCheckEnable()
def intersect_pixel_formats(fmts1: FormatTuple, fmts2: FormatTuple) -> FormatTuple:
"""Build intersection of two sets containing PixelFormat.
Arguments:
fmts1 - PixelFormats to intersect with fmts2
fmts2 - PixelFormats to intersect with fmts1
Returns:
Set of PixelFormats that occur in fmts1 and fmts2
Raises:
TypeError if parameters do not match their type hint.
"""
return tuple(set(fmts1).intersection(set(fmts2)))

View File

@@ -0,0 +1,391 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import enum
from typing import Tuple, List, Callable, Dict
from .c_binding import call_vimba_c, byref, sizeof, decode_cstr
from .c_binding import VmbInterface, VmbInterfaceInfo, VmbHandle, VmbUint32
from .feature import discover_features, FeatureTypes, FeaturesTuple, FeatureTypeTypes
from .shared import filter_features_by_name, filter_features_by_type, filter_affected_features, \
filter_selected_features, filter_features_by_category, \
attach_feature_accessors, remove_feature_accessors, read_memory, \
write_memory, read_registers, write_registers
from .util import TraceEnable, RuntimeTypeCheckEnable, EnterContextOnCall, LeaveContextOnCall, \
RaiseIfOutsideContext
from .error import VimbaFeatureError
__all__ = [
'InterfaceType',
'Interface',
'InterfaceEvent',
'InterfaceChangeHandler',
'InterfacesTuple',
'InterfacesList',
'discover_interfaces',
'discover_interface'
]
# Forward declarations
InterfaceChangeHandler = Callable[['Interface', 'InterfaceEvent'], None]
InterfacesTuple = Tuple['Interface', ...]
InterfacesList = List['Interface']
class InterfaceType(enum.IntEnum):
"""Enum specifying all interface types.
Enum values:
Unknown - Interface is not known to this VimbaPython version.
Firewire - 1394
Ethernet - Gigabit Ethernet
Usb - USB 3.0
CL - Camera Link
CSI2 - CSI-2
"""
Unknown = VmbInterface.Unknown
Firewire = VmbInterface.Firewire
Ethernet = VmbInterface.Ethernet
Usb = VmbInterface.Usb
CL = VmbInterface.CL
CSI2 = VmbInterface.CSI2
class InterfaceEvent(enum.IntEnum):
"""Enum specifying an Interface Event
Enum values:
Missing - A known interface disappeared from the bus
Detected - A new interface was discovered
Reachable - A known interface can be accessed
Unreachable - A known interface cannot be accessed anymore
"""
Missing = 0
Detected = 1
Reachable = 2
Unreachable = 3
class Interface:
"""This class allows access to an interface such as USB detected by Vimba.
Interface is meant to be used in conjunction with the "with" - statement. On entering a context,
all Interface features are detected and can be accessed within the context. Static Interface
properties like Name can be accessed outside the context.
"""
@TraceEnable()
@LeaveContextOnCall()
def __init__(self, info: VmbInterfaceInfo):
"""Do not call directly. Access Interfaces via vimba.Vimba instead."""
self.__handle: VmbHandle = VmbHandle(0)
self.__info: VmbInterfaceInfo = info
self.__feats: FeaturesTuple = ()
self.__context_cnt: int = 0
@TraceEnable()
def __enter__(self):
if not self.__context_cnt:
self._open()
self.__context_cnt += 1
return self
@TraceEnable()
def __exit__(self, exc_type, exc_value, exc_traceback):
self.__context_cnt -= 1
if not self.__context_cnt:
self._close()
def __str__(self):
return 'Interface(id={})'.format(self.get_id())
def __repr__(self):
rep = 'Interface'
rep += '(__handle=' + repr(self.__handle)
rep += ',__info=' + repr(self.__info)
rep += ')'
return rep
def get_id(self) -> str:
"""Get Interface Id such as VimbaUSBInterface_0x0."""
return decode_cstr(self.__info.interfaceIdString)
def get_type(self) -> InterfaceType:
"""Get Interface Type such as InterfaceType.Usb."""
return InterfaceType(self.__info.interfaceType)
def get_name(self) -> str:
"""Get Interface Name such as Vimba USB Interface."""
return decode_cstr(self.__info.interfaceName)
def get_serial(self) -> str:
"""Get Interface Serial or '' if not set."""
return decode_cstr(self.__info.serialString)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def read_memory(self, addr: int, max_bytes: int) -> bytes: # coverage: skip
"""Read a byte sequence from a given memory address.
Arguments:
addr: Starting address to read from.
max_bytes: Maximum number of bytes to read from addr.
Returns:
Read memory contents as bytes.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
ValueError if addr is negative.
ValueError if max_bytes is negative.
ValueError if the memory access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return read_memory(self.__handle, addr, max_bytes)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def write_memory(self, addr: int, data: bytes): # coverage: skip
"""Write a byte sequence to a given memory address.
Arguments:
addr: Address to write the content of 'data' to.
data: Byte sequence to write at address 'addr'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
ValueError if addr is negative.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return write_memory(self.__handle, addr, data)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def read_registers(self, addrs: Tuple[int, ...]) -> Dict[int, int]: # coverage: skip
"""Read contents of multiple registers.
Arguments:
addrs: Sequence of addresses that should be read iteratively.
Returns:
Dictionary containing a mapping from given address to the read register values.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
ValueError if any address in addrs is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return read_registers(self.__handle, addrs)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def write_registers(self, addrs_values: Dict[int, int]): # coverage: skip
"""Write data to multiple registers.
Arguments:
addrs_values: Mapping between register addresses and the data to write.
Raises:
TypeError if parameters do not match their type hint.
ValueError if any address in addrs_values is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return write_registers(self.__handle, addrs_values)
@RaiseIfOutsideContext()
def get_all_features(self) -> FeaturesTuple:
"""Get access to all discovered features of this Interface.
Returns:
A set of all currently detected features.
Raises:
RuntimeError if called outside "with" - statement.
"""
return self.__feats
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_affected_by(self, feat: FeatureTypes) -> FeaturesTuple:
"""Get all features affected by a specific interface feature.
Arguments:
feat - Feature to find features that are affected by 'feat'.
Returns:
A set of features affected by changes on 'feat'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
VimbaFeatureError if 'feat' is not a feature of this interface.
"""
return filter_affected_features(self.__feats, feat)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_selected_by(self, feat: FeatureTypes) -> FeaturesTuple:
"""Get all features selected by a specific interface feature.
Arguments:
feat - Feature to find features that are selected by 'feat'.
Returns:
A set of features selected by changes on 'feat'.
Raises:
TypeError if 'feat' is not of any feature type.
RuntimeError if called outside "with" - statement.
VimbaFeatureError if 'feat' is not a feature of this interface.
"""
return filter_selected_features(self.__feats, feat)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_type(self, feat_type: FeatureTypeTypes) -> FeaturesTuple:
"""Get all interface features of a specific feature type.
Valid FeatureTypes are: IntFeature, FloatFeature, StringFeature, BoolFeature,
EnumFeature, CommandFeature, RawFeature
Arguments:
feat_type - FeatureType used find features of that type.
Returns:
A set of features of type 'feat_type'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
"""
return filter_features_by_type(self.__feats, feat_type)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_category(self, category: str) -> FeaturesTuple:
"""Get all interface features of a specific category.
Arguments:
category - category for filtering.
Returns:
A set of features of category 'category'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
"""
return filter_features_by_category(self.__feats, category)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_feature_by_name(self, feat_name: str) -> FeatureTypes:
"""Get an interface feature by its name.
Arguments:
feat_name - Name to find a feature.
Returns:
Feature with the associated name.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called outside "with" - statement.
VimbaFeatureError if no feature is associated with 'feat_name'.
"""
feat = filter_features_by_name(self.__feats, feat_name)
if not feat:
raise VimbaFeatureError('Feature \'{}\' not found.'.format(feat_name))
return feat
@TraceEnable()
@EnterContextOnCall()
def _open(self):
call_vimba_c('VmbInterfaceOpen', self.__info.interfaceIdString, byref(self.__handle))
self.__feats = discover_features(self.__handle)
attach_feature_accessors(self, self.__feats)
@TraceEnable()
@LeaveContextOnCall()
def _close(self):
for feat in self.__feats:
feat.unregister_all_change_handlers()
remove_feature_accessors(self, self.__feats)
self.__feats = ()
call_vimba_c('VmbInterfaceClose', self.__handle)
self.__handle = VmbHandle(0)
@TraceEnable()
def discover_interfaces() -> InterfacesList:
"""Do not call directly. Access Interfaces via vimba.System instead."""
result = []
inters_count = VmbUint32(0)
call_vimba_c('VmbInterfacesList', None, 0, byref(inters_count), sizeof(VmbInterfaceInfo))
if inters_count:
inters_found = VmbUint32(0)
inters_infos = (VmbInterfaceInfo * inters_count.value)()
call_vimba_c('VmbInterfacesList', inters_infos, inters_count, byref(inters_found),
sizeof(VmbInterfaceInfo))
for info in inters_infos[:inters_found.value]:
result.append(Interface(info))
return result
@TraceEnable()
def discover_interface(id_: str) -> Interface:
"""Do not call directly. Access Interfaces via vimba.System instead."""
# Since there is no function to query a single interface, discover all interfaces and
# extract the Interface with the matching ID.
inters = discover_interfaces()
return [i for i in inters if id_ == i.get_id()].pop()

View File

@@ -0,0 +1,357 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import itertools
from typing import Dict, Tuple
from .c_binding import VmbUint32, VmbUint64, VmbHandle, VmbFeatureInfo
from .c_binding import call_vimba_c, byref, sizeof, create_string_buffer, VimbaCError
from .feature import FeaturesTuple, FeatureTypes, FeatureTypeTypes
from .error import VimbaFeatureError
from .util import TraceEnable
__all__ = [
'filter_affected_features',
'filter_selected_features',
'filter_features_by_name',
'filter_features_by_type',
'filter_features_by_category',
'attach_feature_accessors',
'remove_feature_accessors',
'read_memory',
'write_memory',
'read_registers',
'write_registers'
]
@TraceEnable()
def filter_affected_features(feats: FeaturesTuple, feat: FeatureTypes) -> FeaturesTuple:
"""Search for all Features affected by a given feature within a feature set.
Arguments:
feats: Feature set to search in.
feat: Feature that might affect Features within 'feats'.
Returns:
A set of all features that are affected by 'feat'.
Raises:
VimbaFeatureError if 'feat' is not stored within 'feats'.
"""
if feat not in feats:
raise VimbaFeatureError('Feature \'{}\' not in given Features'.format(feat.get_name()))
result = []
if feat.has_affected_features():
feats_count = VmbUint32()
feats_handle = feat._handle
feats_name = feat._info.name
# Query affected features from given Feature
call_vimba_c('VmbFeatureListAffected', feats_handle, feats_name, None, 0,
byref(feats_count), sizeof(VmbFeatureInfo))
feats_found = VmbUint32(0)
feats_infos = (VmbFeatureInfo * feats_count.value)()
call_vimba_c('VmbFeatureListAffected', feats_handle, feats_name, feats_infos, feats_count,
byref(feats_found), sizeof(VmbFeatureInfo))
# Search affected features in given feature set
for info, feature in itertools.product(feats_infos[:feats_found.value], feats):
if info.name == feature._info.name:
result.append(feature)
return tuple(result)
@TraceEnable()
def filter_selected_features(feats: FeaturesTuple, feat: FeatureTypes) -> FeaturesTuple:
"""Search for all Features selected by a given feature within a feature set.
Arguments:
feats: Feature set to search in.
feat: Feature that might select Features within 'feats'.
Returns:
A set of all features that are selected by 'feat'.
Raises:
VimbaFeatureError if 'feat' is not stored within 'feats'.
"""
if feat not in feats:
raise VimbaFeatureError('Feature \'{}\' not in given Features'.format(feat.get_name()))
result = []
if feat.has_selected_features():
feats_count = VmbUint32()
feats_handle = feat._handle
feats_name = feat._info.name
# Query selected features from given feature
call_vimba_c('VmbFeatureListSelected', feats_handle, feats_name, None, 0,
byref(feats_count), sizeof(VmbFeatureInfo))
feats_found = VmbUint32(0)
feats_infos = (VmbFeatureInfo * feats_count.value)()
call_vimba_c('VmbFeatureListSelected', feats_handle, feats_name, feats_infos, feats_count,
byref(feats_found), sizeof(VmbFeatureInfo))
# Search selected features in given feature set
for info, feature in itertools.product(feats_infos[:feats_found.value], feats):
if info.name == feature._info.name:
result.append(feature)
return tuple(result)
@TraceEnable()
def filter_features_by_name(feats: FeaturesTuple, feat_name: str):
"""Search for a feature with a specific name within a feature set.
Arguments:
feats: Feature set to search in.
feat_name: Feature name to look for.
Returns:
The Feature with the name 'feat_name' or None if lookup failed
"""
filtered = [feat for feat in feats if feat_name == feat.get_name()]
return filtered.pop() if filtered else None
@TraceEnable()
def filter_features_by_type(feats: FeaturesTuple, feat_type: FeatureTypeTypes) -> FeaturesTuple:
"""Search for all features with a specific type within a given feature set.
Arguments:
feats: Feature set to search in.
feat_type: Feature Type to search for
Returns:
A set of all features of type 'feat_type' in 'feats'. If no matching type is found an
empty set is returned.
"""
return tuple([feat for feat in feats if type(feat) == feat_type])
@TraceEnable()
def filter_features_by_category(feats: FeaturesTuple, category: str) -> FeaturesTuple:
"""Search for all features of a given category.
Arguments:
feats: Feature set to search in.
category: Category to filter for
Returns:
A set of all features of category 'category' in 'feats'. If no matching type is found an
empty set is returned.
"""
return tuple([feat for feat in feats if feat.get_category() == category])
@TraceEnable()
def attach_feature_accessors(obj, feats: FeaturesTuple):
"""Attach all Features in feats to obj under the feature name.
Arguments:
obj: Object feats should be attached on.
feats: Features to attach.
"""
BLACKLIST = (
'PixelFormat', # PixelFormats have special access methods.
)
for feat in feats:
feat_name = feat.get_name()
if feat_name not in BLACKLIST:
setattr(obj, feat_name, feat)
@TraceEnable()
def remove_feature_accessors(obj, feats: FeaturesTuple):
"""Remove all Features in feats from obj.
Arguments:
obj: Object, feats should be removed from.
feats: Features to remove.
"""
for feat in feats:
try:
delattr(obj, feat.get_name())
except AttributeError:
pass
@TraceEnable()
def read_memory(handle: VmbHandle, addr: int, max_bytes: int) -> bytes: # coverage: skip
"""Read a byte sequence from a given memory address.
Arguments:
handle: Handle on entity that allows raw memory access.
addr: Starting address to read from.
max_bytes: Maximum number of bytes to read from addr.
Returns:
Read memory contents as bytes.
Raises:
ValueError if addr is negative
ValueError if max_bytes is negative.
ValueError if the memory access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
_verify_addr(addr)
_verify_size(max_bytes)
buf = create_string_buffer(max_bytes)
bytesRead = VmbUint32()
try:
call_vimba_c('VmbMemoryRead', handle, addr, max_bytes, buf, byref(bytesRead))
except VimbaCError as e:
msg = 'Memory read access at {} failed with C-Error: {}.'
raise ValueError(msg.format(hex(addr), repr(e.get_error_code()))) from e
return buf.raw[:bytesRead.value]
@TraceEnable()
def write_memory(handle: VmbHandle, addr: int, data: bytes): # coverage: skip
""" Write a byte sequence to a given memory address.
Arguments:
handle: Handle on entity that allows raw memory access.
addr: Address to write the content of 'data' too.
data: Byte sequence to write at address 'addr'.
Raises:
ValueError if addr is negative.
ValueError if the memory access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
_verify_addr(addr)
bytesWrite = VmbUint32()
try:
call_vimba_c('VmbMemoryWrite', handle, addr, len(data), data, byref(bytesWrite))
except VimbaCError as e:
msg = 'Memory write access at {} failed with C-Error: {}.'
raise ValueError(msg.format(hex(addr), repr(e.get_error_code()))) from e
@TraceEnable()
def read_registers(handle: VmbHandle, addrs: Tuple[int, ...]) -> Dict[int, int]: # coverage: skip
"""Read contents of multiple registers.
Arguments:
handle: Handle on entity providing registers to access.
addrs: Sequence of addresses that should be read iteratively.
Return:
Dictionary containing a mapping from given address to the read register values.
Raises:
ValueError if any address in addrs is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
for addr in addrs:
_verify_addr(addr)
size = len(addrs)
valid_reads = VmbUint32()
c_addrs = (VmbUint64 * size)()
c_values = (VmbUint64 * size)()
for i, addr in enumerate(addrs):
c_addrs[i] = addr
try:
call_vimba_c('VmbRegistersRead', handle, size, c_addrs, c_values, byref(valid_reads))
except VimbaCError as e:
msg = 'Register read access failed with C-Error: {}.'
raise ValueError(msg.format(repr(e.get_error_code()))) from e
return dict(zip(c_addrs, c_values))
@TraceEnable()
def write_registers(handle: VmbHandle, addrs_values: Dict[int, int]): # coverage: skip
"""Write data to multiple Registers.
Arguments:
handle: Handle on entity providing registers to access.
addrs_values: Mapping between Register addresses and the data to write.
Raises:
ValueError if any address in addrs_values is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
for addr in addrs_values:
_verify_addr(addr)
size = len(addrs_values)
valid_writes = VmbUint32()
addrs = (VmbUint64 * size)()
values = (VmbUint64 * size)()
for i, addr in enumerate(addrs_values):
addrs[i] = addr
values[i] = addrs_values[addr]
try:
call_vimba_c('VmbRegistersWrite', handle, size, addrs, values, byref(valid_writes))
except VimbaCError as e:
msg = 'Register write access failed with C-Error: {}.'
raise ValueError(msg.format(repr(e.get_error_code()))) from e
def _verify_addr(addr: int): # coverage: skip
# Note: Coverage is skipped. Function is untestable in a generic way.
if addr < 0:
raise ValueError('Given Address {} is negative'.format(addr))
def _verify_size(size: int): # coverage: skip
# Note: Coverage is skipped. Function is untestable in a generic way.
if size < 0:
raise ValueError('Given size {} is negative'.format(size))

View File

@@ -0,0 +1,72 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
# Suppress 'imported but unused' - Error from static style checker.
# flake8: noqa: F401
__all__ = [
'LogLevel',
'LogConfig',
'Log',
'LOG_CONFIG_TRACE_CONSOLE_ONLY',
'LOG_CONFIG_TRACE_FILE_ONLY',
'LOG_CONFIG_TRACE',
'LOG_CONFIG_INFO_CONSOLE_ONLY',
'LOG_CONFIG_INFO_FILE_ONLY',
'LOG_CONFIG_INFO',
'LOG_CONFIG_WARNING_CONSOLE_ONLY',
'LOG_CONFIG_WARNING_FILE_ONLY',
'LOG_CONFIG_WARNING',
'LOG_CONFIG_ERROR_CONSOLE_ONLY',
'LOG_CONFIG_ERROR_FILE_ONLY',
'LOG_CONFIG_ERROR',
'LOG_CONFIG_CRITICAL_CONSOLE_ONLY',
'LOG_CONFIG_CRITICAL_FILE_ONLY',
'LOG_CONFIG_CRITICAL',
# Decorators
'TraceEnable',
'ScopedLogEnable',
'RuntimeTypeCheckEnable',
'EnterContextOnCall',
'LeaveContextOnCall',
'RaiseIfInsideContext',
'RaiseIfOutsideContext'
]
from .log import Log, LogLevel, LogConfig, LOG_CONFIG_TRACE_CONSOLE_ONLY, \
LOG_CONFIG_TRACE_FILE_ONLY, LOG_CONFIG_TRACE, LOG_CONFIG_INFO_CONSOLE_ONLY, \
LOG_CONFIG_INFO_FILE_ONLY, LOG_CONFIG_INFO, LOG_CONFIG_WARNING_CONSOLE_ONLY, \
LOG_CONFIG_WARNING_FILE_ONLY, LOG_CONFIG_WARNING, LOG_CONFIG_ERROR_CONSOLE_ONLY, \
LOG_CONFIG_ERROR_FILE_ONLY, LOG_CONFIG_ERROR, LOG_CONFIG_CRITICAL_CONSOLE_ONLY, \
LOG_CONFIG_CRITICAL_FILE_ONLY, LOG_CONFIG_CRITICAL
from .tracer import TraceEnable
from .scoped_log import ScopedLogEnable
from .runtime_type_check import RuntimeTypeCheckEnable
from .context_decorator import EnterContextOnCall, LeaveContextOnCall, RaiseIfInsideContext, \
RaiseIfOutsideContext

View File

@@ -0,0 +1,96 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import functools
__all__ = [
'EnterContextOnCall',
'LeaveContextOnCall',
'RaiseIfInsideContext',
'RaiseIfOutsideContext'
]
class EnterContextOnCall:
"""Decorator setting/injecting flag used for checking the context."""
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
args[0]._context_entered = True
return func(*args, **kwargs)
return wrapper
class LeaveContextOnCall:
"""Decorator clearing/injecting flag used for checking the context."""
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
args[0]._context_entered = False
return result
return wrapper
class RaiseIfInsideContext:
"""Raising RuntimeError is decorated Method is called inside with-statement.
Note This Decorator shall work only on Object implementing a Context Manger.
For this to work object must offer a boolean attribute called _context_entered
"""
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if args[0]._context_entered:
msg = 'Called \'{}()\' inside of \'with\' - statement scope.'
msg = msg.format('{}'.format(func.__qualname__))
raise RuntimeError(msg)
return func(*args, **kwargs)
return wrapper
class RaiseIfOutsideContext:
"""Raising RuntimeError is decorated Method is called outside with-statement.
Note This Decorator shall work only on Object implementing a Context Manger.
For this to work object must offer a boolean attribute called __context_entered
"""
def __call__(self, func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if not args[0]._context_entered:
msg = 'Called \'{}()\' outside of \'with\' - statement scope.'
msg = msg.format('{}'.format(func.__qualname__))
raise RuntimeError(msg)
return func(*args, **kwargs)
return wrapper

View File

@@ -0,0 +1,295 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import os
import enum
import datetime
import logging
from typing import List, Optional
__all__ = [
'LogLevel',
'LogConfig',
'Log',
'LOG_CONFIG_TRACE_CONSOLE_ONLY',
'LOG_CONFIG_TRACE_FILE_ONLY',
'LOG_CONFIG_TRACE',
'LOG_CONFIG_INFO_CONSOLE_ONLY',
'LOG_CONFIG_INFO_FILE_ONLY',
'LOG_CONFIG_INFO',
'LOG_CONFIG_WARNING_CONSOLE_ONLY',
'LOG_CONFIG_WARNING_FILE_ONLY',
'LOG_CONFIG_WARNING',
'LOG_CONFIG_ERROR_CONSOLE_ONLY',
'LOG_CONFIG_ERROR_FILE_ONLY',
'LOG_CONFIG_ERROR',
'LOG_CONFIG_CRITICAL_CONSOLE_ONLY',
'LOG_CONFIG_CRITICAL_FILE_ONLY',
'LOG_CONFIG_CRITICAL'
]
class LogLevel(enum.IntEnum):
"""Enum containing all LogLevels.
Enum values are:
Trace - Show Tracing information. Show all messages.
Info - Show Informational, Warning, Error, and Critical Events.
Warning - Show Warning, Error, and Critical Events.
Error - Show Errors and Critical Events.
Critical - Show Critical Events only.
"""
Trace = logging.DEBUG
Info = logging.INFO
Warning = logging.WARNING
Error = logging.ERROR
Critical = logging.CRITICAL
def __str__(self):
return self._name_
def as_equal_len_str(self) -> str:
return _LEVEL_TO_EQUAL_LEN_STR[self]
_LEVEL_TO_EQUAL_LEN_STR = {
LogLevel.Trace: 'Trace ',
LogLevel.Info: 'Info ',
LogLevel.Warning: 'Warning ',
LogLevel.Error: 'Error ',
LogLevel.Critical: 'Critical'
}
class LogConfig:
"""The LogConfig is a builder to configure various specialized logging configurations.
The constructed LogConfig must set via vimba.Vimba or the ScopedLogEnable Decorator
to start logging.
"""
__ENTRY_FORMAT = logging.Formatter('%(asctime)s | %(message)s')
def __init__(self):
self.__handlers: List[logging.Handler] = []
self.__max_msg_length: Optional[int] = None
def add_file_log(self, level: LogLevel) -> 'LogConfig':
"""Add a new Log file to the Config Builder.
Arguments:
level: LogLevel of the added log file.
Returns:
Reference to the LogConfig instance (builder pattern).
"""
log_ts = datetime.datetime.today().strftime('%Y-%m-%d_%H-%M-%S')
log_file = 'VimbaPython_{}_{}.log'.format(log_ts, str(level))
log_file = os.path.join(os.getcwd(), log_file)
handler = logging.FileHandler(log_file, delay=True)
handler.setLevel(level)
handler.setFormatter(LogConfig.__ENTRY_FORMAT)
self.__handlers.append(handler)
return self
def add_console_log(self, level: LogLevel) -> 'LogConfig':
"""Add a new Console Log to the Config Builder.
Arguments:
level: LogLevel of the added console log file.
Returns:
Reference to the LogConfig instance (builder pattern).
"""
handler = logging.StreamHandler()
handler.setLevel(level)
handler.setFormatter(LogConfig.__ENTRY_FORMAT)
self.__handlers.append(handler)
return self
def set_max_msg_length(self, max_msg_length: int):
"""Set max length of a log entry. Messages longer than this entry will be cut off."""
self.__max_msg_length = max_msg_length
def get_max_msg_length(self) -> Optional[int]:
"""Get configured max message length"""
return self.__max_msg_length
def get_handlers(self) -> List[logging.Handler]:
"""Get all configured log handlers"""
return self.__handlers
class Log:
class __Impl:
"""This class is wraps the logging Facility. Since this is as Singleton
Use Log.get_instace(), to access the log.
"""
def __init__(self):
"""Do not call directly. Use Log.get_instance() instead."""
self.__logger: Optional[logging.Logger] = None
self.__config: Optional[LogConfig] = None
self._test_buffer: Optional[List[str]] = None
def __bool__(self):
return bool(self.__logger)
def enable(self, config: LogConfig):
"""Enable global VimbaPython logging mechanism.
Arguments:
config: The configuration to apply.
"""
self.disable()
logger = logging.getLogger('VimbaPythonLog')
logger.setLevel(logging.DEBUG)
for handler in config.get_handlers():
logger.addHandler(handler)
self.__config = config
self.__logger = logger
def disable(self):
"""Disable global VimbaPython logging mechanism."""
if self.__logger and self.__config:
for handler in self.__config.get_handlers():
handler.close()
self.__logger.removeHandler(handler)
self.__logger = None
self.__config = None
def get_config(self) -> Optional[LogConfig]:
""" Get log configuration
Returns:
Configuration if the log is enabled. In case the log is disabled return None.
"""
return self.__config
def trace(self, msg: str):
"""Add an entry of LogLevel.Trace to the log. Does nothing is the log is disabled.
Arguments:
msg - The message that should be added to the Log.
"""
if self.__logger:
self.__logger.debug(self.__build_msg(LogLevel.Trace, msg))
def info(self, msg: str):
"""Add an entry of LogLevel.Info to the log. Does nothing is the log is disabled.
Arguments:
msg - The message that should be added to the Log.
"""
if self.__logger:
self.__logger.info(self.__build_msg(LogLevel.Info, msg))
def warning(self, msg: str):
"""Add an entry of LogLevel.Warning to the log. Does nothing is the log is disabled.
Arguments:
msg - The message that should be added to the Log.
"""
if self.__logger:
self.__logger.warning(self.__build_msg(LogLevel.Warning, msg))
def error(self, msg: str):
"""Add an entry of LogLevel.Error to the log. Does nothing is the log is disabled.
Arguments:
msg - The message that should be added to the Log.
"""
if self.__logger:
self.__logger.error(self.__build_msg(LogLevel.Error, msg))
def critical(self, msg: str):
"""Add an entry of LogLevel.Critical to the log. Does nothing is the log is disabled.
Arguments:
msg - The message that should be added to the Log.
"""
if self.__logger:
self.__logger.critical(self.__build_msg(LogLevel.Critical, msg))
def __build_msg(self, loglevel: LogLevel, msg: str) -> str:
msg = '{} | {}'.format(loglevel.as_equal_len_str(), msg)
max_len = self.__config.get_max_msg_length() if self.__config else None
if max_len and (max_len < len(msg)):
suffix = ' ...'
msg = msg[:max_len - len(suffix)] + suffix
if self._test_buffer is not None:
self._test_buffer.append(msg)
return msg
__instance = __Impl()
@staticmethod
def get_instance() -> '__Impl':
"""Get Log instance."""
return Log.__instance
def _build_cfg(console_level: Optional[LogLevel], file_level: Optional[LogLevel]) -> LogConfig:
cfg = LogConfig()
cfg.set_max_msg_length(200)
if console_level:
cfg.add_console_log(console_level)
if file_level:
cfg.add_file_log(file_level)
return cfg
# Exported Default Log configurations.
LOG_CONFIG_TRACE_CONSOLE_ONLY = _build_cfg(LogLevel.Trace, None)
LOG_CONFIG_TRACE_FILE_ONLY = _build_cfg(None, LogLevel.Trace)
LOG_CONFIG_TRACE = _build_cfg(LogLevel.Trace, LogLevel.Trace)
LOG_CONFIG_INFO_CONSOLE_ONLY = _build_cfg(LogLevel.Info, None)
LOG_CONFIG_INFO_FILE_ONLY = _build_cfg(None, LogLevel.Info)
LOG_CONFIG_INFO = _build_cfg(LogLevel.Info, LogLevel.Info)
LOG_CONFIG_WARNING_CONSOLE_ONLY = _build_cfg(LogLevel.Warning, None)
LOG_CONFIG_WARNING_FILE_ONLY = _build_cfg(None, LogLevel.Warning)
LOG_CONFIG_WARNING = _build_cfg(LogLevel.Warning, LogLevel.Warning)
LOG_CONFIG_ERROR_CONSOLE_ONLY = _build_cfg(LogLevel.Error, None)
LOG_CONFIG_ERROR_FILE_ONLY = _build_cfg(None, LogLevel.Error)
LOG_CONFIG_ERROR = _build_cfg(LogLevel.Error, LogLevel.Error)
LOG_CONFIG_CRITICAL_CONSOLE_ONLY = _build_cfg(LogLevel.Critical, None)
LOG_CONFIG_CRITICAL_FILE_ONLY = _build_cfg(None, LogLevel.Critical)
LOG_CONFIG_CRITICAL = _build_cfg(LogLevel.Critical, LogLevel.Critical)

View File

@@ -0,0 +1,223 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import collections.abc
from inspect import isfunction, ismethod, signature
from functools import wraps
from typing import get_type_hints, Union
from .log import Log
__all__ = [
'RuntimeTypeCheckEnable'
]
class RuntimeTypeCheckEnable:
"""Decorator adding runtime type checking to the wrapped callable.
Each time the callable is executed, all arguments are checked if they match with the given
type hints. If all checks are passed, the wrapped function is executed, if the given
arguments to not match a TypeError is raised.
Note: This decorator is no replacement for a feature complete TypeChecker. It supports only
a subset of all types expressible by type hints.
"""
_log = Log.get_instance()
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
full_args, hints = self.__dismantle_sig(func, *args, **kwargs)
for arg_name in hints:
self.__verify_arg(func, hints[arg_name], (arg_name, full_args[arg_name]))
return func(*args, **kwargs)
return wrapper
def __dismantle_sig(self, func, *args, **kwargs):
# Get merge args, kwargs and defaults to complete argument list.
full_args = signature(func).bind(*args, **kwargs)
full_args.apply_defaults()
# Get available type hints, remove return value.
hints = get_type_hints(func)
hints.pop('return', None)
return (full_args.arguments, hints)
def __verify_arg(self, func, type_hint, arg_spec):
arg_name, arg = arg_spec
if (self.__matches(type_hint, arg)):
return
msg = '\'{}\' called with unexpected argument type. Argument\'{}\'. Expected type: {}.'
msg = msg.format(func.__qualname__, arg_name, type_hint)
RuntimeTypeCheckEnable._log.error(msg)
raise TypeError(msg)
def __matches(self, type_hint, arg) -> bool:
if self.__matches_base_types(type_hint, arg):
return True
elif self.__matches_type_types(type_hint, arg):
return True
elif self.__matches_union_types(type_hint, arg):
return True
elif self.__matches_tuple_types(type_hint, arg):
return True
elif self.__matches_dict_types(type_hint, arg):
return True
else:
return self.__matches_callable(type_hint, arg)
def __matches_base_types(self, type_hint, arg) -> bool:
return type_hint == type(arg)
def __matches_type_types(self, type_hint, arg) -> bool:
try:
if not type_hint.__origin__ == type:
return False
hint_args = type_hint.__args__
except AttributeError:
return False
return arg in hint_args
def __matches_union_types(self, type_hint, arg) -> bool:
try:
if not type_hint.__origin__ == Union:
return False
except AttributeError:
return False
# If Matches if true for an Union hint:
for hint in type_hint.__args__:
if self.__matches(hint, arg):
return True
return False
def __matches_tuple_types(self, type_hint, arg) -> bool:
try:
if not (type_hint.__origin__ == tuple and type(arg) == tuple):
return False
except AttributeError:
return False
if arg == ():
return True
if Ellipsis in type_hint.__args__:
fn = self.__matches_var_length_tuple
else:
fn = self.__matches_fixed_size_tuple
return fn(type_hint, arg)
def __matches_fixed_size_tuple(self, type_hint, arg) -> bool:
# To pass, the entire tuple must match in length and all types
expand_hint = type_hint.__args__
if len(expand_hint) != len(arg):
return False
for hint, value in zip(expand_hint, arg):
if not self.__matches(hint, value):
return False
return True
def __matches_var_length_tuple(self, type_hint, arg) -> bool:
# To pass a tuple can be empty or all contents must match the given type.
hint, _ = type_hint.__args__
for value in arg:
if not self.__matches(hint, value):
return False
return True
def __matches_dict_types(self, type_hint, arg) -> bool:
# To pass the hint must be a Dictionary and arg must match the given types.
try:
if not (type_hint.__origin__ == dict and type(arg) == dict):
return False
except AttributeError:
return False
key_type, val_type = type_hint.__args__
for k, v in arg.items():
if type(k) != key_type or type(v) != val_type:
return False
return True
def __matches_callable(self, type_hint, arg) -> bool:
# Return if the given hint is no callable
try:
if not type_hint.__origin__ == collections.abc.Callable:
return False
except AttributeError:
return False
# Verify that are is some form of callable.:
# 1) Check if it is either a function or a method
# 2) If it is an object, check if it has a __call__ method. If so use call for checks.
if not (isfunction(arg) or ismethod(arg)):
try:
arg = getattr(arg, '__call__')
except AttributeError:
return False
# Examine signature of given callable
sig_args = signature(arg).parameters
hint_args = type_hint.__args__
# Verify Parameter list length
if len(sig_args) != len(hint_args[:-1]):
return False
return True

View File

@@ -0,0 +1,80 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
from functools import wraps
from typing import Any, Callable, Tuple, Optional
from .log import LogConfig, Log
__all__ = [
'ScopedLogEnable'
]
class _ScopedLog:
__log = Log.get_instance()
def __init__(self, config: LogConfig):
self.__config: LogConfig = config
self.__old_config: Optional[LogConfig] = None
def __enter__(self):
self.__old_config = _ScopedLog.__log.get_config()
_ScopedLog.__log.enable(self.__config)
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
if self.__old_config:
_ScopedLog.__log.enable(self.__old_config)
else:
_ScopedLog.__log.disable()
class ScopedLogEnable:
"""Decorator: Enables logging facility before execution of the wrapped function
and disables logging after exiting the wrapped function. This allows more specific
logging of a code section compared to enabling or disabling the global logging mechanism.
Arguments:
config: The configuration the log should be enabled with.
"""
def __init__(self, config: LogConfig):
"""Add scoped logging to a Callable.
Arguments:
config: The configuration the log should be enabled with.
"""
self.__config = config
def __call__(self, func: Callable[..., Any]):
@wraps(func)
def wrapper(*args: Tuple[Any, ...]):
with _ScopedLog(self.__config):
return func(*args)
return wrapper

View File

@@ -0,0 +1,136 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
from functools import reduce, wraps
from inspect import signature
from .log import Log
__all__ = [
'TraceEnable'
]
_FMT_MSG_ENTRY: str = 'Enter | {}'
_FMT_MSG_LEAVE: str = 'Leave | {}'
_FMT_MSG_RAISE: str = 'Raise | {}, {}'
_FMT_ERROR: str = 'ErrorType: {}, ErrorValue: {}'
_INDENT_PER_LEVEL: str = ' '
def _args_to_str(func, *args, **kwargs) -> str:
# Expand function signature
sig = signature(func).bind(*args, **kwargs)
sig.apply_defaults()
full_args = sig.arguments
# Early return if there is nothing to print
if not full_args:
return '(None)'
def fold(args_as_str: str, arg):
name, value = arg
if name == 'self':
arg_str = 'self'
else:
arg_str = str(value)
return '{}{}, '.format(args_as_str, arg_str)
return '({})'.format(reduce(fold, full_args.items(), '')[:-2])
def _get_indent(level: int) -> str:
return _INDENT_PER_LEVEL * level
def _create_enter_msg(name: str, level: int, args_str: str) -> str:
msg = '{}{}{}'.format(_get_indent(level), name, args_str)
return _FMT_MSG_ENTRY.format(msg)
def _create_leave_msg(name: str, level: int, ) -> str:
msg = '{}{}'.format(_get_indent(level), name)
return _FMT_MSG_LEAVE.format(msg)
def _create_raise_msg(name: str, level: int, exc_type: Exception, exc_value: str) -> str:
msg = '{}{}'.format(_get_indent(level), name)
exc = _FMT_ERROR.format(exc_type, exc_value)
return _FMT_MSG_RAISE.format(msg, exc)
class _Tracer:
__log = Log.get_instance()
__level: int = 0
@staticmethod
def is_log_enabled() -> bool:
return bool(_Tracer.__log)
def __init__(self, func, *args, **kwargs):
self.__full_name: str = '{}.{}'.format(func.__module__, func.__qualname__)
self.__full_args: str = _args_to_str(func, *args, **kwargs)
def __enter__(self):
msg = _create_enter_msg(self.__full_name, _Tracer.__level, self.__full_args)
_Tracer.__log.trace(msg)
_Tracer.__level += 1
def __exit__(self, exc_type, exc_value, exc_traceback):
_Tracer.__level -= 1
if exc_type:
msg = _create_raise_msg(self.__full_name, _Tracer.__level, exc_type, exc_value)
else:
msg = _create_leave_msg(self.__full_name, _Tracer.__level)
_Tracer.__log.trace(msg)
class TraceEnable:
"""Decorator: Adds an entry of LogLevel. Trace on entry and exit of the wrapped function.
On exit, the log entry contains information if the function was left normally or with an
exception.
"""
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
if _Tracer.is_log_enabled():
with _Tracer(func, *args, **kwargs):
result = func(*args, **kwargs)
return result
else:
return func(*args, **kwargs)
return wrapper

View File

@@ -0,0 +1,600 @@
"""BSD 2-Clause License
Copyright (c) 2019, Allied Vision Technologies GmbH
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
import threading
from typing import List, Dict, Tuple
from .c_binding import call_vimba_c, VIMBA_C_VERSION, VIMBA_IMAGE_TRANSFORM_VERSION, \
G_VIMBA_C_HANDLE
from .feature import discover_features, FeatureTypes, FeaturesTuple, FeatureTypeTypes, EnumFeature
from .shared import filter_features_by_name, filter_features_by_type, filter_affected_features, \
filter_selected_features, filter_features_by_category, \
attach_feature_accessors, remove_feature_accessors, read_memory, \
write_memory, read_registers, write_registers
from .interface import Interface, InterfaceChangeHandler, InterfaceEvent, InterfacesTuple, \
InterfacesList, discover_interfaces, discover_interface
from .camera import Camera, CamerasList, CameraChangeHandler, CameraEvent, CamerasTuple, \
discover_cameras, discover_camera
from .util import Log, LogConfig, TraceEnable, RuntimeTypeCheckEnable, EnterContextOnCall, \
LeaveContextOnCall, RaiseIfInsideContext, RaiseIfOutsideContext
from .error import VimbaCameraError, VimbaInterfaceError, VimbaFeatureError
from . import __version__ as VIMBA_PYTHON_VERSION
__all__ = [
'Vimba',
]
class Vimba:
class __Impl:
"""This class allows access to the entire Vimba System.
Vimba is meant be used in conjunction with the "with" - Statement, upon
entering the context, all system features, connected cameras and interfaces are detected
and can be used.
"""
@TraceEnable()
@LeaveContextOnCall()
def __init__(self):
"""Do not call directly. Use Vimba.get_instance() instead."""
self.__feats: FeaturesTuple = ()
self.__inters: InterfacesList = ()
self.__inters_lock: threading.Lock = threading.Lock()
self.__inters_handlers: List[InterfaceChangeHandler] = []
self.__inters_handlers_lock: threading.Lock = threading.Lock()
self.__cams: CamerasList = ()
self.__cams_lock: threading.Lock = threading.Lock()
self.__cams_handlers: List[CameraChangeHandler] = []
self.__cams_handlers_lock: threading.Lock = threading.Lock()
self.__nw_discover: bool = True
self.__context_cnt: int = 0
@TraceEnable()
def __enter__(self):
if not self.__context_cnt:
self._startup()
self.__context_cnt += 1
return self
@TraceEnable()
def __exit__(self, exc_type, exc_value, exc_traceback):
self.__context_cnt -= 1
if not self.__context_cnt:
self._shutdown()
def get_version(self) -> str:
""" Returns version string of VimbaPython and underlaying dependencies."""
msg = 'VimbaPython: {} (using VimbaC: {}, VimbaImageTransform: {})'
return msg.format(VIMBA_PYTHON_VERSION, VIMBA_C_VERSION, VIMBA_IMAGE_TRANSFORM_VERSION)
@RaiseIfInsideContext()
@RuntimeTypeCheckEnable()
def set_network_discovery(self, enable: bool):
"""Enable/Disable network camera discovery.
Arguments:
enable - If 'True' VimbaPython tries to detect cameras connected via Ethernet
on entering the 'with' statement. If set to 'False', no network
discover occurs.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError if called inside with-statement.
"""
self.__nw_discover = enable
@RuntimeTypeCheckEnable()
def enable_log(self, config: LogConfig):
"""Enable VimbaPython's logging mechanism.
Arguments:
config - Configuration for the logging mechanism.
Raises:
TypeError if parameters do not match their type hint.
"""
Log.get_instance().enable(config)
def disable_log(self):
"""Disable VimbaPython's logging mechanism."""
Log.get_instance().disable()
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def read_memory(self, addr: int, max_bytes: int) -> bytes: # coverage: skip
"""Read a byte sequence from a given memory address.
Arguments:
addr: Starting address to read from.
max_bytes: Maximum number of bytes to read from addr.
Returns:
Read memory contents as bytes.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
ValueError if addr is negative
ValueError if max_bytes is negative.
ValueError if the memory access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return read_memory(G_VIMBA_C_HANDLE, addr, max_bytes)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def write_memory(self, addr: int, data: bytes): # coverage: skip
""" Write a byte sequence to a given memory address.
Arguments:
addr: Address to write the content of 'data' too.
data: Byte sequence to write at address 'addr'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
ValueError if addr is negative.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return write_memory(G_VIMBA_C_HANDLE, addr, data)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def read_registers(self, addrs: Tuple[int, ...]) -> Dict[int, int]: # coverage: skip
"""Read contents of multiple registers.
Arguments:
addrs: Sequence of addresses that should be read iteratively.
Return:
Dictionary containing a mapping from given address to the read register values.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
ValueError if any address in addrs_values is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return read_registers(G_VIMBA_C_HANDLE, addrs)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def write_registers(self, addrs_values: Dict[int, int]): # coverage: skip
"""Write data to multiple Registers.
Arguments:
addrs_values: Mapping between Register addresses and the data to write.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
ValueError if any address in addrs is negative.
ValueError if the register access was invalid.
"""
# Note: Coverage is skipped. Function is untestable in a generic way.
return write_registers(G_VIMBA_C_HANDLE, addrs_values)
@RaiseIfOutsideContext()
def get_all_interfaces(self) -> InterfacesTuple:
"""Get access to all discovered Interfaces:
Returns:
A set of all currently detected Interfaces.
Raises:
RuntimeError then called outside of "with" - statement.
"""
with self.__inters_lock:
return tuple(self.__inters)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_interface_by_id(self, id_: str) -> Interface:
"""Lookup Interface with given ID.
Arguments:
id_ - Interface Id to search for.
Returns:
Interface associated with given Id.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
VimbaInterfaceError if interface with id_ can't be found.
"""
with self.__inters_lock:
inter = [inter for inter in self.__inters if id_ == inter.get_id()]
if not inter:
raise VimbaInterfaceError('Interface with ID \'{}\' not found.'.format(id_))
return inter.pop()
@RaiseIfOutsideContext()
def get_all_cameras(self) -> CamerasTuple:
"""Get access to all discovered Cameras.
Returns:
A set of all currently detected Cameras.
Raises:
RuntimeError then called outside of "with" - statement.
"""
with self.__cams_lock:
return tuple(self.__cams)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_camera_by_id(self, id_: str) -> Camera:
"""Lookup Camera with given ID.
Arguments:
id_ - Camera Id to search for. For GigE - Cameras, the IP and MAC-Address
can be used to Camera lookup
Returns:
Camera associated with given Id.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
VimbaCameraError if camera with id_ can't be found.
"""
with self.__cams_lock:
# Search for given Camera Id in all currently detected cameras.
for cam in self.__cams:
if id_ == cam.get_id():
return cam
# If a search by ID fails, the given id_ is almost certain an IP or MAC - Address.
# Try to query this Camera.
try:
cam_info = discover_camera(id_)
# Since cam_info is newly constructed, search in existing cameras for a Camera
for cam in self.__cams:
if cam_info.get_id() == cam.get_id():
return cam
except VimbaCameraError:
pass
raise VimbaCameraError('No Camera with Id \'{}\' available.'.format(id_))
@RaiseIfOutsideContext()
def get_all_features(self) -> FeaturesTuple:
"""Get access to all discovered system features:
Returns:
A set of all currently detected Features.
Raises:
RuntimeError then called outside of "with" - statement.
"""
return self.__feats
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_affected_by(self, feat: FeatureTypes) -> FeaturesTuple:
"""Get all system features affected by a specific system feature.
Arguments:
feat - Feature used find features that are affected by feat.
Returns:
A set of features affected by changes on 'feat'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
VimbaFeatureError if 'feat' is not a system feature.
"""
return filter_affected_features(self.__feats, feat)
@TraceEnable()
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_selected_by(self, feat: FeatureTypes) -> FeaturesTuple:
"""Get all system features selected by a specific system feature.
Arguments:
feat - Feature used find features that are selected by feat.
Returns:
A set of features selected by 'feat'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
VimbaFeatureError if 'feat' is not a system feature.
"""
return filter_selected_features(self.__feats, feat)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_type(self, feat_type: FeatureTypeTypes) -> FeaturesTuple:
"""Get all system features of a specific feature type.
Valid FeatureTypes are: IntFeature, FloatFeature, StringFeature, BoolFeature,
EnumFeature, CommandFeature, RawFeature
Arguments:
feat_type - FeatureType used find features of that type.
Returns:
A set of features of type 'feat_type'.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
"""
return filter_features_by_type(self.__feats, feat_type)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_features_by_category(self, category: str) -> FeaturesTuple:
"""Get all system features of a specific category.
Arguments:
category - Category that should be used for filtering.
Returns:
A set of features of category 'category'.
Returns:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
"""
return filter_features_by_category(self.__feats, category)
@RaiseIfOutsideContext()
@RuntimeTypeCheckEnable()
def get_feature_by_name(self, feat_name: str) -> FeatureTypes:
"""Get a system feature by its name.
Arguments:
feat_name - Name used to find a feature.
Returns:
Feature with the associated name.
Raises:
TypeError if parameters do not match their type hint.
RuntimeError then called outside of "with" - statement.
VimbaFeatureError if no feature is associated with 'feat_name'.
"""
feat = filter_features_by_name(self.__feats, feat_name)
if not feat:
raise VimbaFeatureError('Feature \'{}\' not found.'.format(feat_name))
return feat
@RuntimeTypeCheckEnable()
def register_camera_change_handler(self, handler: CameraChangeHandler):
"""Add Callable what is executed on camera connect/disconnect
Arguments:
handler - The change handler that shall be added.
Raises:
TypeError if parameters do not match their type hint.
"""
with self.__cams_handlers_lock:
if handler not in self.__cams_handlers:
self.__cams_handlers.append(handler)
def unregister_all_camera_change_handlers(self):
"""Remove all currently registered camera change handlers"""
with self.__cams_handlers_lock:
if self.__cams_handlers:
self.__cams_handlers.clear()
@RuntimeTypeCheckEnable()
def unregister_camera_change_handler(self, handler: CameraChangeHandler):
"""Remove previously registered camera change handler
Arguments:
handler - The change handler that shall be removed.
Raises:
TypeError if parameters do not match their type hint.
"""
with self.__cams_handlers_lock:
if handler in self.__cams_handlers:
self.__cams_handlers.remove(handler)
@RuntimeTypeCheckEnable()
def register_interface_change_handler(self, handler: InterfaceChangeHandler):
"""Add Callable what is executed on interface connect/disconnect
Arguments:
handler - The change handler that shall be added.
Raises:
TypeError if parameters do not match their type hint.
"""
with self.__inters_handlers_lock:
if handler not in self.__inters_handlers:
self.__inters_handlers.append(handler)
def unregister_all_interface_change_handlers(self):
"""Remove all currently registered interface change handlers"""
with self.__inters_handlers_lock:
if self.__inters_handlers:
self.__inters_handlers.clear()
@RuntimeTypeCheckEnable()
def unregister_interface_change_handler(self, handler: InterfaceChangeHandler):
"""Remove previously registered interface change handler
Arguments:
handler - The change handler that shall be removed.
Raises:
TypeError if parameters do not match their type hint.
"""
with self.__inters_handlers_lock:
if handler in self.__inters_handlers:
self.__inters_handlers.remove(handler)
@TraceEnable()
@EnterContextOnCall()
def _startup(self):
Log.get_instance().info('Starting {}'.format(self.get_version()))
call_vimba_c('VmbStartup')
self.__inters = discover_interfaces()
self.__cams = discover_cameras(self.__nw_discover)
self.__feats = discover_features(G_VIMBA_C_HANDLE)
attach_feature_accessors(self, self.__feats)
feat = self.get_feature_by_name('DiscoveryInterfaceEvent')
feat.register_change_handler(self.__inter_cb_wrapper)
feat = self.get_feature_by_name('DiscoveryCameraEvent')
feat.register_change_handler(self.__cam_cb_wrapper)
@TraceEnable()
@LeaveContextOnCall()
def _shutdown(self):
self.unregister_all_camera_change_handlers()
self.unregister_all_interface_change_handlers()
for feat in self.__feats:
feat.unregister_all_change_handlers()
remove_feature_accessors(self, self.__feats)
self.__feats = ()
self.__cams_handlers = []
self.__cams = ()
self.__inters_handlers = []
self.__inters = ()
call_vimba_c('VmbShutdown')
def __cam_cb_wrapper(self, cam_event: EnumFeature): # coverage: skip
# Skip coverage because it can't be measured. This is called from C-Context
event = CameraEvent(int(cam_event.get()))
cam = None
cam_id = self.get_feature_by_name('DiscoveryCameraIdent').get()
log = Log.get_instance()
# New camera found: Add it to camera list
if event == CameraEvent.Detected:
cam = discover_camera(cam_id)
with self.__cams_lock:
self.__cams.append(cam)
log.info('Added camera \"{}\" to active cameras'.format(cam_id))
# Existing camera lost. Remove it from active cameras
elif event == CameraEvent.Missing:
with self.__cams_lock:
cam = [c for c in self.__cams if cam_id == c.get_id()].pop()
cam._disconnected = True
self.__cams.remove(cam)
log.info('Removed camera \"{}\" from active cameras'.format(cam_id))
else:
cam = self.get_camera_by_id(cam_id)
with self.__cams_handlers_lock:
for handler in self.__cams_handlers:
try:
handler(cam, event)
except Exception as e:
msg = 'Caught Exception in handler: '
msg += 'Type: {}, '.format(type(e))
msg += 'Value: {}, '.format(e)
msg += 'raised by: {}'.format(handler)
Log.get_instance().error(msg)
raise e
def __inter_cb_wrapper(self, inter_event: EnumFeature): # coverage: skip
# Skip coverage because it can't be measured. This is called from C-Context
event = InterfaceEvent(int(inter_event.get()))
inter = None
inter_id = self.get_feature_by_name('DiscoveryInterfaceIdent').get()
log = Log.get_instance()
# New interface found: Add it to interface list
if event == InterfaceEvent.Detected:
inter = discover_interface(inter_id)
with self.__inters_lock:
self.__inters.append(inter)
log.info('Added interface \"{}\" to active interfaces'.format(inter_id))
# Existing interface lost. Remove it from active interfaces
elif event == InterfaceEvent.Missing:
with self.__inters_lock:
inter = [i for i in self.__inters if inter_id == i.get_id()].pop()
self.__inters.remove(inter)
log.info('Removed interface \"{}\" from active interfaces'.format(inter_id))
else:
inter = self.get_interface_by_id(inter_id)
with self.__inters_handlers_lock:
for handler in self.__inters_handlers:
try:
handler(inter, event)
except Exception as e:
msg = 'Caught Exception in handler: '
msg += 'Type: {}, '.format(type(e))
msg += 'Value: {}, '.format(e)
msg += 'raised by: {}'.format(handler)
Log.get_instance().error(msg)
raise e
__instance = __Impl()
@staticmethod
@TraceEnable()
def get_instance() -> '__Impl':
"""Get VimbaSystem Singleton."""
return Vimba.__instance