Gige多相机高速拍照模式补充

软件触发(Software Trigger)

  • 代码指令 让相机拍一张
  • 调用:ExecuteSoftwareTrigger()
  • 不需要接线、不需要外部信号

优点:

  • 控制最灵活,想什么时候拍就什么时候拍
  • 多相机可以代码级同步
  • 适合:高精度定时采集(50ms、20ms、10ms)

缺点:

  • PC 忙的时候,触发精度会掉一点
  • 28 个相机一起触发,时序会有几毫秒偏差

硬件触发(Hardware Trigger)

最稳定、最同步、工业标准方案

  • IO 线 给相机一个 3.3V/5V 脉冲
  • 一通电,所有相机同时拍照
  • 同步精度:微秒级

优点:

  • 28 台相机可以做到 完全同时曝光
  • 不受 CPU 占用、系统延迟影响
  • 运动抓拍、高精度同步必用

缺点:

  • 要接线、要 IO 卡、要继电器 / PLC
  • 成本高、布线麻烦

自由运行 / 连续采集(Free Run / Auto)

  • 相机自己按帧率一直拍:25fps、30fps
  • 不用触发,不用指令

优点:

  • 最简单
  • 不用管

缺点:

  • 多相机完全不同步

信号触发(IO 信号、编码器、光耦)

属于硬件触发的分支:

  • 编码器触发(走多少距离拍一张)
  • 光电开关触发(有物体过来拍)
  • PLC 触发

高频单帧取图的陷阱

ExecuteSoftwareTrigger与多次调用PhotoImage

区别在于 ExecuteSoftwareTrigger流启动后,无需触发,可以根据指令触发拍照

但是PhotoImage每次都会走全流程:创建流->推缓冲区->启动采集->取帧->释放流

仅适用于偶尔手动拍一张(如调试、预览)


代码刨析

首先是触发方式是根据官方给的API:arv_camera_set_string决定的

在动态库中添加两个函数

开启软件触发前台调用m_nErrCode = m_cam->SetSoftwareTrigger(true, m_szErrMsg);

m_cam->SetTriggerSelector("FrameStart");(我没有写因为默认开启就是帧触发)

m_cam->OpenStream();启动流

cpp 复制代码
COMMON_ERR CDevice::SetSoftwareTrigger(bool enable, char* szMsg/*= NULL*/)
{

    //校验相机是否有效(m_pGige不为空)
    if (Invalidate()) return ERR_CAMERA_INVALID;

    GError* error = NULL;
    ArvCamera* camera = (ArvCamera*)m_pGige;
    COMMON_ERR nErrCode = COMMON_OK;

    // 设置 TriggerMode
    arv_camera_set_string(camera, "TriggerMode", enable ? "On" : "Off", &error);
    if (error) {
        nErrCode = error->code;
        if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
        g_clear_error(&error);
        return nErrCode;
    }

    // 开启时设置 TriggerSource = Software

    if (enable) {
        arv_camera_set_string(camera, "TriggerSource", "Software", &error);
        if (error) {
            nErrCode = error->code;
            if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
            g_clear_error(&error);
            // 可选回滚
            arv_camera_set_string(camera, "TriggerMode", "Off", nullptr);
            return nErrCode;
        }
    }

    return COMMON_OK;
}

在程序中调用m_nErrCode = m_cam->ExecuteSoftwareTrigger(m_szErrMsg);

cpp 复制代码
// 执行软件触发
COMMON_ERR CDevice::ExecuteSoftwareTrigger(char* szMsg/*= NULL*/)
{
    // 1. 校验相机是否有效(m_pGige不为空)
    if (Invalidate()) return ERR_CAMERA_INVALID;

    GError* error = NULL;
    ArvCamera* camera = (ArvCamera*)m_pGige;

    // 2. 核心调用:向相机发送软件触发指令
    arv_camera_software_trigger(camera, &error);

    COMMON_ERR nErrCode = COMMON_OK;
    if (error) {
        nErrCode = error->code;
        if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
        g_clear_error(&error);
    }

    return nErrCode;
}

之后相机会自己拍照,我们只需要读他拍照后反馈的流就可以

相比

COMMON_ERR CGige::PhotoImage(char* szMsg/*= NULL*/)中

cpp 复制代码
COMMON_ERR CGige::PhotoImage(char* szMsg/*= NULL*/)
{
    if (Invalidate()) return ERR_CAMERA_INVALID;
    COMMON_ERR nErrCode = COMMON_OK;

    GError* error = NULL;
    ArvCamera* camera =(ArvCamera*)m_pGige;

    int bits = GetBitCount();
    m_nBitCount = (bits >= 24) ? bits : 8;

    int width = arv_camera_get_integer(camera, "Width", NULL);
    int height = arv_camera_get_integer(camera, "Height", NULL);

    arv_camera_gv_select_stream_channel(camera, 0, NULL);
    arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_SINGLE_FRAME, NULL);

    guint payload = arv_camera_get_payload(camera, NULL);
    ArvStream* stream = arv_camera_create_stream(camera, NULL, NULL, &error);
    if (stream && payload > 0)
    {
        for (int i = 0; i < 1; i++)
            arv_stream_push_buffer(stream, arv_buffer_new(payload, NULL));

        InitRateSpeed();
        arv_camera_start_acquisition(camera, &error);
        if (!error)
        {
            ArvBuffer* buffer = arv_stream_pop_buffer(stream);
            if (buffer && arv_buffer_get_status(buffer) == ARV_BUFFER_STATUS_SUCCESS)
            {
                size_t buffer_size = 0;
                const uint8_t* data = reinterpret_cast<const uint8_t*>(arv_buffer_get_data(buffer, &buffer_size));
                int nWidth = arv_buffer_get_image_width(buffer);
                int nHeight = arv_buffer_get_image_height(buffer);
                SaveBuffer(data, buffer_size, nWidth, nHeight);
            }
            if (buffer) g_clear_object(&buffer);
        }
        arv_camera_stop_acquisition(camera, NULL);
    }
    if (error)
    {
        nErrCode = error->code; //ERR_CREATE_STREAM;
        if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
        g_clear_error(&error);
    }
    if (stream) g_clear_object(&stream);

    return nErrCode;
}

每次都会创建新的流

要节省大多时间

相关推荐
小驰行动派1 天前
Camera实战案例分析-三方相机,扫一扫预览卡顿
数码相机
废嘉在线抓狂.1 天前
Cinemachine 多大脑与多震源管理详解
数码相机
WX186163619091 天前
索尼相机视频变为RSV格式怎么封装修复转换为MP4视频
数码相机·音视频
格林威2 天前
工业相机图像高速存储(C++版):直接IO存储方法,附海康相机实战代码!
开发语言·c++·人工智能·数码相机·计算机视觉·视觉检测·工业相机
沐雲小哥2 天前
bevfomer算法嵌入的tricks
数码相机·算法
格林威2 天前
工业相机图像高速存储(C++版):直接IO存储方法,附Basler相机实战代码!
开发语言·c++·人工智能·数码相机·计算机视觉·视觉检测·工业相机
AI浩3 天前
使用模糊图像进行通用相机校准
人工智能·数码相机·计算机视觉
格林威3 天前
工业相机图像高速存储(C#版):直接IO(Direct I/O)绕过系统缓存,附堡盟相机实战代码!
开发语言·人工智能·数码相机·计算机视觉·缓存·c#·视觉检测
格林威3 天前
工业相机图像高速存储(C#版):直接IO(Direct I/O)方法,附Basler相机实战代码!
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机