hgrabber-sdk 0.1.0__tar.gz
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.
- hgrabber_sdk-0.1.0/.dockerignore +17 -0
- hgrabber_sdk-0.1.0/.gitignore +7 -0
- hgrabber_sdk-0.1.0/.python-version +1 -0
- hgrabber_sdk-0.1.0/Dockerfile +34 -0
- hgrabber_sdk-0.1.0/PKG-INFO +316 -0
- hgrabber_sdk-0.1.0/README.md +308 -0
- hgrabber_sdk-0.1.0/examples/continuous_sync.py +20 -0
- hgrabber_sdk-0.1.0/examples/linux_smoke.py +16 -0
- hgrabber_sdk-0.1.0/examples/list_devices.py +11 -0
- hgrabber_sdk-0.1.0/examples/multi_camera_action_ptp.py +34 -0
- hgrabber_sdk-0.1.0/examples/software_trigger_async.py +24 -0
- hgrabber_sdk-0.1.0/pyproject.toml +23 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/__init__.py +46 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/_runtime.py +212 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/_sdk.py +126 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/camera.py +853 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/config.py +321 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/discovery.py +143 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/errors.py +19 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/frames.py +137 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/group.py +315 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/py.typed +1 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/CameraParams_const.py +82 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/CameraParams_header.py +1289 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/MvCameraControl_class.py +1153 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/MvErrorDefine_const.py +67 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/PixelType_header.py +258 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/__init__.py +1 -0
- hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/__init__.py +1 -0
- hgrabber_sdk-0.1.0/tests/test_import.py +103 -0
- hgrabber_sdk-0.1.0/uv.lock +869 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.git/
|
|
2
|
+
.venv/
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
__pycache__/
|
|
5
|
+
*.py[cod]
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
*.egg-info/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
|
|
12
|
+
# Keep native MVS runtimes out of build context by default.
|
|
13
|
+
mvs/
|
|
14
|
+
mvs-runtime/
|
|
15
|
+
docker/mvs/
|
|
16
|
+
docker/mvs-runtime/
|
|
17
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
ARG PYTHON_VERSION=3.12
|
|
4
|
+
FROM python:${PYTHON_VERSION}-slim-bookworm
|
|
5
|
+
|
|
6
|
+
ENV PYTHONDONTWRITEBYTECODE=1
|
|
7
|
+
ENV PYTHONUNBUFFERED=1
|
|
8
|
+
ENV LD_LIBRARY_PATH=/opt/mvs/64:/opt/mvs/aarch64:/opt/mvs/armhf:/opt/mvs
|
|
9
|
+
|
|
10
|
+
RUN apt-get update \
|
|
11
|
+
&& apt-get install -y --no-install-recommends \
|
|
12
|
+
ca-certificates \
|
|
13
|
+
iproute2 \
|
|
14
|
+
iputils-ping \
|
|
15
|
+
libglib2.0-0 \
|
|
16
|
+
libgomp1 \
|
|
17
|
+
libstdc++6 \
|
|
18
|
+
libusb-1.0-0 \
|
|
19
|
+
libx11-6 \
|
|
20
|
+
libxext6 \
|
|
21
|
+
udev \
|
|
22
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
23
|
+
|
|
24
|
+
WORKDIR /app
|
|
25
|
+
|
|
26
|
+
COPY pyproject.toml README.md ./
|
|
27
|
+
COPY src ./src
|
|
28
|
+
COPY tests ./tests
|
|
29
|
+
COPY examples ./examples
|
|
30
|
+
|
|
31
|
+
RUN python -m pip install --no-cache-dir --upgrade pip \
|
|
32
|
+
&& python -m pip install --no-cache-dir -e . pytest
|
|
33
|
+
|
|
34
|
+
CMD ["python", "-m", "pytest", "-q"]
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hgrabber-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pythonic Hikrobot MVS camera SDK wrapper for USB3 and GigE cameras
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: numpy>=1.24
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
|
|
9
|
+
# hgrabber-sdk
|
|
10
|
+
|
|
11
|
+
Small Python wrapper around Hikrobot MVS `MvCameraControl` for USB3 and GigE cameras.
|
|
12
|
+
|
|
13
|
+
The package vendors the official generated Python `MvImport` files from:
|
|
14
|
+
|
|
15
|
+
`C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport`
|
|
16
|
+
|
|
17
|
+
The native Hikrobot MVS runtime is not bundled in this package. Install MVS separately on the
|
|
18
|
+
target machine, or point the package at the native library with `HIK_CAMERA_SDK_MVS_LIBRARY`.
|
|
19
|
+
|
|
20
|
+
## Setup with uv
|
|
21
|
+
|
|
22
|
+
This project is configured for `uv` and pins Python through `.python-version`.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install hgrabber-sdk
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
uv sync --dev
|
|
30
|
+
uv run python -c "import hgrabber_sdk; print(hgrabber_sdk.__all__)"
|
|
31
|
+
uv run pytest
|
|
32
|
+
uv run python examples/list_devices.py
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The import check does not load the native Hikrobot runtime. Commands that enumerate or open cameras
|
|
36
|
+
load `MvCameraControl` lazily.
|
|
37
|
+
|
|
38
|
+
## Native MVS runtime
|
|
39
|
+
|
|
40
|
+
Install Hikrobot MVS from the official installer for the target OS.
|
|
41
|
+
|
|
42
|
+
The loader checks these locations in order:
|
|
43
|
+
|
|
44
|
+
- `HIK_CAMERA_SDK_MVS_LIBRARY`: full path to `MvCameraControl.dll` or `libMvCameraControl.so`.
|
|
45
|
+
- Windows: the standard MVS runtime folder under `Common Files\MVS\Runtime`, then normal `PATH`.
|
|
46
|
+
- Linux: `MVCAM_COMMON_RUNENV` pointing to a runtime root that contains `64/libMvCameraControl.so`,
|
|
47
|
+
`aarch64/libMvCameraControl.so`, or another matching architecture directory. Common install paths
|
|
48
|
+
such as `/opt/MVS/lib` are also checked.
|
|
49
|
+
|
|
50
|
+
Windows override example:
|
|
51
|
+
|
|
52
|
+
```powershell
|
|
53
|
+
$env:HIK_CAMERA_SDK_MVS_LIBRARY = "C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Linux root example:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
export MVCAM_COMMON_RUNENV=/opt/MVS/lib
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Linux exact library override:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export HIK_CAMERA_SDK_MVS_LIBRARY=/opt/MVS/lib/64/libMvCameraControl.so
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Build and publish
|
|
69
|
+
|
|
70
|
+
Build a pure Python wheel. It contains the wrapper code only, not Hikrobot's native runtime:
|
|
71
|
+
|
|
72
|
+
```powershell
|
|
73
|
+
uv sync --dev
|
|
74
|
+
uv build
|
|
75
|
+
uv run --dev twine check dist\*
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Upload to TestPyPI first, then PyPI:
|
|
79
|
+
|
|
80
|
+
```powershell
|
|
81
|
+
uv run --dev twine upload --repository testpypi dist\*.whl
|
|
82
|
+
uv run --dev twine upload dist\*.whl
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Linux Docker Smoke Test
|
|
86
|
+
|
|
87
|
+
Build the Linux image and run package tests without native MVS libraries:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
docker build -t hgrabber-sdk-linux .
|
|
91
|
+
docker run --rm hgrabber-sdk-linux
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
To test the native Hikrobot SDK and camera discovery, install or extract the Linux MVS runtime on
|
|
95
|
+
the host and mount the runtime directory into `/opt/mvs`. The mounted directory must contain the
|
|
96
|
+
architecture subdirectory expected by the loader, for example:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
/path/to/mvs-runtime/
|
|
100
|
+
64/libMvCameraControl.so
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
GigE camera discovery is easiest with host networking:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
docker run --rm --network host \
|
|
107
|
+
-e MVCAM_COMMON_RUNENV=/opt/mvs \
|
|
108
|
+
-v /path/to/mvs-runtime:/opt/mvs:ro \
|
|
109
|
+
hgrabber-sdk-linux \
|
|
110
|
+
python examples/linux_smoke.py
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For USB cameras, run on a real Linux host and pass USB devices through:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
docker run --rm --network host --privileged \
|
|
117
|
+
-e MVCAM_COMMON_RUNENV=/opt/mvs \
|
|
118
|
+
-v /dev/bus/usb:/dev/bus/usb \
|
|
119
|
+
-v /path/to/mvs-runtime:/opt/mvs:ro \
|
|
120
|
+
hgrabber-sdk-linux \
|
|
121
|
+
python examples/linux_smoke.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Docker Desktop/WSL may not expose industrial USB/GigE cameras reliably; use a native Linux host
|
|
125
|
+
for hardware validation.
|
|
126
|
+
|
|
127
|
+
## Supported flows
|
|
128
|
+
|
|
129
|
+
- USB3 and GigE discovery by serial number, user name, model name, or GigE IP.
|
|
130
|
+
- Synchronous grabbing with `GetImageBuffer`.
|
|
131
|
+
- Async polling worker.
|
|
132
|
+
- `asyncio` methods for non-blocking application code.
|
|
133
|
+
- Native SDK image callback mode.
|
|
134
|
+
- Continuous acquisition.
|
|
135
|
+
- Software trigger.
|
|
136
|
+
- Hardware line trigger: `Line0`, `Line1`, `Line2`, `Line3`, with activation, delay, cache, debouncer.
|
|
137
|
+
- GigE action trigger: `Action1` with device/group keys and broadcast address.
|
|
138
|
+
- PTP helpers for GigE: enable `GevIEEE1588`, wait for `Master`/`Slave`, latch timestamp, scheduled action command.
|
|
139
|
+
- Multi-camera group API.
|
|
140
|
+
- Direct GenICam feature passthrough for extra settings.
|
|
141
|
+
|
|
142
|
+
## Quick start
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from hgrabber_sdk import HikCamera
|
|
146
|
+
|
|
147
|
+
config = (
|
|
148
|
+
HikCamera.builder("left")
|
|
149
|
+
.usb("02K09720174")
|
|
150
|
+
.settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
|
|
151
|
+
.continuous()
|
|
152
|
+
.build()
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
with HikCamera(config) as camera:
|
|
156
|
+
frame = camera.grab(timeout_ms=1000)
|
|
157
|
+
print(frame.width, frame.height, frame.pixel_format, frame.image.shape)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Software trigger
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from hgrabber_sdk import HikCamera
|
|
164
|
+
|
|
165
|
+
config = (
|
|
166
|
+
HikCamera.builder("top")
|
|
167
|
+
.gige("192.168.10.20")
|
|
168
|
+
.software_trigger()
|
|
169
|
+
.settings(exposure_us=6000, gain=2.0)
|
|
170
|
+
.build()
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
with HikCamera(config) as camera:
|
|
174
|
+
frame = camera.grab() # sends TriggerSoftware, then waits for the frame
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Threaded streaming
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from hgrabber_sdk import HikCamera
|
|
181
|
+
|
|
182
|
+
def on_frame(frame):
|
|
183
|
+
print(frame.camera_name, frame.frame_number, frame.device_timestamp)
|
|
184
|
+
|
|
185
|
+
config = HikCamera.builder("preview").usb("SERIAL").continuous().build()
|
|
186
|
+
|
|
187
|
+
with HikCamera(config) as camera:
|
|
188
|
+
camera.start_stream(on_frame)
|
|
189
|
+
frame = camera.next_frame(timeout_ms=1000)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`start_async` and `stop_async` are kept as compatibility aliases for the threaded API.
|
|
193
|
+
|
|
194
|
+
## Asyncio grabbing
|
|
195
|
+
|
|
196
|
+
All blocking SDK calls have `asyncio` wrappers. They run the MVS calls in worker threads, so
|
|
197
|
+
`MV_CC_GetImageBuffer`, software trigger, PTP waits, and action commands do not block the event loop.
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
import asyncio
|
|
201
|
+
from hgrabber_sdk import HikCamera
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
async def main():
|
|
205
|
+
config = (
|
|
206
|
+
HikCamera.builder("cam")
|
|
207
|
+
.gige("192.168.10.20")
|
|
208
|
+
.software_trigger()
|
|
209
|
+
.build()
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
async with HikCamera(config) as camera:
|
|
213
|
+
frame = await camera.async_grab(timeout_ms=1000)
|
|
214
|
+
print(frame.frame_number)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
asyncio.run(main())
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
For continuous streaming into an `asyncio.Queue`:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
async with HikCamera(config) as camera:
|
|
224
|
+
frames = await camera.async_start_stream(queue_size=4)
|
|
225
|
+
frame = await asyncio.wait_for(frames.get(), timeout=2.0)
|
|
226
|
+
await camera.async_stop_stream(frames)
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Native SDK callback
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
config = (
|
|
233
|
+
HikCamera.builder("callback")
|
|
234
|
+
.gige("192.168.10.21")
|
|
235
|
+
.sdk_callback()
|
|
236
|
+
.continuous()
|
|
237
|
+
.build()
|
|
238
|
+
)
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Callback mode registers `MV_CC_RegisterImageCallBackEx` before `MV_CC_StartGrabbing`.
|
|
242
|
+
|
|
243
|
+
## Line trigger
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
config = (
|
|
247
|
+
HikCamera.builder("io")
|
|
248
|
+
.usb("SERIAL")
|
|
249
|
+
.line_trigger("Line0", activation="RisingEdge", delay_us=0, line_debouncer_us=50)
|
|
250
|
+
.build()
|
|
251
|
+
)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
For line-scan cameras, set another trigger selector:
|
|
255
|
+
|
|
256
|
+
```python
|
|
257
|
+
.line_trigger("Line1", selector="LineStart")
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Multi-camera GigE action/PTP
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from hgrabber_sdk import HikCamera, HikCameraGroup
|
|
264
|
+
|
|
265
|
+
left = (
|
|
266
|
+
HikCamera.builder("left")
|
|
267
|
+
.gige("192.168.10.21")
|
|
268
|
+
.ptp(wait_synchronized=True)
|
|
269
|
+
.action_trigger(device_key=1, group_key=1, group_mask=1)
|
|
270
|
+
.build()
|
|
271
|
+
)
|
|
272
|
+
right = (
|
|
273
|
+
HikCamera.builder("right")
|
|
274
|
+
.gige("192.168.10.22")
|
|
275
|
+
.ptp(wait_synchronized=True)
|
|
276
|
+
.action_trigger(device_key=1, group_key=1, group_mask=1)
|
|
277
|
+
.build()
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
with HikCameraGroup([left, right]) as cameras:
|
|
281
|
+
cameras.start_async(queue_size=4)
|
|
282
|
+
results = cameras.issue_action_after(delay_ticks=10_000_000)
|
|
283
|
+
frames = {name: camera.next_frame(timeout_ms=2000) for name, camera in cameras.cameras.items()}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Asyncio group variant:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
async with HikCameraGroup([left, right]) as cameras:
|
|
290
|
+
queues = await cameras.async_start_stream(queue_size=4)
|
|
291
|
+
await cameras.async_issue_action_after(delay_ticks=10_000_000)
|
|
292
|
+
frames = {
|
|
293
|
+
name: await asyncio.wait_for(queue.get(), timeout=2.0)
|
|
294
|
+
for name, queue in queues.items()
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`delay_ticks` is in camera timestamp ticks. On most GigE Vision PTP setups this is nanoseconds,
|
|
299
|
+
but validate this against the exact camera model before using scheduled actions in production.
|
|
300
|
+
|
|
301
|
+
## Raw feature passthrough
|
|
302
|
+
|
|
303
|
+
Any extra GenICam feature can be passed through the builder:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
config = (
|
|
307
|
+
HikCamera.builder("cam")
|
|
308
|
+
.gige("192.168.10.20")
|
|
309
|
+
.feature("GammaEnable", True)
|
|
310
|
+
.feature("Gamma", 0.7)
|
|
311
|
+
.feature("AcquisitionBurstFrameCount", 3)
|
|
312
|
+
.build()
|
|
313
|
+
)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
String values are first attempted as enum symbols and then as string nodes.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# hgrabber-sdk
|
|
2
|
+
|
|
3
|
+
Small Python wrapper around Hikrobot MVS `MvCameraControl` for USB3 and GigE cameras.
|
|
4
|
+
|
|
5
|
+
The package vendors the official generated Python `MvImport` files from:
|
|
6
|
+
|
|
7
|
+
`C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport`
|
|
8
|
+
|
|
9
|
+
The native Hikrobot MVS runtime is not bundled in this package. Install MVS separately on the
|
|
10
|
+
target machine, or point the package at the native library with `HIK_CAMERA_SDK_MVS_LIBRARY`.
|
|
11
|
+
|
|
12
|
+
## Setup with uv
|
|
13
|
+
|
|
14
|
+
This project is configured for `uv` and pins Python through `.python-version`.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install hgrabber-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```powershell
|
|
21
|
+
uv sync --dev
|
|
22
|
+
uv run python -c "import hgrabber_sdk; print(hgrabber_sdk.__all__)"
|
|
23
|
+
uv run pytest
|
|
24
|
+
uv run python examples/list_devices.py
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The import check does not load the native Hikrobot runtime. Commands that enumerate or open cameras
|
|
28
|
+
load `MvCameraControl` lazily.
|
|
29
|
+
|
|
30
|
+
## Native MVS runtime
|
|
31
|
+
|
|
32
|
+
Install Hikrobot MVS from the official installer for the target OS.
|
|
33
|
+
|
|
34
|
+
The loader checks these locations in order:
|
|
35
|
+
|
|
36
|
+
- `HIK_CAMERA_SDK_MVS_LIBRARY`: full path to `MvCameraControl.dll` or `libMvCameraControl.so`.
|
|
37
|
+
- Windows: the standard MVS runtime folder under `Common Files\MVS\Runtime`, then normal `PATH`.
|
|
38
|
+
- Linux: `MVCAM_COMMON_RUNENV` pointing to a runtime root that contains `64/libMvCameraControl.so`,
|
|
39
|
+
`aarch64/libMvCameraControl.so`, or another matching architecture directory. Common install paths
|
|
40
|
+
such as `/opt/MVS/lib` are also checked.
|
|
41
|
+
|
|
42
|
+
Windows override example:
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
$env:HIK_CAMERA_SDK_MVS_LIBRARY = "C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Linux root example:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
export MVCAM_COMMON_RUNENV=/opt/MVS/lib
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Linux exact library override:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
export HIK_CAMERA_SDK_MVS_LIBRARY=/opt/MVS/lib/64/libMvCameraControl.so
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Build and publish
|
|
61
|
+
|
|
62
|
+
Build a pure Python wheel. It contains the wrapper code only, not Hikrobot's native runtime:
|
|
63
|
+
|
|
64
|
+
```powershell
|
|
65
|
+
uv sync --dev
|
|
66
|
+
uv build
|
|
67
|
+
uv run --dev twine check dist\*
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Upload to TestPyPI first, then PyPI:
|
|
71
|
+
|
|
72
|
+
```powershell
|
|
73
|
+
uv run --dev twine upload --repository testpypi dist\*.whl
|
|
74
|
+
uv run --dev twine upload dist\*.whl
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Linux Docker Smoke Test
|
|
78
|
+
|
|
79
|
+
Build the Linux image and run package tests without native MVS libraries:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
docker build -t hgrabber-sdk-linux .
|
|
83
|
+
docker run --rm hgrabber-sdk-linux
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
To test the native Hikrobot SDK and camera discovery, install or extract the Linux MVS runtime on
|
|
87
|
+
the host and mount the runtime directory into `/opt/mvs`. The mounted directory must contain the
|
|
88
|
+
architecture subdirectory expected by the loader, for example:
|
|
89
|
+
|
|
90
|
+
```text
|
|
91
|
+
/path/to/mvs-runtime/
|
|
92
|
+
64/libMvCameraControl.so
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
GigE camera discovery is easiest with host networking:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
docker run --rm --network host \
|
|
99
|
+
-e MVCAM_COMMON_RUNENV=/opt/mvs \
|
|
100
|
+
-v /path/to/mvs-runtime:/opt/mvs:ro \
|
|
101
|
+
hgrabber-sdk-linux \
|
|
102
|
+
python examples/linux_smoke.py
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For USB cameras, run on a real Linux host and pass USB devices through:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
docker run --rm --network host --privileged \
|
|
109
|
+
-e MVCAM_COMMON_RUNENV=/opt/mvs \
|
|
110
|
+
-v /dev/bus/usb:/dev/bus/usb \
|
|
111
|
+
-v /path/to/mvs-runtime:/opt/mvs:ro \
|
|
112
|
+
hgrabber-sdk-linux \
|
|
113
|
+
python examples/linux_smoke.py
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Docker Desktop/WSL may not expose industrial USB/GigE cameras reliably; use a native Linux host
|
|
117
|
+
for hardware validation.
|
|
118
|
+
|
|
119
|
+
## Supported flows
|
|
120
|
+
|
|
121
|
+
- USB3 and GigE discovery by serial number, user name, model name, or GigE IP.
|
|
122
|
+
- Synchronous grabbing with `GetImageBuffer`.
|
|
123
|
+
- Async polling worker.
|
|
124
|
+
- `asyncio` methods for non-blocking application code.
|
|
125
|
+
- Native SDK image callback mode.
|
|
126
|
+
- Continuous acquisition.
|
|
127
|
+
- Software trigger.
|
|
128
|
+
- Hardware line trigger: `Line0`, `Line1`, `Line2`, `Line3`, with activation, delay, cache, debouncer.
|
|
129
|
+
- GigE action trigger: `Action1` with device/group keys and broadcast address.
|
|
130
|
+
- PTP helpers for GigE: enable `GevIEEE1588`, wait for `Master`/`Slave`, latch timestamp, scheduled action command.
|
|
131
|
+
- Multi-camera group API.
|
|
132
|
+
- Direct GenICam feature passthrough for extra settings.
|
|
133
|
+
|
|
134
|
+
## Quick start
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from hgrabber_sdk import HikCamera
|
|
138
|
+
|
|
139
|
+
config = (
|
|
140
|
+
HikCamera.builder("left")
|
|
141
|
+
.usb("02K09720174")
|
|
142
|
+
.settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
|
|
143
|
+
.continuous()
|
|
144
|
+
.build()
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
with HikCamera(config) as camera:
|
|
148
|
+
frame = camera.grab(timeout_ms=1000)
|
|
149
|
+
print(frame.width, frame.height, frame.pixel_format, frame.image.shape)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Software trigger
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from hgrabber_sdk import HikCamera
|
|
156
|
+
|
|
157
|
+
config = (
|
|
158
|
+
HikCamera.builder("top")
|
|
159
|
+
.gige("192.168.10.20")
|
|
160
|
+
.software_trigger()
|
|
161
|
+
.settings(exposure_us=6000, gain=2.0)
|
|
162
|
+
.build()
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
with HikCamera(config) as camera:
|
|
166
|
+
frame = camera.grab() # sends TriggerSoftware, then waits for the frame
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Threaded streaming
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
from hgrabber_sdk import HikCamera
|
|
173
|
+
|
|
174
|
+
def on_frame(frame):
|
|
175
|
+
print(frame.camera_name, frame.frame_number, frame.device_timestamp)
|
|
176
|
+
|
|
177
|
+
config = HikCamera.builder("preview").usb("SERIAL").continuous().build()
|
|
178
|
+
|
|
179
|
+
with HikCamera(config) as camera:
|
|
180
|
+
camera.start_stream(on_frame)
|
|
181
|
+
frame = camera.next_frame(timeout_ms=1000)
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`start_async` and `stop_async` are kept as compatibility aliases for the threaded API.
|
|
185
|
+
|
|
186
|
+
## Asyncio grabbing
|
|
187
|
+
|
|
188
|
+
All blocking SDK calls have `asyncio` wrappers. They run the MVS calls in worker threads, so
|
|
189
|
+
`MV_CC_GetImageBuffer`, software trigger, PTP waits, and action commands do not block the event loop.
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
import asyncio
|
|
193
|
+
from hgrabber_sdk import HikCamera
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
async def main():
|
|
197
|
+
config = (
|
|
198
|
+
HikCamera.builder("cam")
|
|
199
|
+
.gige("192.168.10.20")
|
|
200
|
+
.software_trigger()
|
|
201
|
+
.build()
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
async with HikCamera(config) as camera:
|
|
205
|
+
frame = await camera.async_grab(timeout_ms=1000)
|
|
206
|
+
print(frame.frame_number)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
asyncio.run(main())
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
For continuous streaming into an `asyncio.Queue`:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
async with HikCamera(config) as camera:
|
|
216
|
+
frames = await camera.async_start_stream(queue_size=4)
|
|
217
|
+
frame = await asyncio.wait_for(frames.get(), timeout=2.0)
|
|
218
|
+
await camera.async_stop_stream(frames)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Native SDK callback
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
config = (
|
|
225
|
+
HikCamera.builder("callback")
|
|
226
|
+
.gige("192.168.10.21")
|
|
227
|
+
.sdk_callback()
|
|
228
|
+
.continuous()
|
|
229
|
+
.build()
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Callback mode registers `MV_CC_RegisterImageCallBackEx` before `MV_CC_StartGrabbing`.
|
|
234
|
+
|
|
235
|
+
## Line trigger
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
config = (
|
|
239
|
+
HikCamera.builder("io")
|
|
240
|
+
.usb("SERIAL")
|
|
241
|
+
.line_trigger("Line0", activation="RisingEdge", delay_us=0, line_debouncer_us=50)
|
|
242
|
+
.build()
|
|
243
|
+
)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
For line-scan cameras, set another trigger selector:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
.line_trigger("Line1", selector="LineStart")
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Multi-camera GigE action/PTP
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
from hgrabber_sdk import HikCamera, HikCameraGroup
|
|
256
|
+
|
|
257
|
+
left = (
|
|
258
|
+
HikCamera.builder("left")
|
|
259
|
+
.gige("192.168.10.21")
|
|
260
|
+
.ptp(wait_synchronized=True)
|
|
261
|
+
.action_trigger(device_key=1, group_key=1, group_mask=1)
|
|
262
|
+
.build()
|
|
263
|
+
)
|
|
264
|
+
right = (
|
|
265
|
+
HikCamera.builder("right")
|
|
266
|
+
.gige("192.168.10.22")
|
|
267
|
+
.ptp(wait_synchronized=True)
|
|
268
|
+
.action_trigger(device_key=1, group_key=1, group_mask=1)
|
|
269
|
+
.build()
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
with HikCameraGroup([left, right]) as cameras:
|
|
273
|
+
cameras.start_async(queue_size=4)
|
|
274
|
+
results = cameras.issue_action_after(delay_ticks=10_000_000)
|
|
275
|
+
frames = {name: camera.next_frame(timeout_ms=2000) for name, camera in cameras.cameras.items()}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Asyncio group variant:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
async with HikCameraGroup([left, right]) as cameras:
|
|
282
|
+
queues = await cameras.async_start_stream(queue_size=4)
|
|
283
|
+
await cameras.async_issue_action_after(delay_ticks=10_000_000)
|
|
284
|
+
frames = {
|
|
285
|
+
name: await asyncio.wait_for(queue.get(), timeout=2.0)
|
|
286
|
+
for name, queue in queues.items()
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
`delay_ticks` is in camera timestamp ticks. On most GigE Vision PTP setups this is nanoseconds,
|
|
291
|
+
but validate this against the exact camera model before using scheduled actions in production.
|
|
292
|
+
|
|
293
|
+
## Raw feature passthrough
|
|
294
|
+
|
|
295
|
+
Any extra GenICam feature can be passed through the builder:
|
|
296
|
+
|
|
297
|
+
```python
|
|
298
|
+
config = (
|
|
299
|
+
HikCamera.builder("cam")
|
|
300
|
+
.gige("192.168.10.20")
|
|
301
|
+
.feature("GammaEnable", True)
|
|
302
|
+
.feature("Gamma", 0.7)
|
|
303
|
+
.feature("AcquisitionBurstFrameCount", 3)
|
|
304
|
+
.build()
|
|
305
|
+
)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
String values are first attempted as enum symbols and then as string nodes.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from hgrabber_sdk import HikCamera
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def main() -> None:
|
|
5
|
+
config = (
|
|
6
|
+
HikCamera.builder("cam")
|
|
7
|
+
.usb("PUT_SERIAL_HERE")
|
|
8
|
+
.settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
|
|
9
|
+
.continuous()
|
|
10
|
+
.build()
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
with HikCamera(config) as camera:
|
|
14
|
+
frame = camera.grab(timeout_ms=1000)
|
|
15
|
+
print(frame.frame_number, frame.width, frame.height, frame.pixel_format)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if __name__ == "__main__":
|
|
19
|
+
main()
|
|
20
|
+
|