Skip to main content

Pythonic Hikrobot MVS camera SDK wrapper for USB3 and GigE cameras

Project description

hgrabber-sdk

Small Python wrapper around Hikrobot MVS MvCameraControl for USB3 and GigE cameras.

Подробная документация по использованию: docs/USAGE.md.

The package vendors the official generated Python MvImport files from:

C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport

The native Hikrobot MVS runtime is not bundled in this package. Install MVS separately on the target machine, or point the package at the native library with HIK_CAMERA_SDK_MVS_LIBRARY.

Setup with uv

This project is configured for uv and pins Python through .python-version.

pip install hgrabber-sdk
uv sync --dev
uv run python -c "import hgrabber_sdk; print(hgrabber_sdk.__all__)"
uv run pytest
uv run python examples/list_devices.py
uv run python examples/gige_grab.py --ip 192.168.10.20

The import check does not load the native Hikrobot runtime. Commands that enumerate or open cameras load MvCameraControl lazily.

Native MVS runtime

Install Hikrobot MVS from the official installer for the target OS.

The loader checks these locations in order:

  • HIK_CAMERA_SDK_MVS_LIBRARY: full path to MvCameraControl.dll or libMvCameraControl.so.
  • Windows: the standard MVS runtime folder under Common Files\MVS\Runtime, then normal PATH.
  • Linux: MVCAM_COMMON_RUNENV pointing to a runtime root that contains 64/libMvCameraControl.so, aarch64/libMvCameraControl.so, or another matching architecture directory. Common install paths such as /opt/MVS/lib are also checked.

Windows override example:

$env:HIK_CAMERA_SDK_MVS_LIBRARY = "C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll"

Linux root example:

export MVCAM_COMMON_RUNENV=/opt/MVS/lib

Linux exact library override:

export HIK_CAMERA_SDK_MVS_LIBRARY=/opt/MVS/lib/64/libMvCameraControl.so

Build and publish

Build a pure Python wheel. It contains the wrapper code only, not Hikrobot's native runtime:

uv sync --dev
uv build
uv run --dev twine check dist\*

Upload to TestPyPI first, then PyPI:

uv run --dev twine upload --repository testpypi dist\*.whl
uv run --dev twine upload dist\*.whl

Linux Docker Smoke Test

Build the Linux image and run package tests without native MVS libraries:

docker build -t hgrabber-sdk-linux .
docker run --rm hgrabber-sdk-linux

To test the native Hikrobot SDK and camera discovery, install or extract the Linux MVS runtime on the host and mount the runtime directory into /opt/mvs. The mounted directory must contain the architecture subdirectory expected by the loader, for example:

/path/to/mvs-runtime/
  64/libMvCameraControl.so

GigE camera discovery is easiest with host networking:

docker run --rm --network host \
  -e MVCAM_COMMON_RUNENV=/opt/mvs \
  -v /path/to/mvs-runtime:/opt/mvs:ro \
  hgrabber-sdk-linux \
  python examples/linux_smoke.py

For USB cameras, run on a real Linux host and pass USB devices through:

docker run --rm --network host --privileged \
  -e MVCAM_COMMON_RUNENV=/opt/mvs \
  -v /dev/bus/usb:/dev/bus/usb \
  -v /path/to/mvs-runtime:/opt/mvs:ro \
  hgrabber-sdk-linux \
  python examples/linux_smoke.py

Docker Desktop/WSL may not expose industrial USB/GigE cameras reliably; use a native Linux host for hardware validation.

Supported flows

  • USB3 and GigE discovery by serial number, user name, model name, or GigE IP.
  • Synchronous grabbing with GetImageBuffer.
  • Async polling worker.
  • asyncio methods for non-blocking application code.
  • Native SDK image callback mode.
  • Continuous acquisition.
  • Software trigger.
  • Hardware line trigger: Line0, Line1, Line2, Line3, with activation, delay, cache, debouncer.
  • GigE action trigger: Action1 with device/group keys and broadcast address.
  • PTP helpers for GigE: enable GevIEEE1588, wait for Master/Slave, latch timestamp, scheduled action command.
  • Multi-camera group API.
  • Direct GenICam feature passthrough for extra settings.

Quick start

from hgrabber_sdk import HikCamera

config = (
    HikCamera.builder("left")
    .usb("02K09720174")
    .settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
    .continuous()
    .build()
)

with HikCamera(config) as camera:
    frame = camera.grab(timeout_ms=1000)
    print(frame.width, frame.height, frame.pixel_format, frame.image.shape)

Software trigger

from hgrabber_sdk import HikCamera

config = (
    HikCamera.builder("top")
    .gige("192.168.10.20")
    .software_trigger()
    .settings(exposure_us=6000, gain=2.0)
    .build()
)

