Introduction

GXCI is a high-level encapsulation based on the Rust of the Daheng camera API

Modules

It is mainly divided into four modules:

  1. HAL API: High-level encapsulation based on RAW Wrapper for specific functions
  2. RAW Wrapper: Direct Rust encapsulation of GxIAPI.dll, providing native API calls
  3. Utils: Some utility functions
  4. Error Handling: Unified error handling

Features

There are currently four Features:

  • solo: Single camera mode
  • use-opencv: Use the opencv library
  • (under development) multi-mode: Multi-camera mode
  • (under development) use-imageproc: Use the imageproc library

The default is solo and use-opencv

Getting Started

This section is mainly divided into

  1. Migration from the old version
  2. Pre-configuration items
  3. Installation
  4. List your devices
  5. Take a picture
  6. Streaming
  7. Adjust camera settings

These seven parts, combined with examples, quickly get started with GXCI

Migration

If you are using GXCI for the first time, you can skip this section. This section is mainly to help GXCI users before 0.3.6 migrate to the new version.

GXCI has been using version 4.9.0 of OpenCV since 0.3.5 and earlier versions, but GXCI has been using version 4.10.0 of OpenCV since 0.3.6. So users also need to upgrade their OpenCV version accordingly.

Upgrade OpenCV through Choco

choco upgrade chocolatey
choco upgrade opencv

Change system environment variables

Update the system variable OPENCV_LINK_LIBS to opencv_world4100

If you encounter the error STATUS_DLL_NOT_FOUND in the future, just copy a copy of opencv_world4100.dll to the same folder as the exe

Clean up the old version Target

If you have used GXCI before, you may need to clean up the previous target folder, because the previous target folder may have some old dependent libraries, resulting in compilation errors

cargo clean

Prerequisites

There are two prerequisites in total, namely the official driver of Daheng camera and OpenCV.

Official driver of Daheng camera

GXCI library is developed based on the C language dll provided by the official driver of Daheng camera (i.e. GxIAPI.dll), which is located by default at C:\Program Files\Daheng Imaging\GalaxySDK\APIDll\Win64\GxIAPI.dll

You can download the driver of the camera you are using directly from the official website of Daheng.

OpenCV

The default image processing library that GXCI depends on is opencv, which is the Rust binding library of OpenCV.

This part of the configuration can refer to the following articles.

Of course, we also provide a pre-configured method for OpenCV-rust.

Install LLVM and OpenCV 4.10.0

In Windows 10/11, I recommend using Chocolatey to install LLVM and OpenCV 4.10.0:

choco install llvm opencv

Here are some official websites that will be used:

Add Path environment variables (system variables)

Add the following paths to the corresponding system Path environment variables:

  1. OpenCV bin path
  2. OpenCV x64 bin path
  3. Chocolatey bin path
  4. LLVM bin path

Please adjust according to your installation path, here is an example:

C:\tools\opencv\build\bin
C:\tools\opencv\build\x64\vc16\bin
C:\ProgramData\chocolatey\bin
C:\Program Files\LLVM\bin

Add OpenCV environment variables (system variables)

Create three system variables:

  1. OPENCV_INCLUDE_PATHS
  2. OPENCV_LINK_LIBS
  3. OPENCV_LINK_PATHS

Please adjust according to your installation path, here is an example: |Variable name|Variable value| |---|---| |OPENCV_INCLUDE_PATHS|C:\tools\opencv\build\include| |OPENCV_LINK_LIBS|opencv_world410| |OPENCV_LINK_PATHS|C:\tools\opencv\build\x64\vc16\lib|

Copy opencv_world410.dll to the target directory (if necessary)

Sometimes you need to copy opencv_world4100.dll to the target directory, which is the same directory as the exe file.

Restart the computer (if necessary)

Sometimes you need to restart the computer to make the environment variables take effect.

Galaxy Viewer (optional)

Galaxy Viewer is a camera debugging tool provided by Daheng Imaging, which can be used to view camera parameters, adjust camera parameters, etc.

Oh, what's this part? Unbengable babble

The OpenCV library is used here to conveniently matrix the image and provide GUI display of the image, in other words, to save the image and display the push stream. In fact, GXCI currently does not use too many image processing algorithms.

How should I put it, I think OpenCV is indeed a necessary library in the field of image processing, so we also re-exported this library, and the dependency enabled the use-opencv feature of gxci can directly use use gxci::opencv to use opencv.

But the disadvantage of OpenCV is that the configuration and compilation time are a bit difficult, so here is also a use-imageproc feature, which uses the imageproc library to avoid using OpenCV.

But in my testing process, the compilation time of imageproc is also very long (or I have never compiled it successfully), especially in the nalgebra part. One day I spent 3 hours compiling the nalgebra of imageproc and it was not finished yet, it was definitely stuck there, and I was forced to terminate the attempt. So I can only think that OpenCV is still a good choice, so the default feature enabled by GXCI is the use-opencv feature.

Installation

Add the dependency to your Cargo.toml:

[dependencies]
gxci = "0.3.6"
# Only support solo and use-opencv features,because multi-camera and use-imageproc are under development

That's it, start using the library!

List your devices

HAL code example

Here is an example code that lists the devices connected to the computer. This example code uses the gxi_count_devices and gxi_list_devices functions to get the number of devices and device information, and then uses the print_device_info function to print the device information.


