pyhikrobot 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hikrobot/__init__.py +97 -0
- hikrobot/_ctypes_defs.py +568 -0
- hikrobot/_errors.py +490 -0
- hikrobot/_loader.py +295 -0
- hikrobot/camera.py +680 -0
- hikrobot/device.py +212 -0
- hikrobot/frame.py +308 -0
- hikrobot/nodes.py +275 -0
- hikrobot/py.typed +0 -0
- pyhikrobot-0.1.0.dist-info/METADATA +234 -0
- pyhikrobot-0.1.0.dist-info/RECORD +14 -0
- pyhikrobot-0.1.0.dist-info/WHEEL +4 -0
- pyhikrobot-0.1.0.dist-info/licenses/LICENSE +201 -0
- pyhikrobot-0.1.0.dist-info/licenses/NOTICE +11 -0
hikrobot/__init__.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Thin, zero-copy Python bindings for Hikrobot machine-vision cameras (MVS SDK).
|
|
3
|
+
|
|
4
|
+
Importing this package never loads the vendor SDK: the shared library is located and
|
|
5
|
+
opened lazily on first real use, so ``import hikrobot`` succeeds on machines with no
|
|
6
|
+
SDK and no camera attached. A missing SDK surfaces as :class:`SDKNotFoundError` at
|
|
7
|
+
call time.
|
|
8
|
+
|
|
9
|
+
Every failure derives from :class:`HikrobotError`. A status returned by the SDK becomes a
|
|
10
|
+
:class:`StatusError` subclass chosen by the code; the raw ``MV_E_*`` values stay internal
|
|
11
|
+
and are reachable through :attr:`StatusError.status` and :attr:`StatusError.name`.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"AccessDeniedError",
|
|
18
|
+
"BufferInUseError",
|
|
19
|
+
"BufferReleasedError",
|
|
20
|
+
"CallOrderError",
|
|
21
|
+
"Camera",
|
|
22
|
+
"CameraStateError",
|
|
23
|
+
"CameraTimeoutError",
|
|
24
|
+
"DeviceBusyError",
|
|
25
|
+
"DeviceInfo",
|
|
26
|
+
"FloatRange",
|
|
27
|
+
"Frame",
|
|
28
|
+
"GenICamError",
|
|
29
|
+
"GeneralError",
|
|
30
|
+
"GigEError",
|
|
31
|
+
"HikrobotError",
|
|
32
|
+
"IPConflictError",
|
|
33
|
+
"IncompleteImageError",
|
|
34
|
+
"InsufficientBufferError",
|
|
35
|
+
"IntRange",
|
|
36
|
+
"InvalidHandleError",
|
|
37
|
+
"NetworkError",
|
|
38
|
+
"NoDataError",
|
|
39
|
+
"NodeAccessError",
|
|
40
|
+
"NodeMap",
|
|
41
|
+
"NotImplementedByDeviceError",
|
|
42
|
+
"NotSupportedError",
|
|
43
|
+
"PacketError",
|
|
44
|
+
"ParameterError",
|
|
45
|
+
"PreconditionError",
|
|
46
|
+
"SDKLoadError",
|
|
47
|
+
"SDKNotFoundError",
|
|
48
|
+
"StatusError",
|
|
49
|
+
"TransportStats",
|
|
50
|
+
"USBBandwidthError",
|
|
51
|
+
"USBError",
|
|
52
|
+
"UnsupportedPixelFormatError",
|
|
53
|
+
"UnsupportedPlatformError",
|
|
54
|
+
"UpgradeError",
|
|
55
|
+
"ValueOutOfRangeError",
|
|
56
|
+
"__version__",
|
|
57
|
+
"enumerate_devices",
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
from ._errors import (
|
|
61
|
+
AccessDeniedError,
|
|
62
|
+
BufferInUseError,
|
|
63
|
+
BufferReleasedError,
|
|
64
|
+
CallOrderError,
|
|
65
|
+
CameraStateError,
|
|
66
|
+
CameraTimeoutError,
|
|
67
|
+
DeviceBusyError,
|
|
68
|
+
GeneralError,
|
|
69
|
+
GenICamError,
|
|
70
|
+
GigEError,
|
|
71
|
+
HikrobotError,
|
|
72
|
+
IncompleteImageError,
|
|
73
|
+
InsufficientBufferError,
|
|
74
|
+
InvalidHandleError,
|
|
75
|
+
IPConflictError,
|
|
76
|
+
NetworkError,
|
|
77
|
+
NoDataError,
|
|
78
|
+
NodeAccessError,
|
|
79
|
+
NotImplementedByDeviceError,
|
|
80
|
+
NotSupportedError,
|
|
81
|
+
PacketError,
|
|
82
|
+
ParameterError,
|
|
83
|
+
PreconditionError,
|
|
84
|
+
SDKLoadError,
|
|
85
|
+
SDKNotFoundError,
|
|
86
|
+
StatusError,
|
|
87
|
+
UnsupportedPixelFormatError,
|
|
88
|
+
UnsupportedPlatformError,
|
|
89
|
+
UpgradeError,
|
|
90
|
+
USBBandwidthError,
|
|
91
|
+
USBError,
|
|
92
|
+
ValueOutOfRangeError,
|
|
93
|
+
)
|
|
94
|
+
from .camera import Camera, TransportStats
|
|
95
|
+
from .device import DeviceInfo, enumerate_devices
|
|
96
|
+
from .frame import Frame
|
|
97
|
+
from .nodes import FloatRange, IntRange, NodeMap
|
hikrobot/_ctypes_defs.py
ADDED
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""ctypes transcription of the MVS structures needed to enumerate, open and grab.
|
|
3
|
+
|
|
4
|
+
Hand-written from the vendor C headers of MVS SDK 4.4.1 - ``CameraParams.h`` for the
|
|
5
|
+
structures and constants, ``MvCameraControl.h`` for the entry-point signatures. Only what
|
|
6
|
+
the enumerate/open/grab path needs is here; everything else is transcribed on demand.
|
|
7
|
+
|
|
8
|
+
Field names keep the vendor's spelling (``nWidth``, ``chSerialNumber``) so that a reader
|
|
9
|
+
can diff this file against the header line by line. Turning them into Python names is the
|
|
10
|
+
job of the public layer.
|
|
11
|
+
|
|
12
|
+
Three details that a careless transcription gets wrong:
|
|
13
|
+
|
|
14
|
+
* ``MvGvspPixelType`` contains ``PixelType_Gvsp_Undefined = 0xFFFFFFFF`` and a custom-format
|
|
15
|
+
bit of ``0x80000000``, so its values do not fit in a signed ``int``. The C enum is
|
|
16
|
+
therefore unsigned, and ``enPixelType`` must be read as :class:`ctypes.c_uint` - as a
|
|
17
|
+
signed field every custom 3D format would come back negative.
|
|
18
|
+
* ``MV_CC_DEVICE_INFO`` ends in a union of six transport-specific structures. Only the
|
|
19
|
+
GigE and USB3 members are ever read here, but every member has to be transcribed or the
|
|
20
|
+
union - and with it the whole device list - comes out the wrong size.
|
|
21
|
+
* The structures are naturally aligned, not packed. ``MV_FRAME_OUT_INFO_EX`` even carries
|
|
22
|
+
an explicit ``nReserved0`` whose header comment says it is there to 8-byte-align the
|
|
23
|
+
``int64_t`` that follows, which confirms the vendor compiles with default alignment.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import ctypes
|
|
29
|
+
from ctypes import (
|
|
30
|
+
POINTER,
|
|
31
|
+
Structure,
|
|
32
|
+
Union,
|
|
33
|
+
c_bool,
|
|
34
|
+
c_char,
|
|
35
|
+
c_char_p,
|
|
36
|
+
c_float,
|
|
37
|
+
c_int,
|
|
38
|
+
c_int64,
|
|
39
|
+
c_ubyte,
|
|
40
|
+
c_uint,
|
|
41
|
+
c_uint64,
|
|
42
|
+
c_ushort,
|
|
43
|
+
c_void_p,
|
|
44
|
+
)
|
|
45
|
+
from typing import Any
|
|
46
|
+
|
|
47
|
+
from . import _loader
|
|
48
|
+
|
|
49
|
+
# --------------------------------------------------------------------------------------
|
|
50
|
+
# Constants (CameraParams.h)
|
|
51
|
+
# --------------------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
INFO_MAX_BUFFER_SIZE = 64
|
|
54
|
+
MV_MAX_DEVICE_NUM = 256
|
|
55
|
+
|
|
56
|
+
# Device transport layer protocol type, passed to MV_CC_EnumDevices as a bit mask.
|
|
57
|
+
MV_UNKNOW_DEVICE = 0x00000000
|
|
58
|
+
MV_GIGE_DEVICE = 0x00000001
|
|
59
|
+
MV_1394_DEVICE = 0x00000002
|
|
60
|
+
MV_USB_DEVICE = 0x00000004
|
|
61
|
+
MV_CAMERALINK_DEVICE = 0x00000008
|
|
62
|
+
MV_VIR_GIGE_DEVICE = 0x00000010
|
|
63
|
+
MV_VIR_USB_DEVICE = 0x00000020
|
|
64
|
+
MV_GENTL_GIGE_DEVICE = 0x00000040
|
|
65
|
+
MV_GENTL_CAMERALINK_DEVICE = 0x00000080
|
|
66
|
+
MV_GENTL_CXP_DEVICE = 0x00000100
|
|
67
|
+
MV_GENTL_XOF_DEVICE = 0x00000200
|
|
68
|
+
|
|
69
|
+
# Device access mode, passed to MV_CC_OpenDevice.
|
|
70
|
+
MV_ACCESS_Exclusive = 1
|
|
71
|
+
MV_ACCESS_ExclusiveWithSwitch = 2
|
|
72
|
+
MV_ACCESS_Control = 3
|
|
73
|
+
MV_ACCESS_ControlWithSwitch = 4
|
|
74
|
+
MV_ACCESS_ControlSwitchEnable = 5
|
|
75
|
+
MV_ACCESS_ControlSwitchEnableWithKey = 6
|
|
76
|
+
MV_ACCESS_Monitor = 7
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# --------------------------------------------------------------------------------------
|
|
80
|
+
# Device information (CameraParams.h)
|
|
81
|
+
# --------------------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class MV_GIGE_DEVICE_INFO(Structure):
|
|
85
|
+
"""GigE Vision device information."""
|
|
86
|
+
|
|
87
|
+
_fields_ = [
|
|
88
|
+
("nIpCfgOption", c_uint),
|
|
89
|
+
("nIpCfgCurrent", c_uint),
|
|
90
|
+
("nCurrentIp", c_uint),
|
|
91
|
+
("nCurrentSubNetMask", c_uint),
|
|
92
|
+
("nDefultGateWay", c_uint),
|
|
93
|
+
("chManufacturerName", c_ubyte * 32),
|
|
94
|
+
("chModelName", c_ubyte * 32),
|
|
95
|
+
("chDeviceVersion", c_ubyte * 32),
|
|
96
|
+
("chManufacturerSpecificInfo", c_ubyte * 48),
|
|
97
|
+
("chSerialNumber", c_ubyte * 16),
|
|
98
|
+
("chUserDefinedName", c_ubyte * 16),
|
|
99
|
+
("nNetExport", c_uint),
|
|
100
|
+
("nReserved", c_uint * 4),
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class MV_USB3_DEVICE_INFO(Structure):
|
|
105
|
+
"""USB3 Vision device information."""
|
|
106
|
+
|
|
107
|
+
_fields_ = [
|
|
108
|
+
("CrtlInEndPoint", c_ubyte),
|
|
109
|
+
("CrtlOutEndPoint", c_ubyte),
|
|
110
|
+
("StreamEndPoint", c_ubyte),
|
|
111
|
+
("EventEndPoint", c_ubyte),
|
|
112
|
+
("idVendor", c_ushort),
|
|
113
|
+
("idProduct", c_ushort),
|
|
114
|
+
("nDeviceNumber", c_uint),
|
|
115
|
+
("chDeviceGUID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
116
|
+
("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
117
|
+
("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
118
|
+
("chFamilyName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
119
|
+
("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
120
|
+
("chManufacturerName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
121
|
+
("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
122
|
+
("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
123
|
+
("nbcdUSB", c_uint),
|
|
124
|
+
("nDeviceAddress", c_uint),
|
|
125
|
+
("nReserved", c_uint * 2),
|
|
126
|
+
]
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class MV_CamL_DEV_INFO(Structure):
|
|
130
|
+
"""Camera Link device information."""
|
|
131
|
+
|
|
132
|
+
_fields_ = [
|
|
133
|
+
("chPortID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
134
|
+
("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
135
|
+
("chFamilyName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
136
|
+
("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
137
|
+
("chManufacturerName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
138
|
+
("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
139
|
+
("nReserved", c_uint * 38),
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class MV_CXP_DEVICE_INFO(Structure):
|
|
144
|
+
"""CoaXPress device information, as reported by a frame grabber."""
|
|
145
|
+
|
|
146
|
+
_fields_ = [
|
|
147
|
+
("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
148
|
+
("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
149
|
+
("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
150
|
+
("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
151
|
+
("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
152
|
+
("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
153
|
+
("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
154
|
+
("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
155
|
+
("nReserved", c_uint * 7),
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class MV_CML_DEVICE_INFO(Structure):
|
|
160
|
+
"""Camera Link device information, as reported by a frame grabber."""
|
|
161
|
+
|
|
162
|
+
_fields_ = [
|
|
163
|
+
("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
164
|
+
("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
165
|
+
("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
166
|
+
("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
167
|
+
("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
168
|
+
("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
169
|
+
("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
170
|
+
("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
171
|
+
("nReserved", c_uint * 7),
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class MV_XOF_DEVICE_INFO(Structure):
|
|
176
|
+
"""XoFLink device information, as reported by a frame grabber."""
|
|
177
|
+
|
|
178
|
+
_fields_ = [
|
|
179
|
+
("chInterfaceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
180
|
+
("chVendorName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
181
|
+
("chModelName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
182
|
+
("chManufacturerInfo", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
183
|
+
("chDeviceVersion", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
184
|
+
("chSerialNumber", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
185
|
+
("chUserDefinedName", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
186
|
+
("chDeviceID", c_ubyte * INFO_MAX_BUFFER_SIZE),
|
|
187
|
+
("nReserved", c_uint * 7),
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class _SpecialInfo(Union):
|
|
192
|
+
_fields_ = [
|
|
193
|
+
("stGigEInfo", MV_GIGE_DEVICE_INFO),
|
|
194
|
+
("stUsb3VInfo", MV_USB3_DEVICE_INFO),
|
|
195
|
+
("stCamLInfo", MV_CamL_DEV_INFO),
|
|
196
|
+
("stCMLInfo", MV_CML_DEVICE_INFO),
|
|
197
|
+
("stCXPInfo", MV_CXP_DEVICE_INFO),
|
|
198
|
+
("stXoFInfo", MV_XOF_DEVICE_INFO),
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class MV_CC_DEVICE_INFO(Structure):
|
|
203
|
+
"""One enumerated device.
|
|
204
|
+
|
|
205
|
+
``nTLayerType`` selects which member of ``SpecialInfo`` is the valid one; reading the
|
|
206
|
+
wrong member yields plausible-looking garbage rather than an error.
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
_fields_ = [
|
|
210
|
+
("nMajorVer", c_ushort),
|
|
211
|
+
("nMinorVer", c_ushort),
|
|
212
|
+
("nMacAddrHigh", c_uint),
|
|
213
|
+
("nMacAddrLow", c_uint),
|
|
214
|
+
("nTLayerType", c_uint),
|
|
215
|
+
("nDevTypeInfo", c_uint),
|
|
216
|
+
("nReserved", c_uint * 3),
|
|
217
|
+
("SpecialInfo", _SpecialInfo),
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class MV_CC_DEVICE_INFO_LIST(Structure):
|
|
222
|
+
"""Result of ``MV_CC_EnumDevices``.
|
|
223
|
+
|
|
224
|
+
The SDK owns the pointed-to device structures. They stay valid only until the next
|
|
225
|
+
enumeration, so anything worth keeping must be copied out.
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
_fields_ = [
|
|
229
|
+
("nDeviceNum", c_uint),
|
|
230
|
+
("pDeviceInfo", POINTER(MV_CC_DEVICE_INFO) * MV_MAX_DEVICE_NUM),
|
|
231
|
+
]
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# --------------------------------------------------------------------------------------
|
|
235
|
+
# Frames (CameraParams.h)
|
|
236
|
+
# --------------------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class _UnparsedChunkList(Union):
|
|
240
|
+
_fields_ = [
|
|
241
|
+
# MV_CHUNK_DATA_CONTENT*. Kept as an opaque pointer: chunk data is not parsed yet,
|
|
242
|
+
# and only the width of the member matters for the layout.
|
|
243
|
+
("pUnparsedChunkContent", c_void_p),
|
|
244
|
+
("nAligning", c_int64),
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
class MV_FRAME_OUT_INFO_EX(Structure):
|
|
249
|
+
"""Metadata of one grabbed frame.
|
|
250
|
+
|
|
251
|
+
``nWidth`` / ``nHeight`` saturate at 65535; the header directs callers to
|
|
252
|
+
``nExtendWidth`` / ``nExtendHeight`` above that. Likewise ``nFrameLen`` saturates at
|
|
253
|
+
4 GiB and ``nFrameLenEx`` carries the real length.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
_fields_ = [
|
|
257
|
+
("nWidth", c_ushort),
|
|
258
|
+
("nHeight", c_ushort),
|
|
259
|
+
# enum MvGvspPixelType - unsigned, see the module docstring.
|
|
260
|
+
("enPixelType", c_uint),
|
|
261
|
+
("nFrameNum", c_uint),
|
|
262
|
+
("nDevTimeStampHigh", c_uint),
|
|
263
|
+
("nDevTimeStampLow", c_uint),
|
|
264
|
+
("nReserved0", c_uint),
|
|
265
|
+
("nHostTimeStamp", c_int64),
|
|
266
|
+
("nFrameLen", c_uint),
|
|
267
|
+
("nSecondCount", c_uint),
|
|
268
|
+
("nCycleCount", c_uint),
|
|
269
|
+
("nCycleOffset", c_uint),
|
|
270
|
+
("fGain", c_float),
|
|
271
|
+
("fExposureTime", c_float),
|
|
272
|
+
("nAverageBrightness", c_uint),
|
|
273
|
+
("nRed", c_uint),
|
|
274
|
+
("nGreen", c_uint),
|
|
275
|
+
("nBlue", c_uint),
|
|
276
|
+
("nFrameCounter", c_uint),
|
|
277
|
+
("nTriggerIndex", c_uint),
|
|
278
|
+
("nInput", c_uint),
|
|
279
|
+
("nOutput", c_uint),
|
|
280
|
+
("nOffsetX", c_ushort),
|
|
281
|
+
("nOffsetY", c_ushort),
|
|
282
|
+
("nChunkWidth", c_ushort),
|
|
283
|
+
("nChunkHeight", c_ushort),
|
|
284
|
+
("nLostPacket", c_uint),
|
|
285
|
+
("nUnparsedChunkNum", c_uint),
|
|
286
|
+
("UnparsedChunkList", _UnparsedChunkList),
|
|
287
|
+
("nExtendWidth", c_uint),
|
|
288
|
+
("nExtendHeight", c_uint),
|
|
289
|
+
("nFrameLenEx", c_uint64),
|
|
290
|
+
("nReserved", c_uint * 32),
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class MV_FRAME_OUT(Structure):
|
|
295
|
+
"""A grabbed frame: a pointer into driver memory plus its metadata.
|
|
296
|
+
|
|
297
|
+
``pBufAddr`` is a node from the SDK's fixed pool, not memory this process owns. It is
|
|
298
|
+
valid only until the node goes back with ``MV_CC_FreeImageBuffer``; after that the
|
|
299
|
+
driver writes the next frame to the same address.
|
|
300
|
+
"""
|
|
301
|
+
|
|
302
|
+
_fields_ = [
|
|
303
|
+
("pBufAddr", POINTER(c_ubyte)),
|
|
304
|
+
("stFrameInfo", MV_FRAME_OUT_INFO_EX),
|
|
305
|
+
("nRes", c_uint * 16),
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# --------------------------------------------------------------------------------------
|
|
310
|
+
# Pixel formats (PixelType.h)
|
|
311
|
+
# --------------------------------------------------------------------------------------
|
|
312
|
+
#
|
|
313
|
+
# A pixel type packs three fields: bits 24-31 say monochrome/colour/custom, bits 16-23 the
|
|
314
|
+
# effective bits per pixel including padding, bits 0-15 an arbitrary id. Only the last is
|
|
315
|
+
# opaque, so bit depth is computable while the channel layout is not - hence the explicit
|
|
316
|
+
# table in `frame.py`.
|
|
317
|
+
|
|
318
|
+
MV_GVSP_PIX_MONO = 0x01000000
|
|
319
|
+
MV_GVSP_PIX_COLOR = 0x02000000
|
|
320
|
+
MV_GVSP_PIX_CUSTOM = 0x80000000
|
|
321
|
+
MV_GVSP_PIX_COLOR_MASK = 0xFF000000
|
|
322
|
+
MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK = 0x00FF0000
|
|
323
|
+
MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT = 16
|
|
324
|
+
MV_GVSP_PIX_ID_MASK = 0x0000FFFF
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def _pixel(color: int, bits: int, identifier: int) -> int:
|
|
328
|
+
"""Compose a pixel type the way ``PixelType.h`` does."""
|
|
329
|
+
return color | (bits << MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT) | identifier
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def pixel_bit_depth(pixel_type: int) -> int:
|
|
333
|
+
"""Effective bits per pixel of a pixel type, padding included."""
|
|
334
|
+
return (pixel_type & MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_MASK) >> (
|
|
335
|
+
MV_GVSP_PIX_EFFECTIVE_PIXEL_SIZE_SHIFT
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
PixelType_Gvsp_Undefined = 0xFFFFFFFF
|
|
340
|
+
|
|
341
|
+
PixelType_Gvsp_Mono8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0001)
|
|
342
|
+
PixelType_Gvsp_Mono10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0003)
|
|
343
|
+
PixelType_Gvsp_Mono10_Packed = _pixel(MV_GVSP_PIX_MONO, 12, 0x0004)
|
|
344
|
+
PixelType_Gvsp_Mono12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0005)
|
|
345
|
+
PixelType_Gvsp_Mono12_Packed = _pixel(MV_GVSP_PIX_MONO, 12, 0x0006)
|
|
346
|
+
PixelType_Gvsp_Mono14 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0025)
|
|
347
|
+
PixelType_Gvsp_Mono16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0007)
|
|
348
|
+
|
|
349
|
+
# Bayer data is undemosaiced, so the vendor tags it monochrome.
|
|
350
|
+
PixelType_Gvsp_BayerGR8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0008)
|
|
351
|
+
PixelType_Gvsp_BayerRG8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x0009)
|
|
352
|
+
PixelType_Gvsp_BayerGB8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x000A)
|
|
353
|
+
PixelType_Gvsp_BayerBG8 = _pixel(MV_GVSP_PIX_MONO, 8, 0x000B)
|
|
354
|
+
PixelType_Gvsp_BayerGR10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000C)
|
|
355
|
+
PixelType_Gvsp_BayerRG10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000D)
|
|
356
|
+
PixelType_Gvsp_BayerGB10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000E)
|
|
357
|
+
PixelType_Gvsp_BayerBG10 = _pixel(MV_GVSP_PIX_MONO, 16, 0x000F)
|
|
358
|
+
PixelType_Gvsp_BayerGR12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0010)
|
|
359
|
+
PixelType_Gvsp_BayerRG12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0011)
|
|
360
|
+
PixelType_Gvsp_BayerGB12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0012)
|
|
361
|
+
PixelType_Gvsp_BayerBG12 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0013)
|
|
362
|
+
PixelType_Gvsp_BayerGR16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x002E)
|
|
363
|
+
PixelType_Gvsp_BayerRG16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x002F)
|
|
364
|
+
PixelType_Gvsp_BayerGB16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0030)
|
|
365
|
+
PixelType_Gvsp_BayerBG16 = _pixel(MV_GVSP_PIX_MONO, 16, 0x0031)
|
|
366
|
+
|
|
367
|
+
PixelType_Gvsp_RGB8_Packed = _pixel(MV_GVSP_PIX_COLOR, 24, 0x0014)
|
|
368
|
+
PixelType_Gvsp_BGR8_Packed = _pixel(MV_GVSP_PIX_COLOR, 24, 0x0015)
|
|
369
|
+
PixelType_Gvsp_RGBA8_Packed = _pixel(MV_GVSP_PIX_COLOR, 32, 0x0016)
|
|
370
|
+
PixelType_Gvsp_BGRA8_Packed = _pixel(MV_GVSP_PIX_COLOR, 32, 0x0017)
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
# --------------------------------------------------------------------------------------
|
|
374
|
+
# Node map values (CameraParams.h)
|
|
375
|
+
# --------------------------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
MV_MAX_ENUM_SYMBOLIC_NUM = 256
|
|
378
|
+
MV_MAX_SYMBOLIC_LEN = 64
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class MVCC_INTVALUE_EX(Structure):
|
|
382
|
+
"""Current value and range of an integer node.
|
|
383
|
+
|
|
384
|
+
The non-``Ex`` form of this structure is 32-bit; GenICam integer nodes are 64-bit, so
|
|
385
|
+
only this one can carry values such as a full sensor timestamp.
|
|
386
|
+
"""
|
|
387
|
+
|
|
388
|
+
_fields_ = [
|
|
389
|
+
("nCurValue", c_int64),
|
|
390
|
+
("nMax", c_int64),
|
|
391
|
+
("nMin", c_int64),
|
|
392
|
+
("nInc", c_int64),
|
|
393
|
+
("nReserved", c_uint * 16),
|
|
394
|
+
]
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class MVCC_FLOATVALUE(Structure):
|
|
398
|
+
"""Current value and range of a float node. There is no increment for these."""
|
|
399
|
+
|
|
400
|
+
_fields_ = [
|
|
401
|
+
("fCurValue", c_float),
|
|
402
|
+
("fMax", c_float),
|
|
403
|
+
("fMin", c_float),
|
|
404
|
+
("nReserved", c_uint * 4),
|
|
405
|
+
]
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
class MVCC_ENUMVALUE_EX(Structure):
|
|
409
|
+
"""Current value of an enumeration node and the raw values it accepts.
|
|
410
|
+
|
|
411
|
+
The entries are integers; ``MV_CC_GetEnumEntrySymbolic`` turns one into its name. The
|
|
412
|
+
non-``Ex`` form caps the list at 64, which some cameras' ``PixelFormat`` exceeds.
|
|
413
|
+
"""
|
|
414
|
+
|
|
415
|
+
_fields_ = [
|
|
416
|
+
("nCurValue", c_uint),
|
|
417
|
+
("nSupportedNum", c_uint),
|
|
418
|
+
("nSupportValue", c_uint * MV_MAX_ENUM_SYMBOLIC_NUM),
|
|
419
|
+
("nReserved", c_uint * 4),
|
|
420
|
+
]
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class MVCC_ENUMENTRY(Structure):
|
|
424
|
+
"""One entry of an enumeration: ``nValue`` goes in, ``chSymbolic`` comes back."""
|
|
425
|
+
|
|
426
|
+
_fields_ = [
|
|
427
|
+
("nValue", c_uint),
|
|
428
|
+
("chSymbolic", c_char * MV_MAX_SYMBOLIC_LEN),
|
|
429
|
+
("nReserved", c_uint * 4),
|
|
430
|
+
]
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
class MVCC_STRINGVALUE(Structure):
|
|
434
|
+
"""Current value of a string node, with the length the node will accept."""
|
|
435
|
+
|
|
436
|
+
_fields_ = [
|
|
437
|
+
("chCurValue", c_char * 256),
|
|
438
|
+
("nMaxLength", c_int64),
|
|
439
|
+
("nReserved", c_uint * 2),
|
|
440
|
+
]
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
# --------------------------------------------------------------------------------------
|
|
444
|
+
# Transport statistics (CameraParams.h)
|
|
445
|
+
# --------------------------------------------------------------------------------------
|
|
446
|
+
|
|
447
|
+
MV_MATCH_TYPE_NET_DETECT = 0x00000001
|
|
448
|
+
MV_MATCH_TYPE_USB_DETECT = 0x00000002
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
class MV_MATCH_INFO_NET_DETECT(Structure):
|
|
452
|
+
"""GigE traffic and packet-loss counters, accumulated between start and stop."""
|
|
453
|
+
|
|
454
|
+
_fields_ = [
|
|
455
|
+
("nReceiveDataSize", c_int64),
|
|
456
|
+
("nLostPacketCount", c_int64),
|
|
457
|
+
("nLostFrameCount", c_uint),
|
|
458
|
+
("nNetRecvFrameCount", c_uint),
|
|
459
|
+
("nRequestResendPacketCount", c_int64),
|
|
460
|
+
("nResendPacketCount", c_int64),
|
|
461
|
+
]
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class MV_MATCH_INFO_USB_DETECT(Structure):
|
|
465
|
+
"""USB3 traffic counters, accumulated between open and close."""
|
|
466
|
+
|
|
467
|
+
_fields_ = [
|
|
468
|
+
("nReceiveDataSize", c_int64),
|
|
469
|
+
("nReceivedFrameCount", c_uint),
|
|
470
|
+
("nErrorFrameCount", c_uint),
|
|
471
|
+
("nReserved", c_uint * 2),
|
|
472
|
+
]
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class MV_ALL_MATCH_INFO(Structure):
|
|
476
|
+
"""Request wrapper: ``nType`` selects the statistics, the caller owns the buffer."""
|
|
477
|
+
|
|
478
|
+
_fields_ = [
|
|
479
|
+
("nType", c_uint),
|
|
480
|
+
("pInfo", c_void_p),
|
|
481
|
+
("nInfoSize", c_uint),
|
|
482
|
+
]
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
# --------------------------------------------------------------------------------------
|
|
486
|
+
# Entry points (MvCameraControl.h)
|
|
487
|
+
# --------------------------------------------------------------------------------------
|
|
488
|
+
|
|
489
|
+
#: ``(symbol, argtypes, restype)``. Every entry point is declared before first use: an
|
|
490
|
+
#: unset ``argtypes`` happens to work on x86_64 Linux and corrupts the stack on Windows.
|
|
491
|
+
#: ``restype`` follows the header, which declares a signed ``int``; the checked-call helper
|
|
492
|
+
#: normalises it to unsigned before matching against the ``MV_E_*`` constants.
|
|
493
|
+
PROTOTYPES: tuple[tuple[str, list[Any], Any], ...] = (
|
|
494
|
+
("MV_CC_GetSDKVersion", [], c_uint),
|
|
495
|
+
("MV_CC_EnumDevices", [c_uint, POINTER(MV_CC_DEVICE_INFO_LIST)], c_int),
|
|
496
|
+
("MV_CC_CreateHandle", [POINTER(c_void_p), POINTER(MV_CC_DEVICE_INFO)], c_int),
|
|
497
|
+
("MV_CC_DestroyHandle", [c_void_p], c_int),
|
|
498
|
+
("MV_CC_OpenDevice", [c_void_p, c_uint, c_ushort], c_int),
|
|
499
|
+
("MV_CC_CloseDevice", [c_void_p], c_int),
|
|
500
|
+
("MV_CC_IsDeviceConnected", [c_void_p], c_bool),
|
|
501
|
+
("MV_CC_SetImageNodeNum", [c_void_p, c_uint], c_int),
|
|
502
|
+
("MV_CC_StartGrabbing", [c_void_p], c_int),
|
|
503
|
+
("MV_CC_StopGrabbing", [c_void_p], c_int),
|
|
504
|
+
("MV_CC_GetImageBuffer", [c_void_p, POINTER(MV_FRAME_OUT), c_uint], c_int),
|
|
505
|
+
("MV_CC_FreeImageBuffer", [c_void_p, POINTER(MV_FRAME_OUT)], c_int),
|
|
506
|
+
# Node map. Keys are GenICam node names, ASCII, e.g. b"ExposureTime".
|
|
507
|
+
("MV_CC_GetIntValueEx", [c_void_p, c_char_p, POINTER(MVCC_INTVALUE_EX)], c_int),
|
|
508
|
+
("MV_CC_SetIntValueEx", [c_void_p, c_char_p, c_int64], c_int),
|
|
509
|
+
("MV_CC_GetFloatValue", [c_void_p, c_char_p, POINTER(MVCC_FLOATVALUE)], c_int),
|
|
510
|
+
("MV_CC_SetFloatValue", [c_void_p, c_char_p, c_float], c_int),
|
|
511
|
+
("MV_CC_GetBoolValue", [c_void_p, c_char_p, POINTER(c_bool)], c_int),
|
|
512
|
+
("MV_CC_SetBoolValue", [c_void_p, c_char_p, c_bool], c_int),
|
|
513
|
+
("MV_CC_GetEnumValueEx", [c_void_p, c_char_p, POINTER(MVCC_ENUMVALUE_EX)], c_int),
|
|
514
|
+
("MV_CC_SetEnumValue", [c_void_p, c_char_p, c_uint], c_int),
|
|
515
|
+
("MV_CC_SetEnumValueByString", [c_void_p, c_char_p, c_char_p], c_int),
|
|
516
|
+
("MV_CC_GetEnumEntrySymbolic", [c_void_p, c_char_p, POINTER(MVCC_ENUMENTRY)], c_int),
|
|
517
|
+
("MV_CC_GetStringValue", [c_void_p, c_char_p, POINTER(MVCC_STRINGVALUE)], c_int),
|
|
518
|
+
("MV_CC_SetStringValue", [c_void_p, c_char_p, c_char_p], c_int),
|
|
519
|
+
("MV_CC_SetCommandValue", [c_void_p, c_char_p], c_int),
|
|
520
|
+
# Transport tuning and statistics.
|
|
521
|
+
("MV_CC_GetAllMatchInfo", [c_void_p, POINTER(MV_ALL_MATCH_INFO)], c_int),
|
|
522
|
+
# Returns the packet size itself, not a status - see `Camera.optimal_packet_size`.
|
|
523
|
+
("MV_CC_GetOptimalPacketSize", [c_void_p], c_int),
|
|
524
|
+
("MV_GIGE_SetResend", [c_void_p, c_uint, c_uint, c_uint], c_int),
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
_sdk: ctypes.CDLL | None = None
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def apply_prototypes(lib: Any) -> None:
|
|
531
|
+
"""Set ``argtypes`` and ``restype`` on every entry point this package calls.
|
|
532
|
+
|
|
533
|
+
Args:
|
|
534
|
+
lib: The loaded MVS library, or a test double standing in for it.
|
|
535
|
+
|
|
536
|
+
Raises:
|
|
537
|
+
AttributeError: The library does not export one of the expected symbols, which
|
|
538
|
+
means it is not the MVS library or is too old.
|
|
539
|
+
"""
|
|
540
|
+
for symbol, argtypes, restype in PROTOTYPES:
|
|
541
|
+
func = getattr(lib, symbol)
|
|
542
|
+
func.argtypes = argtypes
|
|
543
|
+
func.restype = restype
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
def sdk() -> Any:
|
|
547
|
+
"""Return the MVS library with every prototype declared, loading it on first call.
|
|
548
|
+
|
|
549
|
+
Raises:
|
|
550
|
+
SDKNotFoundError: The SDK is not installed or is installed somewhere unexpected.
|
|
551
|
+
SDKLoadError: The library was found but could not be opened.
|
|
552
|
+
UnsupportedPlatformError: The OS/CPU combination has no known SDK layout.
|
|
553
|
+
"""
|
|
554
|
+
global _sdk
|
|
555
|
+
if _sdk is None:
|
|
556
|
+
lib = _loader.load()
|
|
557
|
+
apply_prototypes(lib)
|
|
558
|
+
_sdk = lib
|
|
559
|
+
return _sdk
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def reset() -> None:
|
|
563
|
+
"""Drop the cached library handle.
|
|
564
|
+
|
|
565
|
+
For tests only; the prototypes are reapplied on the next :func:`sdk` call.
|
|
566
|
+
"""
|
|
567
|
+
global _sdk
|
|
568
|
+
_sdk = None
|