Gige协议的二次开发

首先学习Aravis 库和CDevice,

Aravis 是实现相机通信的 底层工具,直接与硬件交互。
CDevice 是应用层的 抽象接口,通过封装 Aravis 或其他 SDK,提供统一的设备操作方式。
关系CDevice 的子类(如 CGige)使用 Aravis 实现具体功能,但对上层代码隐藏了底层细节。

namespace GigeAravis
{

class ARAVIS_API CDevice
{

public:
    CDevice();
    virtual ~CDevice();

    virtual void OnInitialize() = 0;

protected:
    ArvCamera* m_pGige;

    tagGigeInfo m_info;
    tagGigeParam m_param;

m_pGige 是 Aravis 库的核心相机对象,用于与相机硬件交互
tagGigeInfo 和 tagGigeParam 是自定义结构体:

tagGigeInfo 包含相机标识、IP 地址、基本尺寸等信息
tagGigeParam 包含相机的各种可配置参数和范围

下面是该三个变量的定义

struct tagGigeInfo包含设备索引、尺寸、ID、网络信息
{

    int index;
    int width;
    int height;

    tagGigeID    id;
    tagGigeStr    vendor;
    tagGigeStr    manufacturer;
    tagGigeStr    model;
    tagGigeStr    serial;
    tagGigeIP    ip;
    tagGigeIP    mask;
    tagGigeIP    gateway;
    tagGigeStr    mac;
    tagGigeStr    protocol;
    tagGigeStr    format;
};

tagGigeParam图像采集参数配置

struct tagGigeParam
{