use gxci::hal::base::*;
use gxci::hal::device::{gxi_count_devices,gxi_list_devices};
use gxci::utils::debug::print_device_info;

fn main()->Result<()> {
    gxci_init_default()?;

    let device_num = gxi_count_devices(1000)?;
    println!("Device number: {}", device_num);

    let base_info = gxi_list_devices()?;
    for device in &base_info {
        print_device_info(&device);
    }
    
    gxci_close()?;

    Ok(())
}

HAL Attention

  1. It is recommended to import all functions from the base module of the hal part using use gxci::hal::base::*. This is because all functions in this module will be used, and the Result type of the error module is re-exported here for easy error handling.
  2. The default initialization address of gxci_init_default() is "C:\\Program Files\\Daheng Imaging\\GalaxySDK\\APIDll\\Win64\\GxIAPI.dll". If your DLL file is not in the default path, you can use gxci_init("your_dll_path") to initialize it. (Currently only absolute paths are supported, please concatenate them yourself)
  3. The parameter of the gxi_count_devices function is the timeout time, usually just pass 1000, in milliseconds.
  4. The gxi_list_devices function returns a Vec<GX_DEVICE_BASE_INFO>. The specific content of GX_DEVICE_BASE_INFO can be found in the struct section of the GXCI Docs.rs document or Daheng's C language SDK document. The document is included with the SDK and is located by default at C:\Program Files\Daheng Imaging\GalaxySDK\Doc. You can find it yourself according to the installation directory.
  5. Remember to call gxci_close() to release the DLL when the program ends.

RAW code example

Here is an example code that lists the devices connected to the computer. First, create a GXInstance, then call the gx_init_lib function to initialize the library, then call the gx_update_device_list and gx_get_all_device_base_info functions to get the number of devices and device information, and then use the print_device_info function to print the device information, and finally call the gx_close_lib function to close the library.


use std::mem::size_of;
use gxci::{
    raw::{
        gx_interface::*, 
        gx_struct::*,
    },
    utils::{
        debug::print_device_info,
        builder::GXDeviceBaseInfoBuilder,
    },
};

fn main() {
        // You can change the library path as you need
        let gx = GXInstance::new("C:\\Program Files\\Daheng Imaging\\GalaxySDK\\APIDll\\Win64\\GxIAPI.dll").expect("Failed to load library");
        gx.gx_init_lib().expect("Failed to initialize library");

        let mut device_num = 0;
        gx.gx_update_device_list(&mut device_num, 1000)
            .expect("Failed to update device list");

        if device_num > 0 {

            let mut base_info: Vec<GX_DEVICE_BASE_INFO> = (0..device_num).map(|_| {
                GXDeviceBaseInfoBuilder::new().build()
            }).collect();
            
            // or you can use the following code to initialize the vector without using the builder

            // let mut base_info = vec![
            //     GX_DEVICE_BASE_INFO {
            //         szVendorName: [0; GX_INFO_LENGTH_32_BYTE],
            //         szModelName: [0; GX_INFO_LENGTH_32_BYTE],
            //         szSN: [0; GX_INFO_LENGTH_32_BYTE],
            //         szDisplayName: [0; GX_INFO_LENGTH_128_BYTE],
            //         szDeviceID: [0; GX_INFO_LENGTH_64_BYTE],
            //         szUserID: [0; GX_INFO_LENGTH_64_BYTE],
            //         accessStatus: GX_ACCESS_STATUS_CMD::Unknown,
            //         deviceClass: GX_DEVICE_CLASS::Unknown,
            //         reserved: [0; 300],
            //     };
            //     device_num as usize
            // ];

            let mut size = (device_num as usize) * size_of::<GX_DEVICE_BASE_INFO>();
            let status = gx
                .gx_get_all_device_base_info(base_info.as_mut_ptr(), &mut size)
                .expect("Failed to get all device base info");

            if status == 0 {
                // Assuming 0 is GX_STATUS_SUCCESS
                println!(
                    "Device base info retrieved successfully. Number of devices: {}",
                    device_num
                );
                for device in &base_info {
                    print_device_info(&device);
                }

            } else {
                println!("Failed to retrieve device base info, status: {}", status);
            }
        } else {
            println!("No Devices found.");
        }

        gx.gx_close_lib().expect("Failed to close library");
        println!("Library closed.")
    }

RAW Attention

  1. Use with caution, it is more comfortable to use hal for normal development (mainly because I am lazy to write documents)

Take a Image

HAL Code Example

Taking a picture first requires opening the device with gxi_open_device, then calling gxi_get_image to get the image, and finally calling gxi_save_image_as_png to save the image in the buffer. After that, call gxi_close_device to close the device.

Of course, in addition to gxi_get_image to save the image data in the buffer and return Resulf<()>, there are also two functions gxi_get_image_as_raw and gxi_get_image_as_bytes that can return the acquired image data. The former returns Result<&[u8]>, and the latter returns Result<Vec<u8>>.

use gxci::hal::device::*;
use gxci::hal::base::*;
use gxci::utils::debug::print_device_info;

fn main()->Result<()> {
    gxci_init_default()?;

    let device_num = gxi_count_devices( 1000)?;
    println!("Device number: {}", device_num);

    let base_info = gxi_list_devices()?;
    for device in &base_info {
        print_device_info(&device);
    }
    
    gxi_open_device()?;

    gxi_get_image()?;
    
    gxi_save_image_as_png("test.png")?;

    gxi_close_device()?;

    gxci_close()?;
    
    Ok(())
}

