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.3.tar.gz (114.2 kB 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.3-py3-none-any.whl (62.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: hgrabber_sdk-0.1.3.tar.gz
  • Upload date:
  • Size: 114.2 kB
  • 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.3.tar.gz
Algorithm Hash digest
SHA256 86cb04a6ac0eff787280688abf33e1bf1c9bf5dd2133f0fbeed82864621ad18d
MD5 07859139f35bc710c604b7700c03ec87
BLAKE2b-256 755b33c3b74c70f282df7e2c65a4781b555d871e165f6c6f4fca96620f99998a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: hgrabber_sdk-0.1.3-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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 370546a1272cb964cb46c071e9ec75141e2b2012ef75f1f68e0ee6686822a9d2
MD5 53fe3f9527bf105fdd985710e80877c2
BLAKE2b-256 26480d3907b76ad9a26e285fc31fbacd0d78d9841224b88ce823c341f31166f4

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