    int curWidth;    
    int minWidth;
    int maxWidth;
    int incWidth;
    int curHeight;
    int minHeight;
    int maxHeight;
    int incHeight;
    int curFrameRate;
    int minFrameRate;
    int maxFrameRate;
    BYTE autoBlackLevel;
    int curBlackLevel;
    int minBlackLevel;
    int maxBlackLevel;
    BYTE autoGain;
    int curGain;
    int minGain;
    int maxGain;
    BYTE ExposureMode;
    BYTE autoExposureTime;
    int curExposureTime;
    int minExposureTime;
    int maxExposureTime;
    int nPixelFormatCount;
    tagGigeStr curPixelFormat;
    tagGigeStr PixelFormat[MAX_PF_COUNT];
};

下面依次看实现方式

扫描 → 选择设备 → 打开 → 获取参数 → 参数设置 → 采集

一.扫描

1.首先要遍历接口,遍历list

ARV_API unsigned int    arv_get_n_devices                (void);

2.根据索引(如 0、1、2)获取特定设备的详细信息(必须先调用 GetAllDevices() 获取设备列表/必须先通过 SetIndex() 或直接设置 m_info.id 指定目标设备)

GetDeviceInfo(unsigned int index)/GetDeviceInfo()(无参数版本)

3.获取相机的详细参数(如分辨率、帧率、像素格式等)(必须先调用 GetDeviceInfo() 且设备已成功打开(m_pGige 有效))


int GetBitCount();

int CDevice::GetBitCount()
{

    int bits = 8;
    GError* error = NULL;
    ArvCamera* camera = m_pGige;
  
    ArvPixelFormat pixel = arv_camera_get_pixel_format(camera, &error);
    if (!error) bits = pixel >> 16 & 0xff;

    g_clear_error(&error);

    return bits;
}

int CDevice::GetBitCount() { int bits = 8; // 默认位深度设为8位

GError* error = NULL;

ArvCamera* camera = m_pGige; // 获取Aravis相机对象

// 获取相机的像素格式

ArvPixelFormat pixel = arv_camera_get_pixel_format(camera, &error); // 若获取成功(error为NULL),解析位深度

if (!error) bits = pixel >> 16 & 0xff; g_clear_error(&error); // 清理错误信息 return bits;

}

该方法通过 Aravis 库获取相机像素格式,并从中解析出位深度信息。位深度是图像采集的关键参数,直接影响图像质量、数据量和后续处理方式。在工业视觉应用中,正确获取位深度有助于合理配置图像处理流程和存储资源。


// 设备连接管理
virtual void Close();                  // 关闭设备连接
COMMON_ERR Open(char* szMsg = NULL);   // 按预存ID打开设备
COMMON_ERR Open(char* szPID, char* szMsg);  // 按指定ID打开设备

// 信息获取
COMMON_ERR GetCameraInfo();           // 获取相机参数信息
COMMON_ERR GetDeviceInfo();           // 获取当前设备基础信息
COMMON_ERR GetDeviceInfo(unsigned int index);  // 按索引获取设备信息

// 参数设置(像素格式/区域/帧率)
COMMON_ERR SetPixelFormat(const char* szValue, char* szMsg = NULL);  // 设置像素格式
COMMON_ERR SetFrameRate(const int nFrameRate, char* szMsg = NULL);   // 设置帧率
COMMON_ERR SetRegion(const int nWidth, const int nHeight, char* szMsg = NULL);  // 设置采集区域

// 参数设置(增益/黑电平/曝光)
COMMON_ERR SetGain(const int nGain, char* szMsg = NULL);            // 设置增益
COMMON_ERR SetAutoGain(ArvAuto autoValue, char* szMsg = NULL);      // 设置自动增益模式
COMMON_ERR SetBlackLevel(const int nBlackLevel, char* szMsg = NULL); // 设置黑电平
COMMON_ERR SetAutoBlackLevel(ArvAuto autoValue, char* szMsg = NULL); // 设置自动黑电平模式
COMMON_ERR SetExposureTime(const int nExposureTime, char* szMsg = NULL); // 设置曝光时间
COMMON_ERR SetAutoExposureTime(ArvAuto autoValue, char* szMsg = NULL); // 设置自动曝光模式

// 内部辅助方法(保护成员)
void __GetBaseInfo();       // 获取相机基本属性
void __GetNetInfo();        // 获取网络配置
void __GetControlInfo();    // 获取控制参数

virtual void Close();

void CDevice::Close() {

if (Invalidate()) return; // 检查设备是否已无效(NULL)

g_object_unref(&m_pGige); // 减少Aravis相机对象的引用计数

g_clear_object(&m_pGige); // 确保对象被正确释放

m_pGige = NULL; // 将指针置为NULL,避免悬空指针 }

g_object_unref() 是 GLib 库中的函数,用于减少 GObject 对象的引用计数。
Aravis 库基于 GLib,其相机对象(ArvCamera)是 GObject 的子类。
当引用计数降为 0 时,对象会被自动销毁并释放资源。
g_clear_object() 是 GLib 提供的安全释放宏


二.选择设备

COMMON_ERR GetCameraInfo();
COMMON_ERR GetDeviceInfo();
COMMON_ERR GetDeviceInfo(unsigned int index);
 

COMMON_ERR GetDeviceInfo(unsigned int index);/COMMON_ERR GetDeviceInfo();

COMMON_ERR CDevice::GetDeviceInfo(unsigned int index)
{

    COMMON_ERR nErrCode = COMMON_OK;

    m_info.index = index;

    const char* szID = arv_get_device_id(index);
    if (szID) memcpy(m_info.id, szID, sizeof(tagGigeID));

    const char* szVendor = arv_get_device_vendor(index);
    if (szVendor) memcpy(m_info.vendor, szVendor, sizeof(tagGigeStr));
    const char* szModel = arv_get_device_model(index);
    if (szModel) memcpy(m_info.model, szModel, sizeof(tagGigeStr));
    const char* szSerial = arv_get_device_serial_nbr(index);
    if (szSerial) memcpy(m_info.serial, szSerial, sizeof(tagGigeStr));
    const char* szManufacturer = arv_get_device_manufacturer_info(index);
    if(szManufacturer) memcpy(m_info.manufacturer, szManufacturer, sizeof(tagGigeStr));

    const char* szIP = arv_get_device_address(index);
    if (szIP) memcpy(m_info.ip, szIP, sizeof(tagGigeIP));
    const char* szMac = arv_get_device_physical_id(index);
    if (szMac) memcpy(m_info.mac, szMac, sizeof(tagGigeStr));
    const char* pp = arv_get_device_protocol(index);
    if (pp) memcpy(m_info.protocol, pp, sizeof(tagGigeStr));

    return nErrCode;
}
//——————————
COMMON_ERR CDevice::GetDeviceInfo()
{

    COMMON_ERR nErrCode = COMMON_OK;
    if (Invalidate()) return ERR_CAMERA_INVALID;

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

    const char* szVendor = arv_camera_get_vendor_name(camera, &error);
    if (szVendor) memcpy(m_info.vendor, szVendor, sizeof(tagGigeStr));
    const char* szModel = arv_camera_get_model_name(camera, &error);
    if (szModel) memcpy(m_info.model, szModel, sizeof(tagGigeStr));
    const char* szSerial = arv_camera_get_device_serial_number(camera, &error);
    if (szSerial) memcpy(m_info.serial, szSerial, sizeof(tagGigeStr));
    if (!error && szVendor && szModel && szSerial)
        sprintf(m_info.id, “%s-%s-%s”, szVendor, szModel, szSerial);
    else nErrCode = error->code;

    g_error_free(error);

    return nErrCode;
}

以外部index收到的参数来返回相机在列表中的位置,对对应的index进行参数获取标定来设计m_info。


COMMON_ERR GetCameraInfo();

COMMON_ERR CDevice::GetCameraInfo()
{

    __GetBaseInfo();
    __GetNetInfo();
    __GetControlInfo();

    return 0;
}

__GetBaseInfo():获取相机基本属性
__GetNetInfo():获取相机网络配置
__GetControlInfo():获取相机控制参数

void CDevice::__GetBaseInfo()
{
    if (Invalidate()) return;  // 检查相机是否已打开

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

    // 获取像素格式
    const char* pp = arv_camera_get_string(camera, "PixelFormat", &error);
    if (!error) memcpy(m_info.format, pp, sizeof(tagGigeStr));
    
    // 获取图像宽度
    int nWidth = arv_camera_get_integer(camera, "Width", &error);
    if (!error && nWidth > 0) m_info.width = nWidth;
    
    // 获取图像高度
    int nHeight = arv_camera_get_integer(camera, "Height", &error);
    if (!error && nHeight > 0) m_info.height = nHeight;
    
    // 获取数据包延迟(GigE相机特有)
    gint64 delay = arv_camera_gv_get_packet_delay(camera, &error);

    g_error_free(error);  // 释放错误信息
}

核心功能

检查相机是否已打开(Invalidate() 检查 m_pGige 是否为 NULL
使用 Aravis API 获取相机的像素格式、宽度和高度
特别针对 GigE 相机获取数据包延迟参数
所有操作都包含错误检查,确保安全性

void CDevice::__GetNetInfo()
{
    if (Avalidate())  // 检查相机是否已打开
    {
        GError* error = NULL;
        ArvCamera* camera = m_pGige;

        GInetAddress* ip = NULL;
        GInetAddressMask* mask = NULL;
        GInetAddress* gateway = NULL;
        
        // 获取相机的持久IP配置
        arv_camera_gv_get_persistent_ip(camera, &ip, &mask, &gateway, &error);
        
        if (!error)
        {
            // 转换并存储IP地址
            char* szIP = g_inet_address_to_string(ip);
            sprintf(m_info.ip, "%s", szIP);
            
            // 转换并存储子网掩码
            char* szMask = g_inet_address_mask_to_string(mask);
            sprintf(m_info.mask, "%s", szMask);
            
            // 转换并存储网关(注意:这里可能有错误,重复使用了ip变量)
            char* szGate = g_inet_address_to_string(ip);
            sprintf(m_info.gateway, "%s", szGate);
        }
        
        g_error_free(error);  // 释放错误信息
    }
}

核心功能

检查相机是否已打开(Avalidate() 检查 m_pGige 是否非 NULL
使用 Aravis API 获取相机的 IP 地址、子网掩码和网关
使用 GLib 函数将网络地址转换为字符串格式
注意到一个潜在问题:网关地址获取时错误地使用了 ip 变量,应该使用 gateway 变量

void CDevice::__GetControlInfo()
{
    if (Invalidate()) return;  // 检查相机是否已打开

    GError* error = NULL;
    ArvCamera* camera = m_pGige;
    guint count = 0;
    double dmin = 0, dmax = 0;
    gint gmin = 0, gmax = 0;

    // 获取像素格式信息
    const char* pp = arv_camera_get_pixel_format_as_string(camera, &error);
    if (!error) memcpy(m_param.curPixelFormat, pp, sizeof(tagGigeStr));
    
    const char** ptr = arv_camera_dup_available_pixel_formats_as_strings(camera, &count, &error);
    if (!error) m_param.nPixelFormatCount = count;
    for (int i = 0; i < count && i < MAX_PF_COUNT; i++)
    {
        if (!error) memcpy(m_param.PixelFormat[i], ptr[i], sizeof(tagGigeStr));
    }

    // 获取帧率信息
    double rate = arv_camera_get_frame_rate(camera, &error);
    if (!error) m_param.curFrameRate = int(rate + 0.5);  // 四舍五入转换为整数
    arv_camera_get_frame_rate_bounds(camera, &dmin, &dmax, &error);
    if (!error) m_param.minFrameRate = int(dmin + 0.5);
    if (!error) m_param.maxFrameRate = int(dmax + 0.5);

    // 获取增益信息
    double dGain = arv_camera_get_gain(camera, &error);
    if (!error) m_param.curGain = int(10 * dGain + 0.5);  // 转换为整数(可能单位为0.1)
    arv_camera_get_gain_bounds(camera, &dmin, &dmax, &error);
    if (!error) m_param.minGain = int(10 * dmin + 0.5);
    if (!error) m_param.maxGain = int(10 * dmax + 0.5);
    
    // 检查增益自动功能是否可用
    gboolean bAvailable = arv_camera_is_gain_available(camera, &error);
    if (!error && bAvailable == 1)
    {
        gboolean bAutoable = arv_camera_is_gain_auto_available(camera, &error);
        if (!error && bAutoable == 1)
        {
            ArvAuto autoGain = arv_camera_get_gain_auto(camera, &error);
            if (!error) m_param.autoGain = autoGain;
        }
        else m_param.autoGain = ARV_AUTO_DISABLE;
    }
    else m_param.autoGain = ARV_FUNC_DISABLE;

    // 获取曝光时间信息(类似增益处理逻辑)
    double dtime = arv_camera_get_exposure_time(camera, &error);
    if (!error) m_param.curExposureTime = int(dtime + 0.5);
    arv_camera_get_exposure_time_bounds(camera, &dmin, &dmax, &error);
    if (!error) m_param.minExposureTime = int(dmin + 0.5);
    if (!error) m_param.maxExposureTime = int(dmax + 0.5);
    
    // 检查曝光自动功能是否可用(逻辑同增益)
    bAvailable = arv_camera_is_exposure_time_available(camera, &error);
    if (!error && bAvailable == 1)
    {
        gboolean bAutoable = arv_camera_is_exposure_auto_available(camera, &error);
        if (!error && bAutoable == 1)
        {
            ArvAuto autoExposureTime = arv_camera_get_exposure_time_auto(camera, &error);
            if (!error) m_param.autoExposureTime = autoExposureTime;
        }
        else m_param.autoExposureTime = ARV_AUTO_DISABLE;
    }
    else m_param.autoExposureTime = ARV_FUNC_DISABLE;

    // 获取图像区域信息(宽度和高度)
    gint width = 0, height = 0;
    arv_camera_get_region(camera, NULL, NULL, &width, &height, &error);
    if (!error) m_param.curWidth = width;
    if (!error) m_param.curHeight = height;
    
    // 获取宽度和高度的范围和增量
    arv_camera_get_width_bounds(camera, &gmin, &gmax, &error);
    if (!error) m_param.minWidth = gmin;
    if (!error) m_param.maxWidth = gmax;
    arv_camera_get_height_bounds(camera, &gmin, &gmax, &error);
    if (!error) m_param.minHeight = gmin;
    if (!error) m_param.maxHeight = gmax;
    width = arv_camera_get_width_increment(camera, &error);
    if (!error) m_param.incWidth = width;
    height = arv_camera_get_height_increment(camera, &error);
    if (!error) m_param.incHeight = height;

    // 获取黑电平信息
    double BlackLevel = arv_camera_get_black_level(camera, &error);
    if (!error) m_param.curBlackLevel = int(BlackLevel + 0.5);
    arv_camera_get_black_level_bounds(camera, &dmin, &dmax, &error);
    if (!error) m_param.minBlackLevel = int(dmin + 0.5);
    if (!error) m_param.maxBlackLevel = int(dmax + 0.5);
    
    // 检查黑电平自动功能是否可用(逻辑同增益)
    if (error) g_clear_error(&error); error = NULL;
    bAvailable = arv_camera_is_black_level_available(camera, &error);
    if (!error && bAvailable == 1)
    {
        gboolean bAutoable = arv_camera_is_black_level_auto_available(camera, &error);
        if (!error && bAutoable == 1)
        {
            ArvAuto autoBlackLevel = arv_camera_get_black_level_auto(camera, &error);
            if (!error) m_param.autoBlackLevel = autoBlackLevel;
        }
        else m_param.autoBlackLevel = ARV_AUTO_DISABLE;
    }
    else m_param.autoBlackLevel = ARV_FUNC_DISABLE;

    g_clear_error(&error);  // 释放错误信息
}

核心功能

像素格式管理

获取当前像素格式
获取所有可用像素格式列表

帧率控制

获取当前帧率
获取帧率范围

增益控制

获取当前增益值(转换为整数,可能单位为 0.1)
获取增益范围
检查并获取增益自动功能状态

曝光时间控制

获取当前曝光时间
获取曝光时间范围
检查并获取曝光自动功能状态

图像区域控制

获取当前图像宽度和高度
获取宽度和高度的范围和增量

黑电平控制

获取当前黑电平值
获取黑电平范围
检查并获取黑电平自动功能状态

实现特点

所有操作都包含完整的错误检查
数值转换时使用四舍五入(int(value + 0.5)
自动功能的处理采用统一的逻辑模式
资源管理完善,最后释放错误信息

图片[1] - Gige协议的二次开发 - 宋马
 


三. 打开

COMMON_ERR Open(char* szMsg = NULL);
COMMON_ERR Open(char* szPID, char* szMsg);

COMMON_ERR CDevice::Open(char* szMsg/*= NULL*/)
{
    char* szPID = m_info.id;  // 从类成员获取预存的设备ID
    return Open(szPID, szMsg);  // 调用带设备ID的重载版本
}
COMMON_ERR CDevice::Open(char* szPID, char* szMsg)
{
    // 核心打开逻辑(见下文解析)
}

COMMON_ERR CDevice::Open(char* szMsg/*= NULL*/)
{

    char* szPID = m_info.id;
    return Open(szPID, szMsg);
}
//——————————
COMMON_ERR CDevice::Open(char* szPID, char* szMsg)
{

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

    if (strlen(szPID) > 1)
    {

        if (Invalidate())
            camera = arv_camera_new(szPID, &error);
        if (camera)
        {

            m_pGige = camera;
            if (strlen(m_info.id) < 1)
                GetDeviceInfo();
            GetCameraInfo();
        }
        if (error)
        {

            nErrCode = error->code;
            if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) – 1);
        }
        else if(szMsg) sprintf(szMsg, “%s”, “open camera access”);
    }
    else
    {

        nErrCode = ERR_PID_INVLAID;
        if (szMsg) sprintf(szMsg, “%s”, “camera id /ip is invlaid”);
    }

    return nErrCode;
}

这一块没什么好说的,通过找到index来找相机,判定是否有效,有效就执行前面说的获取信息,初始化的一些操作 ,例如GetDeviceInfo();GetCam
eraInfo();


二次开发

void CSUCCES1Dlg::OnBnClickedBtnPhoto()
{

    // [2] 拍照
    lightSourceSwithOnOff(1, 0); // 开灯

    __photo();
    ShowGigeImage();
    ShowNetStatus();
    Sleep(100);
    lightSourceSwithOnOff(1,1); // 关灯
}

关于PhotoImage

COMMON_ERR CGige::PhotoImage(char* szMsg/*= NULL*/)
{
    // 检查相机是否有效,如果无效则返回错误
    if (Invalidate()) return ERR_CAMERA_INVALID;
    COMMON_ERR nErrCode = COMMON_OK;

    // 创建GError对象用于错误处理
    GError* error = NULL;
    // 获取相机对象指针
    ArvCamera* camera = 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);

    // 选择数据流通道0
    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);
    
    // 如果流创建成功且有效载荷大于0
    if (stream && payload > 0)
    {
        // 为数据流推送两个缓冲区用于接收图像数据
        for (int i = 0; i < 2; 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)
            {
                // 保存缓冲区中的图像数据
                SaveBuffer(buffer);
            }
            
            // 释放缓冲区资源
            if (buffer) g_clear_object(&buffer);
        }
        
        // 停止图像采集
        arv_camera_stop_acquisition(camera, NULL);
    }
    