HAL Attention

  1. Of course, you can also take the lazy approach and import everything from 'device' at once, 23333
  2. gxi_open_device defaults to opening the first device in solo mode. Multiple devices are not yet supported
  3. gxi_get_image returns Result<()> because the image data is saved in the buffer, so this function only saves the image data in the buffer. If you want to get the image data, you can use the two functions gxi_get_image_as_raw and gxi_get_image_as_bytes
  4. The parameter of the gxi_save_image_as_png function is the file name to save, and it is saved in the current directory

RAW Code Example

Taking a picture first requires opening the device with gx_open_device_by_index, then sending the GX_COMMAND_ACQUISITION_START command to start the acquisition, then calling gx_get_image to get the image, after the acquisition is successful, calling the opencv library to convert the image_buffer to a Mat object, and finally calling the imwrite function of the opencv library to save the image. After that, call gx_send_command to send the GX_COMMAND_ACQUISITION_STOP command to stop the acquisition, and finally call gx_close_device to close the device.

use std::mem::size_of;
use std::slice;

use opencv::{
    imgcodecs,
    core,
};

use gxci::{
    raw::{
        gx_interface::*, 
        gx_enum::*,
        gx_struct::*,
        gx_handle::*,
    },
    utils::{
        debug::print_device_info,
        builder::GXDeviceBaseInfoBuilder,
        facade::*,
    },
};


fn main() -> Result<()> {
    unsafe {
        let gx = GXInstance::new("C:\\Program Files\\Daheng Imaging\\GalaxySDK\\APIDll\\Win64\\GxIAPI.dll").expect("Failed to load library");
        gx.gx_init_lib().expect("Failed to initialize library");

        // Update the device list
        let mut device_num = 0;
        gx.gx_update_device_list(&mut device_num, 1000)
            .expect("Failed to update device list");

        if device_num > 0 {

            let mut base_info: Vec<GX_DEVICE_BASE_INFO> = (0..device_num).map(|_| {
                GXDeviceBaseInfoBuilder::new().build()
            }).collect();
            let mut size = (device_num as usize) * size_of::<GX_DEVICE_BASE_INFO>();
            let status = gx
                .gx_get_all_device_base_info(base_info.as_mut_ptr(), &mut size)
                .expect("Failed to get all device base info");

            if status == 0 {
                println!(
                    "Device base info retrieved successfully. Number of devices: {}",
                    device_num
                );
                
                for device in &base_info {
                    print_device_info(&device);
                }

                let first_device_sn = std::str::from_utf8(&base_info[0].szSN).unwrap_or("");
                let mut device_handle: GX_DEV_HANDLE = std::ptr::null_mut();

                let open_status = gx
                    .gx_open_device_by_index(1, &mut device_handle)
                    .expect("Failed to open device with index");

                if open_status == 0 {
                    println!(
                        "Successfully opened device index 1 with SN: {}",
                        first_device_sn.trim_end_matches(char::from(0))
                    );

                    gx.gx_send_command(device_handle, GX_FEATURE_ID::GX_COMMAND_ACQUISITION_START)
                        .expect("Failed to send command");

                    // 这种写法在所有权机制下是错误的,因为image_buffer在返回的时候就已经被释放了
                    // let frame_data_facade = fetch_frame_data(&gx, device_handle);
                    // let mut frame_data = convert_to_frame_data(&frame_data_facade.unwrap());
                    
                    // 这种写法是正确的,因为image_buffer被返回到了当前作用域
                    #[allow(unused_variables)]
                    let (frame_data_facade, image_buffer) = fetch_frame_data(&gx, device_handle).unwrap();
                    let mut frame_data = convert_to_frame_data(&frame_data_facade);


                        let result = gx.gx_get_image(device_handle, &mut frame_data, 100);
                        match result {
                            Ok(_) => {
                                println!("Image captured successfully.");

                                if frame_data.nStatus == 0 {
                                    let data = slice::from_raw_parts(frame_data.pImgBuf as *const u8, (frame_data.nWidth * frame_data.nHeight) as usize);
                                    
                                    let mat = core::Mat::new_rows_cols_with_data(
                                        frame_data.nHeight, 
                                        frame_data.nWidth, 
                                        data
                                    ).unwrap();
                        
                                    let vec = core::Vector::<i32>::new();
                                    if imgcodecs::imwrite("right.png", &mat, &vec).unwrap() {
                                        println!("Image saved successfully.");
                                    } else {
                                        println!("Failed to save the image.");
                                    }
                                    
                                }
                            }
                            Err(e) => eprintln!("Failed to capture image: {:?}", e),
                        }

                    gx.gx_send_command(device_handle, GX_FEATURE_ID::GX_COMMAND_ACQUISITION_STOP)
                        .expect("Failed to send command");

                    // Close the device
                    gx.gx_close_device(device_handle)
                        .expect("Failed to close device");
                    println!("Device closed.")
                } else {
                    println!(
                        "Failed to open device with SN: {}",
                        first_device_sn.trim_end_matches(char::from(0))
                    );
                }
            } else {
                println!("Failed to retrieve device base info, status: {}", status);
            }
        } else {
            println!("No Devices found.");
        }

        gx.gx_close_lib().expect("Failed to close library");
        println!("Library closed.");
        Ok(())
    }
}

