How to connect to a Daheng Imaging camera through Python

Based on contributions by Joel.

Daheng Imaging cameras can be accessed from Python either through Daheng’s own gxipy SDK, or through the vendor-neutral Harvester/GenICam library. This how-to covers both, so you have a fallback if one approach doesn’t work for your setup.

What you need

  • A Daheng Imaging camera.
  • A Daheng Imaging account to download the Galaxy Windows SDK (V2).
  • Galaxy Viewer (included in the SDK) to test the connection and check camera settings.
  • OpenCV: pip install opencv-python
  • For the Harvester approach: pip install harvesters

Steps

1. Download the SDK and test the connection

Go to the Daheng Imaging Software page and download the Galaxy Windows SDK (V2) (an account is required). Install it, then open Galaxy Viewer to confirm your camera is detected and can connect. From here you can also change camera settings such as Exposure time (under Acquisition control) and Gain (under Analog control).

There are two ways to then talk to the camera from Python: manually via the gxipy module bundled with the SDK, or via the generic Harvester/GenICam library. Try Harvester first (step 3); fall back to the manual approach (step 2) if it doesn’t work for your camera.

2. Manual approach with gxipy

After installing the SDK, locate the gxipy folder inside your Galaxy installation, by default something like:

C:\Program Files\Daheng Imaging\GalaxySDK\Development\Samples\Python\gxipy

Copy the entire folder into your project so your scripts can import it.

The class below wraps camera setup, streaming, and image retrieval, converting the raw Bayer image to RGB with OpenCV.

import gxipy as gx
import cv2
import os


class DahengCamera:
    class DahengException(Exception):
        pass

    def __init__(self):
        # Initialize the camera system
        self.device_manager = gx.DeviceManager()
        self.device_manager.update_device_list()

        dev_num = self.__get_number_of_cameras()
        if dev_num == 0:
            raise self.DahengException("No Daheng cameras detected")

        self.cam = self.device_manager.open_device_by_index(1)
        self.cam.ExposureAuto.set(False)  # auto exposure off (set exposure manually)
        self.cam.GainAuto.set(False)      # auto gain off (set gain manually)

        self.__set_sensor_area()  # full sensor area — required for full resolution

    def __get_number_of_cameras(self):
        return self.device_manager.get_device_number()

    def __set_sensor_area(self):
        self.cam.Width.set(self.cam.WidthMax.get())
        self.cam.Height.set(self.cam.HeightMax.get())
        self.cam.OffsetX.set(0)
        self.cam.OffsetY.set(0)
        self.cam.TriggerMode.set(gx.GxSwitchEntry.OFF)  # continuous capture, no trigger

    def load_config_file(self, file_path):
        if os.path.exists(file_path):
            self.cam.import_config_file(file_path)
            print("Camera settings loaded from:", file_path)
        else:
            print("Config file not found:", file_path)

    def get_frame(self):
        raw_image = self.cam.data_stream[0].get_image()
        if raw_image is None:
            return None

        raw_image = raw_image.get_numpy_array()
        # Convert Bayer to RGB
        return cv2.cvtColor(raw_image, cv2.COLOR_BAYER_GR2RGB)

    def start_stream(self):
        self.cam.stream_on()
        self.flush_buffer()

    def stop_stream(self):
        self.flush_buffer()
        self.cam.stream_off()

    def flush_buffer(self):
        for _ in range(5):  # adjust count if needed
            try:
                self.cam.StreamGetImage(timeout=50)
            except Exception:
                break  # no more frames to discard

    def change_exposure(self, exposure):
        self.cam.ExposureTime.set(exposure + 24)  # exposure can't go below 24

    def change_gain(self, gain):
        self.cam.Gain.set(gain)

    def close_connection(self):
        self.cam.stream_off()
        self.cam.close_device()

Example usage:

def main():
    cam = DahengCamera()
    cam.start_stream()

    while True:
        frame = cam.get_frame()
        resized_image = cv2.resize(frame, (640, 640), interpolation=cv2.INTER_LINEAR)

        cv2.imshow("Daheng Camera View", resized_image)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

    cam.stop_stream()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

Old/stale images: if you keep receiving old frames, the camera’s internal buffer isn’t being emptied. Call stop_stream() when you’re not actively grabbing frames, and/or call flush_buffer() to discard queued frames.

3. Harvester approach

Install the Harvesters library:

pip install harvesters

The following code opens a single image using the GenTL producer that ships with the Galaxy SDK.

from harvesters.core import Harvester
import cv2

CTI_FILE_PATH = "C:/Program Files/Daheng Imaging/GalaxySDK/GenTL/Win64/GxGVTL.cti"

with Harvester() as h:
    h.add_file(CTI_FILE_PATH)
    h.update()
    with h.create() as ia:
        ia.start()
        with ia.fetch() as buffer:
            component = buffer.payload.components[0]
            width = component.width
            height = component.height
            bayer = component.data.reshape((height, width))
            img = cv2.cvtColor(bayer, cv2.COLOR_BayerRG2BGR)
            img = img[..., ::-1]
            cv2.imshow("image", img)
            cv2.waitKey(0)
            cv2.destroyAllWindows()

For a continuous-capture version and more background on Harvester/GenICam in general, see How to get an image from a GenICam-compatible camera (e.g. a Genie Nano) using Harvester.

Common mistakes

  • Forgetting to actually call flush_buffer() (i.e. calling it without parentheses) — this silently does nothing instead of discarding stale frames.
  • Pointing CTI_FILE_PATH at the wrong GenTL producer file; it must be the .cti file bundled with the Galaxy SDK, not a generic one from another vendor.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: How to… Connect to a Daheng Imaging camera through Python.