    // 检查是否有错误发生
    if (error)
    {
        // 保存错误码
        nErrCode = error->code;
        
        // 如果提供了错误信息缓冲区,则复制错误信息
        if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
        
        // 清理错误对象
        g_clear_error(&error);
    }
    
    // 释放流资源
    if (stream) g_clear_object(&stream);

    // 返回错误码
    return nErrCode;
}

代码执行流程总结

初始化与参数检查

验证相机连接有效性
获取并设置图像位深度
获取图像尺寸参数

相机配置

选择数据流通道
设置为单帧采集模式

图像采集准备

创建数据流对象
分配数据缓冲区
初始化性能监控

图像采集

启动采集
从缓冲区获取图像数据
保存图像数据
停止采集

资源清理与错误处理

释放缓冲区和流资源
检查并处理错误
返回操作结果


关于ShowGigeImage();(显示图像)

void CSUCCES1Dlg::ShowGigeImage()
{

    CDC* pDC = GetDC();
    HBITMAP hBitmap = GetBitmap(pDC);
    if (!hBitmap)
    {

        hBitmap = (HBITMAP)LoadImage(NULL, _T(“res/demo.bmp”), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        if (!hBitmap) hBitmap = (HBITMAP)LoadImage(NULL, _T(“demo.bmp”), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    }
    if (hBitmap) ShowImage(hBitmap);
    if (hBitmap) DeleteObject(hBitmap);
}

HBITMAP CSUCCES1Dlg::GetBitmap(CDC* pDC)
{
    // 检查输入参数有效性
    if (!pDC) return NULL;
    // 准备位图信息结构,失败则返回NULL
    if (!MakeBitMapInfo()) return NULL;

    HBITMAP hBitmap = NULL;
    // 从相机对象获取原始图像数据指针
    LPBYTE lpData = m_curGige->GetMatrix();
    // 获取图像宽度和高度
    int nWidth = m_curGige->GetBmpWidth();
    int nHeight = m_curGige->GetBmpHeight();
    
    // 计算按4字节对齐后的行宽度(Windows位图要求每行字节数必须是4的倍数)
    int nSaveWidth = 4 * ((nWidth + 3) / 4);
    
    // 如果原始宽度已经是4的倍数,直接创建位图
    if (nSaveWidth == nWidth)
    {
        hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(),
            (BITMAPINFOHEADER*)m_pBitInfo, CBM_INIT, lpData, m_pBitInfo, DIB_RGB_COLORS);
    }
    else
    {
        // 否则需要创建临时缓冲区进行行对齐处理
        LPBYTE memData = new BYTE[nSaveWidth * nHeight];
        memset(memData, 0, nSaveWidth * nHeight);
        
        LPBYTE pSrc = lpData;     // 源数据指针
        LPBYTE pp = memData;      // 目标数据指针
        
        // 逐行复制数据,并进行必要的填充
        for (int i = 0; i < nHeight; i++)
        {
            memcpy(pp, pSrc, nWidth);  // 复制有效数据
            pp += nSaveWidth;          // 目标指针移动到下一行
            pSrc += nWidth;            // 源指针移动到下一行
        }
        
        // 使用对齐后的数据创建位图
        hBitmap = ::CreateDIBitmap(pDC->GetSafeHdc(),
            (BITMAPINFOHEADER*)m_pBitInfo, CBM_INIT, memData, m_pBitInfo, DIB_RGB_COLORS);
        
        // 释放临时缓冲区
        delete[] memData; memData = NULL;
    }
    
    return hBitmap;
}


void CSUCCES1Dlg::ShowNetStatus()
{
    // 检查相机对象是否有效
    if (m_curGige)
    {
        // 从相机对象获取各项状态参数
        int useTick = m_curGige->GetUseTick();         // 获取图像处理耗时(毫秒)
        double speed = m_curGige->GetNetSpeed();       // 获取网络传输速度(Mbps)
        double frames = m_curGige->GetNetFrameRate();  // 获取帧率(帧/秒)
        int width = m_curGige->GetBmpWidth();          // 获取图像宽度(像素)
        int height = m_curGige->GetBmpHeight();        // 获取图像高度(像素)
        CString pip = GetFromUTF8(m_curGige->GetIP()); // 获取相机IP地址并转换为UTF-8编码
        
        CString strTemp = _T("");
        
        // 格式化状态信息字符串
        strTemp.Format(_T("remote:%s recv rate=%6.2fframe/s  speed=%9.2fmbps image[ %d * %d ] use:%dms"),
            pip.GetBuffer(), frames, speed, width, height, useTick);
        
        // 将格式化后的字符串显示在ID为IDC_STREAM_DEMO的控件上
        SetDlgItemText(IDC_STREAM_DEMO, strTemp);
    }
}

关于视频流

void CSUCCES1Dlg::OnBnClickedBtnVideo()
{
    // 初始化错误码为成功状态
    COMMON_ERR nErrCode = COMMON_OK;

    // 获取按钮当前显示的文本
    CString strTemp = _T("");
    GetDlgItemText(IDC_BTN_VIDEO, strTemp);
    
    // 根据按钮文本判断当前应该执行的操作
    if (strTemp.CompareNoCase(_T("video")) == 0)
        // 如果按钮文本是"video",则启动视频流
        nErrCode = __StartVideo();
    else
        // 否则停止视频流
        nErrCode = __StopVideo();

    // 更新界面控件状态
    SetDlgItemState();
}

和拍照差不多

COMMON_ERR CSUCCES1Dlg::__StartVideo()
{
    // 初始化错误码为成功状态
    COMMON_ERR nErrCode = COMMON_OK;
    // 定义错误消息缓冲区并初始化为0
    tagErrMsg szMsg; memset(szMsg, 0, sizeof(tagErrMsg));

    // 如果相机对象存在但无效,则尝试打开相机
    if (m_curGige && m_curGige->Invalidate()) m_curGige->Open();
    // 检查相机是否有效,无效则设置错误码
    if (!m_curGige || m_curGige->Invalidate())
        nErrCode = ERR_CAMERA_INVALID;

    // 如果前面的操作成功,则打开视频流
    if (COMMON_SUCCEEDED(nErrCode))
    {
        nErrCode = m_curGige->OpenStream(szMsg);
    }
    
    // 显示错误消息(如果有错误发生)
    __ShowMessage(nErrCode, szMsg);

    return nErrCode;
}

COMMON_ERR CGige::OpenStream(char* szMsg/*= NULL*/)
{
    // 检查相机状态,如果无效则尝试打开
    if (Invalidate()) Open();
    if (Invalidate()) return ERR_CAMERA_INVALID;

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

    // 配置相机流通道和采集模式
    arv_camera_gv_select_stream_channel(camera, 0, NULL);
    arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_CONTINUOUS, NULL);
    
    // 创建数据流对象并设置回调函数
    HeTrace("arv_camera_create_stream");
    m_stream = arv_camera_create_stream(camera, stream_callback, this, &error);
    
    // 配置数据流缓冲区
    if (!error && ARV_IS_STREAM(m_stream))
    {
        // 清除可能存在的旧错误
        if (error) g_error_free(error); error = NULL;
        
        // 获取图像数据有效载荷大小
        size_t payload = arv_camera_get_payload(camera, &error);
        
        // 创建并推送10个缓冲区到数据流
        if (!error && payload > 0)
        {
            for (int i = 0; i < 10; i++)
                arv_stream_push_buffer(m_stream, arv_buffer_new(payload, NULL));
        }
        
        // 初始化速率和速度测量
        InitRateSpeed();
        HeTrace("arv_camera_start_acquisition");

        // 设置采集标志并启动连续采集
        m_bKill = false;
        if (!error) arv_camera_start_acquisition(camera, &error);
    }
    
    // 错误处理
    if (error)
    {
        nErrCode = error->code;
        if (szMsg) memcpy(szMsg, error->message, sizeof(tagErrMsg) - 1);
        g_clear_error(&error);
        
        // 释放资源
        g_clear_object(&m_stream);
        g_object_unref(&m_stream);
        m_stream = NULL;
        HeTrace("arv_camera_create_stream_error");
    }
    else if(ARV_IS_STREAM(m_stream))
    {
        HeTrace("arv_camera_start_acquisition_ok");
    }

    return nErrCode;
}
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容