RAW Attention

  1. Use with caution, it is more comfortable to use hal for normal development (mainly because I am lazy to write documents)
  2. The image_buffer is released when it is returned, so if it is not returned to the current scope, it will be released in the facade function, causing the image data to be directly unavailable in the following text (send the guest without receiving the guest, then the guest dies in a foreign land~)

Streaming

HAL Code Example

The core function is gxi_use_stream, a function added in version 0.3.4.

use gxci::hal::device::*;
use gxci::hal::base::*;
use gxci::utils::debug::print_device_info;
use gxci::utils::extract::{extract_callback_img_buf,extract_frame_callback_param};
use gxci::raw::gx_struct::GX_FRAME_CALLBACK_PARAM;
use gxci::raw::gx_interface::Result;
use gxci::opencv::{core, highgui};


extern "C" fn frame_callback(p_frame_callback_data: *mut GX_FRAME_CALLBACK_PARAM) {
    
    let frame_callback_data = extract_frame_callback_param(p_frame_callback_data);
    let data = extract_callback_img_buf(frame_callback_data);

    let mat = core::Mat::new_rows_cols_with_data(
        frame_callback_data.nHeight, 
        frame_callback_data.nWidth, 
        data
    ).unwrap();
    
    highgui::imshow("Camera Frame", &mat).unwrap();
    if highgui::wait_key(10).unwrap() > 0 {
        highgui::destroy_window("Camera Frame").unwrap();
    }
}

fn main()->Result<()> {
    gxci_init_default()?;

    let device_num = gxi_count_devices( 1000)?;
    println!("Device number: {}", device_num);

    let base_info = gxi_list_devices()?;
    for device in &base_info {
        print_device_info(&device);
    }

    gxi_open_device()?;

    gxi_use_stream(frame_callback)?;

    gxi_close_device()?;

    gxci_close()?;

    Ok(())
}

HAL Attention

  1. The most impressive function is gxi_use_stream, which takes a callback function of type pub type GXCaptureCallBack = extern "C" fn(pFrameData: *mut GX_FRAME_CALLBACK_PARAM); as its parameter. This allows you to define your own callback function to handle the image data captured from the stream. Additionally, the utils module provides two helper functions - extract_callback_img_buf and extract_frame_callback_param - to help you extract image data from within the callback function.
  2. In this case, the frame_callback simply displays the image using OpenCV - nothing fancy. You can process the image data however you want based on your needs. For example, you could expose the image data through global variables and then process it in the main thread, among other approaches.

RAW Code Example

use std::mem::size_of;
use std::slice;
use std::thread::sleep;
use std::time::Duration;

use opencv::{
    highgui,
    core,
};

use gxci::{
    raw::{
        gx_interface::*, 
        gx_enum::*,
        gx_struct::*,
        gx_handle::*,
    },
    utils::{
        debug::print_device_info,
        builder::GXDeviceBaseInfoBuilder,
    },
};

extern "C" fn frame_callback(p_frame_callback_data: *mut GX_FRAME_CALLBACK_PARAM) {
    // 避免刷屏
    // println!("Frame callback triggered.");
    // println!("Frame status: {:?}", unsafe { (*p_frame_callback_data).status });
    // println!("Frame All: {:?}", unsafe { *p_frame_callback_data });

    unsafe {
        let frame_callback_data = &*p_frame_callback_data;
        if frame_callback_data.status == 0 {
            let data = slice::from_raw_parts(frame_callback_data.pImgBuf as *const u8, (frame_callback_data.nWidth * frame_callback_data.nHeight) as usize);
            let mat = core::Mat::new_rows_cols_with_data(
                frame_callback_data.nHeight, 
                frame_callback_data.nWidth, 
                // core::CV_8UC1, 
                data
            ).unwrap();
            highgui::imshow("Camera Frame", &mat).unwrap();
            if highgui::wait_key(10).unwrap() > 0 {
                highgui::destroy_window("Camera Frame").unwrap();
            }
        }
    }
}