with HikCamera(config) as camera:
    frame = camera.grab()  # sends TriggerSoftware, then waits for the frame

Threaded streaming

from hgrabber_sdk import HikCamera

def on_frame(frame):
    print(frame.camera_name, frame.frame_number, frame.device_ticks)

config = HikCamera.builder("preview").usb("SERIAL").continuous().build()

with HikCamera(config) as camera:
    camera.start_stream(on_frame)
    frame = camera.next_frame(timeout_ms=1000)

start_async and stop_async are kept as compatibility aliases for the threaded API.

Asyncio grabbing

All blocking SDK calls have asyncio wrappers. They run the MVS calls in worker threads, so MV_CC_GetImageBuffer, software trigger, PTP waits, and action commands do not block the event loop.

import asyncio
from hgrabber_sdk import HikCamera


async def main():
    config = (
        HikCamera.builder("cam")
        .gige("192.168.10.20")
        .software_trigger()
        .build()
    )

    async with HikCamera(config) as camera:
        frame = await camera.async_grab(timeout_ms=1000)
        print(frame.frame_number)


asyncio.run(main())

For continuous streaming into an asyncio.Queue:

async with HikCamera(config) as camera:
    frames = await camera.async_start_stream(queue_size=4)
    frame = await asyncio.wait_for(frames.get(), timeout=2.0)
    await camera.async_stop_stream(frames)

Native SDK callback

config = (
    HikCamera.builder("callback")
    .gige("192.168.10.21")
    .sdk_callback()
    .continuous()
    .build()
)

Callback mode registers MV_CC_RegisterImageCallBackEx before MV_CC_StartGrabbing.

Line trigger

config = (
    HikCamera.builder("io")
    .usb("SERIAL")
    .line_trigger("Line0", activation="RisingEdge", delay_us=0, line_debouncer_us=50)
    .build()
)

For line-scan cameras, set another trigger selector:

.line_trigger("Line1", selector="LineStart")

Multi-camera GigE action/PTP

from hgrabber_sdk import HikCamera, HikCameraGroup

left = (
    HikCamera.builder("left")
    .gige("192.168.10.21")
    .ptp(wait_synchronized=True)
    .action_trigger(device_key=1, group_key=1, group_mask=1)
    .build()
)
right = (
    HikCamera.builder("right")
    .gige("192.168.10.22")
    .ptp(wait_synchronized=True)
    .action_trigger(device_key=1, group_key=1, group_mask=1)
    .build()
)

with HikCameraGroup([left, right]) as cameras:
    cameras.start_async(queue_size=4)
    results = cameras.issue_action_after(delay_ticks=10_000_000)
    frames = {name: camera.next_frame(timeout_ms=2000) for name, camera in cameras.cameras.items()}

Asyncio group variant:

async with HikCameraGroup([left, right]) as cameras:
    queues = await cameras.async_start_stream(queue_size=4)
    await cameras.async_issue_action_after(delay_ticks=10_000_000)
    frames = {
        name: await asyncio.wait_for(queue.get(), timeout=2.0)
        for name, queue in queues.items()
    }

delay_ticks is in camera timestamp ticks. On most GigE Vision PTP setups this is nanoseconds, but validate this against the exact camera model before using scheduled actions in production.

Raw feature passthrough

Any extra GenICam feature can be passed through the builder:

config = (
    HikCamera.builder("cam")
    .gige("192.168.10.20")
    .feature("GammaEnable", True)
    .feature("Gamma", 0.7)
    .feature("AcquisitionBurstFrameCount", 3)
    .build()
)

String values are first attempted as enum symbols and then as string nodes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

hgrabber_sdk-0.1.6.tar.gz (2.3 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

hgrabber_sdk-0.1.6-py3-none-any.whl (62.8 kB view details)

Uploaded Python 3

File details

Details for the file hgrabber_sdk-0.1.6.tar.gz.

File metadata

  • Download URL: hgrabber_sdk-0.1.6.tar.gz
  • Upload date:
  • Size: 2.3 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for hgrabber_sdk-0.1.6.tar.gz
Algorithm Hash digest
SHA256 8fc4a3bf0f56ace78218d557653877e1d9f8b05bfec0651f9f64030d1432db35
MD5 9bc28d737fed048632f14df4d538550f
BLAKE2b-256 ee0e6f430719fb6bde2f107685ba1d1eeb736b3a4512cb3443899afbb9066a5e

See more details on using hashes here.

File details

Details for the file hgrabber_sdk-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: hgrabber_sdk-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 62.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for hgrabber_sdk-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 a2ff56eefb095ee758d89eddf623838516a334761067540e606b90157c71686b
MD5 9242bf9c046d86e97b814ab4835c8329
BLAKE2b-256 45664f760625eefc7dc08ee109e8ae45575f3a6dfc0c73f9a94bff551a35c491

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page