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.5.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.5-py3-none-any.whl (62.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: hgrabber_sdk-0.1.5.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.5.tar.gz
Algorithm Hash digest
SHA256 3f6163196830a91dc911351225c18dcec998205efd3c97295e74083572ac8415
MD5 1f1a93cc26dc4b673e8b6f9e84c3869e
BLAKE2b-256 80755f6e01047660f964917431a65ef4e1faf7a10c71e4e97094fc16144b73aa

See more details on using hashes here.

File details

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

File metadata

  • Download URL: hgrabber_sdk-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 62.7 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.5-py3-none-any.whl
Algorithm Hash digest
SHA256 3549ea7b9ec0248ab7a1b8b311b799c74729a8abfbca7e134322dacb9684540f
MD5 9af63aaaa2b9c2a1ce5063384aa050bb
BLAKE2b-256 cb18b83d2e1fd3afa7d43e1cf934f36fc9433edda3438f122ec246a32269e8f1

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