fn main()->Result<()> {
        // You can change the library path as you need
        let gx = GXInstance::new("C:\\Program Files\\Daheng Imaging\\GalaxySDK\\APIDll\\Win64\\GxIAPI.dll").expect("Failed to load library");
        gx.gx_init_lib().expect("Failed to initialize library");

        // Update the device list
        let mut device_num = 0;
        gx.gx_update_device_list(&mut device_num, 1000)
            .expect("Failed to update device list");

        if device_num > 0 {

            let mut base_info: Vec<GX_DEVICE_BASE_INFO> = (0..device_num).map(|_| {
                GXDeviceBaseInfoBuilder::new().build()
            }).collect();
            let mut size = (device_num as usize) * size_of::<GX_DEVICE_BASE_INFO>();
            let status = gx
                .gx_get_all_device_base_info(base_info.as_mut_ptr(), &mut size)
                .expect("Failed to get all device base info");

            if status == 0 {
                // Assuming 0 is GX_STATUS_SUCCESS
                println!(
                    "Device base info retrieved successfully. Number of devices: {}",
                    device_num
                );
                
                for device in &base_info {
                    print_device_info(&device);
                }

                // Attempt to open the first device using its SN
                let first_device_sn = std::str::from_utf8(&base_info[0].szSN).unwrap_or("");
                let mut device_handle: GX_DEV_HANDLE = std::ptr::null_mut();

                let open_status = gx
                    .gx_open_device_by_index(1, &mut device_handle)
                    .expect("Failed to open device with index");

                if open_status == 0 {
                    println!(
                        "Successfully opened device index 1 with SN: {}",
                        first_device_sn.trim_end_matches(char::from(0))
                    );

                    gx.gx_set_float(device_handle, GX_FEATURE_ID::GX_FLOAT_GAIN, 20.0)?;

                    let reg_result = gx.gx_register_capture_callback(device_handle, frame_callback);
                    match reg_result {
                        Ok(_) => println!("Capture callback registered successfully."),
                        Err(e) => eprintln!("Failed to register capture callback: {:?}", e),
                    }

                    gx.gx_send_command(device_handle, GX_FEATURE_ID::GX_COMMAND_ACQUISITION_START)
                        .expect("Failed to send command");
                        
                        highgui::named_window("Camera", highgui::WINDOW_AUTOSIZE).unwrap();
                    loop {
                        sleep(Duration::from_secs(60));
                        break;
                    }

                    gx.gx_send_command(device_handle, GX_FEATURE_ID::GX_COMMAND_ACQUISITION_STOP)
                        .expect("Failed to send command");

                    let unregeister_result = gx.gx_unregister_capture_callback(device_handle);
                    match unregeister_result {
                        Ok(_) => println!("Capture callback unregistered successfully."),
                        Err(e) => eprintln!("Failed to unregister capture callback: {:?}", e),
                    }

                    // Close the device
                    gx.gx_close_device(device_handle)
                        .expect("Failed to close device");
                    println!("Device closed.")
                } else {
                    println!(
                        "Failed to open device with SN: {}",
                        first_device_sn.trim_end_matches(char::from(0))
                    );
                }
            } else {
                println!("Failed to retrieve device base info, status: {}", status);
            }
        } else {
            println!("No Devices found.");
        }

        gx.gx_close_lib().expect("Failed to close library");
        println!("Library closed.");
        Ok(())
    }

RAW Attention

  1. Use with caution, it is more comfortable to use hal for normal development (mainly because I am lazy to write documents)

Adjusting Camera Settings

HAL Code Example

Here we continue with the code from the previous streaming section. Here we adjust some camera parameters, such as setting the camera's resolution, automatic gain, etc., which are set by the gxi_set_width, gxi_set_height, gxi_set_gain_auto_continuous, and gxi_set_gain functions, respectively.

use gxci::hal::device::*;
use gxci::hal::base::*;
use gxci::hal::control::analog::*;
use gxci::hal::control::image_format::*;
use gxci::utils::debug::print_device_info;
use gxci::utils::extract::{extract_callback_img_buf,extract_frame_callback_param};
use gxci::raw::gx_struct::GX_FRAME_CALLBACK_PARAM;
use gxci::raw::gx_interface::Result;
use gxci::opencv::{core, highgui};


extern "C" fn frame_callback(p_frame_callback_data: *mut GX_FRAME_CALLBACK_PARAM) {
    
    let frame_callback_data = extract_frame_callback_param(p_frame_callback_data);
    let data = extract_callback_img_buf(frame_callback_data);

    let mat = core::Mat::new_rows_cols_with_data(
        frame_callback_data.nHeight, 
        frame_callback_data.nWidth, 
        data
    ).unwrap();
    
    highgui::imshow("Camera Frame", &mat).unwrap();
    if highgui::wait_key(10).unwrap() > 0 {
        highgui::destroy_window("Camera Frame").unwrap();
    }
}

fn main()->Result<()> {
    gxci_init_default()?;

    let device_num = gxi_count_devices( 1000)?;
    println!("Device number: {}", device_num);

    let base_info = gxi_list_devices()?;
    for device in &base_info {
        print_device_info(&device);
    }
    

    gxi_open_device()?;

    gxi_set_width(4024)?;
    
    gxi_set_height(3036)?;

    gxi_set_gain_auto_continuous()?;

    // gxi_set_gain(1.0)?;

    gxi_use_stream(frame_callback)?;

    gxi_close_device()?;

    gxci_close()?;

    Ok(())
}

HAL Attention

  1. Pay attention to the setting range of parameters, such as the setting range of resolution, the setting range of gain, etc. Exceeding the camera's limit range will cause the function to return an error.
  2. In fact, the control module is written according to the setting interface of Galaxy Viewer, covering most of the camera parameter setting needs. However, it is set through the gxi_get_feature_value and gxi_set_feature_value functions at the bottom, so if there are special parameter setting needs, you can refer to the specific document to directly call these two functions.

RAW Code Example

Oh, this hasn't been written yet

RAW Attention

  1. Write when I have time

Change Log

0.1

  • The raw module is migrated from the gxi_hako library, and then the gxi_hako library enters the deprecated state
  • The hal module is initially implemented for basic camera operations

0.2

0.2.0

  • The raw module is secured, and now all calls to the raw module do not require an unsafe block
  • Initial implementation of global error handling, but in the gx_interface of the raw module
  • Images in the md document are uploaded to the cloud to reduce volume

0.2.3

  • The solo feature is reintroduced
  • gxci_init_default() can load GxIAPI.dll from the default path, and gxci_check_device_handle() can check whether the device handle is valid
  • gxi_get_device_handle() is used to obtain the device handle

0.2.4

  • gxi_get_device_handle() is used to obtain the device handle
  • The config module is initialized, but no functions are implemented

0.3

0.3.0

  • Added the check module to hal for checking common errors
  • Added the config module to hal for configuring camera parameters, but some FeatureIDs are missing, resulting in some functions not implemented
  • Added the control module to hal for camera control, based on the sidebar of Galaxy Viewer

0.3.2

  • gxi_use_stream() allows the use of custom stream callback functions to process image data. You can see the usage in the hal_use_stream example

0.3.3

  • re-exported opencv and imageproc, you can access these two modules through gxci::opencv and gxci::imageproc

0.3.4

  • gxi_get_image_as_frame_data(), gxi_get_image_as_raw() and gxi_get_image_as_bytes() provide interfaces for using image data, and provide examples

0.3.5

  • Independent error.rs module and optimized error handling section

0.3.6

  • Upgraded to OpenCV 4.10.0, dependent on opencv and upgraded to the latest 0.93.5
  • Built a Chinese and English document site based on mdbook, providing a quick start tutorial, the URL is https://hakochest.github.io/gxci/

What's this? It seems like it was written before, but let's keep it

The old version is a crate library called gxi_hako, which is not completely implemented in the raw and utils parts, and is now temporarily abandoned;

The new version is this gxci, which contains the implementation of the raw, HAL, and utils parts;

As of now, 11:45 PM on July 11, 2024, the HAL library writing part of features=["solo"] has been completed, and the multi-camera feature has not been implemented yet. Let's update it when we are free again(๑˃ᴗ˂)ﻭ

September 8, 2024, 9:15 PM, 2.0 update! Mainly error handling and security, now all library functions are safe, and a very standardized and robust error handling has been established. In addition, all examples have been updated, eliminating all warnings.

September 19, 2024, 4:09 PM, 3.0 update! Mainly added the config module, now all HAL and raw-binding config modules have been implemented, you can adjust width, height, gain, white balance and all implemented camera parameters! But due to the lack of some FeatureID in inc, some functions in the config module have not been implemented. In addition, the control module has been added, which is an encapsulation of the sidebar commonly used in Galaxy Viewer.

Roadmap

0.4

  • Add multi-camera support
  • Try to solve the dependency problem of imageproc

Appendix

GxIAPI.dll method implementation status

  • 302 0 0001C020 GXCloseDevice
  • 101 1 0001BBC0 GXCloseLib
  • 700 2 0001E9E0 GXExportConfigFile
  • 707 3 0001EA50 GXExportConfigFileW ?This function is not mentioned in the development document
  • 602 4 0001E920 GXFlushEvent
  • 505 5 0001E6E0 GXFlushQueue
  • 201 6 0001BDE0 GXGetAllDeviceBaseInfo
  • 414 7 0001D5F0 GXGetBool
  • 419 8 0001E080 GXGetBuffer
  • 418 9 0001DF50 GXGetBufferLength
  • 205 A 0001BE80 GXGetDeviceIPInfo
  • 423 B 0001C0B0 GXGetDevicePersistentIpAddress
  • 411 C 0001D3C0 GXGetEnum
  • 410 D 0001CF50 GXGetEnumDescription
  • 409 E 0001CE20 GXGetEnumEntryNums
  • 506 F 0001E970 GXGetEventNumInQueue
  • 422 10 0001C1E0 GXGetFeatureName
  • 408 11 0001CCF0 GXGetFloat
  • 406 12 0001C960 GXGetFloatRange
  • 504 13 0001E670 GXGetImage
  • 404 14 0001C730 GXGetInt
  • 403 15 0001C590 GXGetIntRange
  • 204 16 0001BC40 GXGetLastError
  • 709 17 0001F370 GXGetOptimalPacketSize (Windows Only)
  • 416 18 0001DAA0 GXGetString
  • 415 19 0001D820 GXGetStringLength
  • 425 1A 0001D970 GXGetStringMaxLength
  • 705 1B 0001EEF0 GXGigEForceIp
  • 704 1C 0001ECC0 GXGigEIpConfiguration
  • 706 1D 0001F170 GXGigEResetDevice
  • 701 1E 0001EAC0 GXImportConfigFile
  • 708 1F 0001EB40 GXImportConfigFileW ?This function is not mentioned in the development document
  • 100 20 0001BB70 GXInitLib
  • 400 21 0001C260 GXIsImplemented
  • 401 22 0001C370 GXIsReadable
  • 402 23 0001C480 GXIsWritable
  • 301 24 0001BFB0 GXOpenDevice
  • 300 25 0001BF10 GXOpenDeviceByIndex
  • 702 26 0001EBC0 GXReadRemoteDevicePort
  • 710 27 0001F3E0 GXReadRemoteDevicePortStacked
  • 500 28 0001E5B0 GXRegisterCaptureCallback
  • 600 29 0001E730 GXRegisterDeviceOfflineCallback
  • 603 2A 0001E820 GXRegisterFeatureCallback
  • 421 2B 0001E480 GXSendCommand
  • 507 2C 0001F100 GXSetAcqusitionBufferNumber
  • 413 2D 0001D720 GXSetBool
  • 420 2E 0001E350 GXSetBuffer
  • 424 2F 0001C160 GXSetDevicePersistentIpAddress
  • 412 30 0001D4F0 GXSetEnum
  • 407 31 0001CBE0 GXSetFloat
  • 405 32 0001C860 GXSetInt
  • 417 33 0001DDC0 GXSetString
  • 501 34 0001E620 GXUnregisterCaptureCallback
  • 601 35 0001E7B0 GXUnregisterDeviceOfflineCallback
  • 604 36 0001E8B0 GXUnregisterFeatureCallback
  • 206 37 0001BD70 GXUpdateAllDeviceList
  • 200 38 0001BD00 GXUpdateDeviceList
  • 703 39 0001EC40 GXWriteRemoteDevicePort
  • 711 3A 0001F450 GXWriteRemoteDevicePortStacked (Windows Only)

HAL module function implementation status

  • base
    • gxi_check()
    • gxci_init()
    • gxci_init_default()
    • gxci_close()
  • device
    • gxi_count_devices()
    • gxi_list_devices()
    • gxi_open_device() // solo feature
    • gxi_close_device() // solo feature
    • gxi_check_device_handle() // solo feature
    • gxi_send_command() // solo feature
    • gxi_get_image() // solo feature
    • gxi_open_stream() // solo feature
    • gxi_open_stream_interval() // solo feature
    • gxi_close_stream() // solo feature
  • check
    • check_status()
    • check_status_with_ok_fn()
    • check_gx_status()
    • check_gx_status_with_ok_fn()
  • config
    • Here are the HAL functions
    • gxi_get_feature_value()
    • gxi_set_feature_value()
    • Following are the raw-wapper functions
    • gxi_get_feature_name()
    • gxi_get_int_range()
    • gxi_get_int()
    • gxi_set_int()
    • gxi_get_float_range()
    • gxi_get_float()
    • gxi_set_float()
    • gxi_get_enum_entry_nums()
    • gxi_get_enum_description()
    • gxi_get_enum()
    • gxi_set_enum()
    • gxi_get_bool()
    • gxi_set_bool()
    • gxi_get_string_length()
    • gxi_get_string_max_length()
    • gxi_get_string()
    • gxi_set_string()
    • gxi_get_buffer_length()
    • gxi_get_buffer()
    • gxi_set_buffer()
  • control (Here only the number of functions is listed, the list is too long, so please refer to the ControlList markdown)
    • device 17
    • image_format 27+
    • acquisition 46+
    • digital_io 0 (But MISSING this module's FEATURE_ID)
    • analog 40+
    • transport_layer 1
    • user_set 10
    • chunk_data 8
  • event
    • todo!()
  • network
    • todo!()

List of Control Functions

This part's list is too long, so I devided it into this document.

The special enum selection functions will be implemented in the future, but not 0.3.

And lots of feature_id are missing, so lots of functions are not implemented.

  • control
    • device
      • gxi_get_device_vendor_name()
      • gxi_get_device_model_name()
      • gxi_get_device_version()
      • gxi_get_device_firmware_version()
      • gxi_get_device_serial_number()
      • gxi_get_factory_setting_version()
      • gxi_get_device_user_id()
      • gxi_set_device_user_id()
      • gxi_get_device_link_selector()
      • gxi_set_device_link_selector()
      • gxi_get_device_link_throughput_limit_mode()
      • gxi_set_device_link_throughput_limit_mode()
      • gxi_set_device_link_throughput_limit_mode_off()
      • gxi_set_device_link_throughput_limit_mode_on()
      • gxi_get_device_link_throughput_limit()
      • gxi_set_device_link_throughput_limit()
      • gxi_get_device_link_current_throughput()
      • todo!()
    • image_format
      • gxi_get_sensor_width()
      • gxi_get_sensor_height()
      • gxi_get_max_width()
      • gxi_get_max_height()
      • gxi_get_width()
      • gxi_set_width()
      • gxi_get_height()
      • gxi_set_height()
      • gxi_get_offset_x()
      • gxi_set_offset_x()
      • gxi_get_offset_y()
      • gxi_set_offset_y()
      • gxi_get_region_selector()
      • gxi_set_region_selector()
      • gxi_set_region_selector_region0()
      • gxi_get_pixel_format()
      • gxi_set_pixel_format()
      • gxi_set_pixel_format_bayer_rgb()
      • gxi_set_pixel_format_bayer_rg10()
      • gxi_get_pixel_size()
      • gxi_get_pixel_color_filter()
      • gxi_get_test_pattern_generator_selector()
      • gxi_set_test_pattern_generator_selector()
      • gxi_set_test_pattern_generator_selector_region0()
      • gxi_get_test_pattern()
      • gxi_set_test_pattern()
      • gxi_set_test_pattern_off()
      • gxi_set_test_pattern_gray_frame_ramp_moving()
      • gxi_set_test_pattern_slant_line_moving()
      • gxi_set_test_pattern_slant_line()
      • todo!()
    • acquisition
      • gxi_get_acquisition_mode()
      • gxi_set_acquisition_mode()
      • gxi_set_acquisition_mode_continuous()
      • gxi_acquisition_start()
      • gxi_acquisition_stop()
      • gxi_get_trigger_selector()
      • gxi_set_trigger_selector()
      • gxi_set_trigger_selector_frame_start()
      • gxi_get_trigger_mode()
      • gxi_set_trigger_mode()
      • gxi_set_trigger_mode_off()
      • gxi_get_trigger_source()
      • gxi_set_trigger_source()
      • gxi_set_trigger_source_software()
      • gxi_set_trigger_source_line0()
      • gxi_set_trigger_source_line2()
      • gxi_set_trigger_source_line3()
      • gxi_get_trigger_activation()
      • gxi_set_trigger_activation()
      • gxi_set_trigger_activation_falling_edge()
      • gxi_set_trigger_activation_rising_edge()
      • gxi_get_trigger_delay()
      • gxi_set_trigger_delay()
      • gxi_get_trigger_filter_rasing_edge()
      • gxi_set_trigger_filter_rasing_edge()
      • gxi_get_trigger_filter_falling_edge()
      • gxi_set_trigger_filter_falling_edge()
      • gxi_get_exposure_mode()
      • gxi_set_exposure_mode()
      • gxi_set_exposure_mode_timed()
      • gxi_get_exposure_time()
      • gxi_set_exposure_time()
      • gxi_get_exposure_auto()
      • gxi_set_exposure_auto()
      • gxi_set_exposure_auto_off()
      • gxi_set_exposure_auto_continuous()
      • gxi_set_exposure_auto_once()
      • gxi_get_auto_exposure_time_min()
      • gxi_set_auto_exposure_time_min()
      • gxi_get_auto_exposure_time_max()
      • gxi_set_auto_exposure_time_min()
      • gxi_get_aaroi_width()
      • gxi_set_aaroi_width()
      • gxi_get_aaroi_height()
      • gxi_set_aaroi_height()
      • gxi_get_aaroi_offset_x()
      • gxi_set_aaroi_offset_x()
      • gxi_get_aaroi_offset_y()
      • gxi_set_aaroi_offset_y()
      • gxi_get_expected_gray_value()
      • gxi_set_expected_gray_value()
      • todo!()
    • digital_io (But MISSING this module's FEATURE_ID)
      • gxi_get_line_selector()
      • gxi_set_line_selector()
      • gxi_set_line_selector_line0()
      • gxi_set_line_selector_line1()
      • gxi_set_line_selector_line2()
      • gxi_set_line_selector_line3()
      • gxi_get_line_mode()
      • gxi_set_line_mode()
      • gxi_set_line_mode_input()
      • gxi_get_line_inverter()
      • gxi_set_line_inverter()
      • gxi_get_line_source()
      • gxi_get_line_status()
      • gxi_get_line_status_all()
      • gxi_get_user_output_selector()
      • gxi_set_user_output_selector()
      • gxi_set_user_output_selector_user_output0()
      • gxi_set_user_output_selector_user_output1()
      • gxi_set_user_output_selector_user_output2()
      • gxi_get_user_output_value()
      • gxi_set_user_output_value()
      • todo!()
    • analog
      • gxi_get_gain_selector()
      • gxi_set_gain_selector()
      • gxi_set_gain_selector_analog_all()
      • gxi_get_gain()
      • gxi_set_gain()
      • gxi_get_gain_auto()
      • gxi_set_gain_auto()
      • gxi_set_gain_auto_off()
      • gxi_set_gain_auto_continuous()
      • gxi_set_gain_auto_once()
      • gxi_get_auto_gain_min()
      • gxi_set_auto_gain_min()
      • gxi_get_auto_gain_max()
      • gxi_set_auto_gain_max()
      • gxi_get_balance_ratio_selector()
      • gxi_set_balance_ratio_selector()
      • gxi_set_balance_ratio_selector_red()
      • gxi_set_balance_ratio_selector_green()
      • gxi_set_balance_ratio_selector_blue()
      • gxi_get_balance_ratio()
      • gxi_get_balance_white_auto()
      • gxi_set_balance_white_auto()
      • gxi_set_balance_white_auto_off()
      • gxi_set_balance_white_auto_continuous()
      • gxi_set_balance_white_auto_once()
      • gxi_get_awb_lamp_house()
      • gxi_set_awb_lamp_house()
      • gxi_set_awb_lamp_house_adaptive()
      • todo!("more variants")
      • gxi_get_awbroi_width()
      • gxi_set_awbroi_width()
      • gxi_get_awbroi_height()
      • gxi_set_awbroi_height()
      • gxi_get_awbroi_offset_x()
      • gxi_set_awbroi_offset_x()
      • gxi_get_awbroi_offset_y()
      • gxi_set_awbroi_offset_y()
      • todo!()
    • transport_layer
      • gxi_get_payload_size()
      • todo!()
    • user_set
      • gxi_get_user_set_selector()
      • gxi_set_user_set_selector()
      • gxi_set_user_set_selector_default()
      • gxi_set_user_set_selector_user_set0()
      • gxi_user_set_load()
      • gxi_user_set_save()
      • gxi_get_user_set_default()
      • gxi_set_user_set_default()
      • gxi_set_user_set_default_default()
      • gxi_set_user_set_default_user_set0()
      • todo!()
    • chunk_data
      • gxi_get_chunk_mode_active()
      • gxi_set_chunk_mode_active()
      • gxi_get_chunk_selector()
      • gxi_set_chunk_selector()
      • gxi_set_chunk_selector_frame_id()
      • gxi_set_chunk_selector_timestamp()
      • gxi_get_chunk_enable()
      • gxi_set_chunk_enable()
      • gxi_get_chunk_timestamp()
      • todo!()

Troubleshoting

If you have any questions, please issue it.

If you want to contribute, please fork it and pull request.

If you want to contact me, you can email me: zoneherobrine@gmail.com;

or by Tencent QQ: 2212540603 (with related information in the friend request)

Ending

Reference