Baumer工业相机堡盟工业相机如何通过BGAPISDK的软触发实现两相机同步采集(C++)

简介: Baumer工业相机堡盟工业相机如何通过BGAPISDK的软触发实现两相机同步采集(C++)

Baumer工业相机

Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。


Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩展性等特点。

Baumer工业相机由于其性能和质量的优越和稳定,常用于高速同步采集领域。


Baumer工业相机的高速同步采集的技术背景

多个工业相机的高速同步采集是一个技术过程,涉及到从多个相机高速采集图像,并将其整合到一个同步系统中。这个过程需要先进的硬件和软件技术,以及对摄像机同步、数据传输和图像处理的理解。


为了实现多个工业相机的高速同步采集,有必要使用支持硬件触发并可通过先进软件进行同步的相机。例如,可以使用主时钟信号或脉冲发生器来触发摄像机,以确保所有摄像机在完全相同的时刻捕获图像。


此外,还需要一个高速数据传输网络,以确保每个摄像机捕获的大量图像数据能够快速传输到中央处理单元(CPU)进行进一步分析。这通常涉及使用高速通信协议,如千兆以太网或CoaXPress。


在图像处理方面,需要专门的软件来处理由多个摄像机产生的大量数据。这可能包括实时视频处理算法、运动检测、模式识别或其他先进技术,旨在从捕获的图像中提取有用信息。


总的来说,实现多个工业相机的高速同步采集是一项复杂的技术任务,需要多个学科的专业知识,包括硬件设计、软件开发和图像处理。


本文这里只简单介绍Baumer的两个工业相机在设置相同参数时,使用软触发进行的同步采集


Baumer工业相机通过BGAPI SDK在回调函数里同步保存图像

下面介绍在C++里两个Baumer工业相机在软触发的情况下进行同步采集


工业相机在回调函数BufferEvent保存

在回调函数里保存图像,使用毫秒级的时间戳去存储图像的名称,C++调用代码如下所示:

//图像回调函数
//==================
void BGAPI2CALL BufferHandler( void * callBackOwner, Buffer * pBufferFilled )
{
  CGigeDemoDlg* pDlg = (CGigeDemoDlg*)callBackOwner;
  unsigned char* imagebuffer = NULL;
  USES_CONVERSION;
  try
  {
  if(pBufferFilled == NULL)
  {
  }
  else if(pBufferFilled->GetIsIncomplete() == true)
  {
    // queue buffer again
    pBufferFilled->QueueBuffer();
  }
  else
  {
    pDlg->FrameID= pBufferFilled->GetFrameID();                                                 //获取当前图像FrameID显示帧率
    int width = 0, height = 0;
    width = (int)pBufferFilled->GetWidth();height = (int)pBufferFilled->GetHeight();    //获取当前图像像素长宽
    CString PixelFormat1 = (CString)pBufferFilled->GetPixelFormat();        //获取当前图像像素格式
    imagebuffer = (BYTE*)((bo_int64)pBufferFilled->GetMemPtr()+pBufferFilled->GetImageOffset());//获取当前图像数据
    #pragma region //保存图像功能
    if(pDlg->m_bSaveImage &&!pDlg->m_strDirectory.IsEmpty())
    {   
    CTime time = CTime::GetCurrentTime(); 
    CString strtime1;
    strtime1.Format(_T("\\%4d%2d%2d%2d%2d%2d"),time.GetYear(),time.GetMonth(),time.GetDay(),time.GetHour(),time.GetMinute(),time.GetSecond());
    SYSTEMTIME st;
    GetSystemTime(&st);  // 获取系统时间,精确到毫秒
    int msecond = st.wMilliseconds;  // 获取毫秒数
    CString strtime;
    strtime.Format(_T("\\%s-%d"),strtime1,msecond);
    CString  strpath = pDlg->m_strDirectory+strtime+"-";
    pDlg->SaveImageMono(strpath, imagebuffer,width,height);
    pDlg->m_bSaveImage = false;
    }
    #pragma endregion 
    Gdiplus::Rect rc = Gdiplus::Rect(0,0,width,height);
    #pragma region 黑白相机代码:像素格式为mono时转Bitmap的代码,彩色相机此处代码不同
    if(pDlg->m_pBitmap == NULL)
    {
    pDlg->m_pBitmap = new Gdiplus::Bitmap(width,height,PixelFormat8bppIndexed);
    }
    Gdiplus::BitmapData lockedbits;
    Gdiplus::ColorPalette * pal = (Gdiplus::ColorPalette*)new BYTE[sizeof(Gdiplus::ColorPalette)+255*sizeof(Gdiplus::ARGB)];
    pal->Count=256;
    for(UINT i=0;i<256;i++)
    {
    UINT color=i*65536+i*256+i;
    color= color|0xFF000000;
    pal->Entries[i]=color;
    }
    pDlg->m_pBitmap->SetPalette(pal);
    Gdiplus::Status ret = pDlg->m_pBitmap->LockBits(&rc,Gdiplus::ImageLockModeWrite,PixelFormat8bppIndexed,&lockedbits);
    BYTE* pixels = (BYTE*)lockedbits.Scan0;
    BYTE* src = (BYTE*)imagebuffer;
    for (int row = 0; row < height; ++row) 
    {
    CopyMemory(pixels, src, lockedbits.Stride);
    pixels += width;
    src += width;
    }
    pDlg->m_pBitmap->UnlockBits(&lockedbits);
    #pragma endregion 
    #pragma region //将图像显示在PictureControl控件上
    HDC hDC = ::GetDC(pDlg->m_stcPicture.m_hWnd);
    Gdiplus::Graphics GdiplusDC(hDC);
    CRect rcControl;
    pDlg->m_stcPicture.GetWindowRect(&rcControl);
    Gdiplus::Rect rtImage(0,0,rcControl.Width(),rcControl.Height());
    GdiplusDC.DrawImage(pDlg->m_pBitmap,rtImage,0,0,width,height, Gdiplus::UnitPixel);
    delete []pal;
    ::ReleaseDC(pDlg->m_stcPicture.m_hWnd,hDC);
    delete pDlg->m_pBitmap ;
    pDlg->m_pBitmap =NULL;
    #pragma endregion 
    // queue buffer again
    pBufferFilled->QueueBuffer();
  }
  }
  catch (BGAPI2::Exceptions::IException& ex)
  {
  CString str;
  str.Format(_T("ExceptionType:%s! ErrorDescription:%s in function:%s"),ex.GetType(),ex.GetErrorDescription(),ex.GetFunctionName());  
  } 
}

SaveImageMono保存图像内存作为图像的函数

bool CGigeDemoDlg::SaveImageMono(CString str,BYTE* bdata,int width,int height)
{  
  if (str.IsEmpty()) return false;
  HANDLE hFile = CreateFile(str,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
  //DWORD dwError = GetLastError();
  if (!hFile || hFile == INVALID_HANDLE_VALUE) 
  return false;
  // 
  BITMAPFILEHEADER  FileHeader;
  BITMAPINFOHEADER  InfoHeader;
  RGBQUAD rgbQuad[256];
  DWORD dwImageSize    = width*height;
  FileHeader.bfType    = 0x4D42; // "BM"
  FileHeader.bfSize    = sizeof(FileHeader) + sizeof(InfoHeader) + dwImageSize;
  FileHeader.bfReserved1    = FileHeader.bfReserved2 = 0;
  FileHeader.bfOffBits    = sizeof(FileHeader) + sizeof(InfoHeader);
  ZeroMemory(&InfoHeader, sizeof(InfoHeader));
  InfoHeader.biWidth    = width;
  InfoHeader.biHeight    = -height;
  InfoHeader.biSizeImage    = dwImageSize;
  InfoHeader.biBitCount   = 8;
  InfoHeader.biCompression  = BI_RGB;
  InfoHeader.biPlanes    = 1;
  InfoHeader.biSize    = sizeof(BITMAPINFOHEADER);
  InfoHeader.biXPelsPerMeter  = 0xEC4;
  InfoHeader.biYPelsPerMeter  = 0xEC4;
  for ( int i=0;i<256; i++ )
  {
  rgbQuad[i].rgbBlue = (BYTE)i;
  rgbQuad[i].rgbGreen = (BYTE)i;
  rgbQuad[i].rgbRed = (BYTE)i;
  rgbQuad[i].rgbReserved = 0;
  }
  DWORD Written;
  WriteFile(hFile, (LPVOID)&FileHeader,sizeof(BITMAPFILEHEADER),&Written, NULL);
  WriteFile(hFile, (LPVOID)&InfoHeader,sizeof(BITMAPINFOHEADER),&Written, NULL);
  WriteFile(hFile, (LPVOID)rgbQuad,256*sizeof(RGBQUAD),&Written,NULL);
  BYTE* src = bdata;
  //int stride = m_Width*4;
  //DWORD bytes = m_Width * 4;
  //for (unsigned long y = 0; y < NHEIGHT; y++) {
  WriteFile(hFile, (LPVOID)src,dwImageSize,&Written,NULL);
  //}
  CloseHandle(hFile);
  return true;
}

工业相机使用软触发进行同步采集

使用软件触发进行同步采集,C++调用代码如下所示:

m_pDevice->GetRemoteNode("TriggerMode")->SetString("Off"); //关闭触发模式,进入自由采集图片流模式
  m_pDevice->GetRemoteNode("AcquisitionStart")->Execute();
void CGigeDemoDlg::TriggerCameras()
{
  if (lisDev.Count ==2)
    {
        fullsavebmp1 = true; fullsavebmp2 = true;
        if ((lisDev[0]->GetRemoteNode("TriggerMode")->GetString() == "Software"
            || lisDev[0]->GetRemoteNode["TriggerSource"]->GetString() == "SoftwareTrigger")
            && (lisDev[1]->GetRemoteNode["TriggerSource"]->GetString() == "Software"
            || lisDev[1]->GetRemoteNode["TriggerSource"]->GetString() == "SoftwareTrigger"))
        {
            int count1 = 0;
            BGAPI2::Device * dev1 = lisDev[0];
            BGAPI2::Device * dev2 = lisDev[1];
            #pragma region 线程自动触发相机
    AfxBeginThread(AutoTriggerSoftwareThread1(dev1) , (void*)this); 
    AfxBeginThread(AutoTriggerSoftwareThread2(dev2) , (void*)this);   
    #pragma endregion  
        }
    }
    if (lisDev.Count == 1)
    {
        if ((lisDev[0]->GetRemoteNode("TriggerMode")->GetString() == "Software"
            || lisDev[0]->GetRemoteNode["TriggerSource"]->GetString() == "SoftwareTrigger"))
        {
              dev->GetRemoteNode("TriggerSoftware")->Execute();
        }
    }
}

工业相机的软件触发命令线程函数

工业相机软件触发命令,C++调用代码如下所示:

UINT CGigeDemoDlg::AutoTriggerSoftwareRun1(LPVOID pParam)
{
  CGigeDemoDlg *dlg = (CGigeDemoDlg *)pParam;
  dlg->TriggerSoftwareRun1();
  return 0;
}
CString strtimeStart; 
void CGigeDemoDlg::TriggerSoftwareRun1()
{
  try
  {  
  bool m_bRun0 = true;
  while (m_bRun0)
  {
    dev->GetRemoteNode("TriggerSoftware")->Execute();    
    m_bRun0  = false;      
  }  
  }
  catch (int e)
  {
  MessageBox(_T("Camera FullFrameSaveimage Error"));
  }
}
UINT CGigeDemoDlg::AutoTriggerSoftwareRun2(LPVOID pParam)
{
  CGigeDemoDlg *dlg = (CGigeDemoDlg *)pParam;
  dlg->TriggerSoftwareRun2();
  return 0;
}
CString strtimeStart; 
void CGigeDemoDlg::TriggerSoftwareRun2()
{
  try
  {  
  bool m_bRun0 = true;
  while (m_bRun0)
  {
    dev->GetRemoteNode("TriggerSoftware")->Execute();    
    m_bRun0  = false;      
  }  
  }
  catch (int e)
  {
  MessageBox(_T("Camera FullFrameSaveimage Error"));
  }
}

Baumer工业相机的软件触发同步采集测试图

8.png


使用软件触发同步采集后保存的图像名称如下所示:


7.png

Baumer工业相机的高速同步采集功能的优势

高速同步采集: 堡盟工业相机具有高速同步采集功能,可以同时采集多个图像。这使它们成为时间至关重要的应用的理想选择,例如在机器视觉、机器人和自动化领域。


提高精度和准确度: 堡盟工业相机的高速同步采集使图像数据的准确性和精确性得到提高。这在需要进行高精确度测量的应用中尤为重要。


提高生产力: 堡盟工业相机具有一次采集多幅图像的能力,有助于提高制造业和其他工业流程的生产率。它们可以帮助实时识别错误和低效率,以便立即采取纠正措施。


定制化: 堡盟工业相机可进行定制,以满足不同应用的具体需求。它们提供各种选项,包括分辨率、帧率和动态范围。


耐用性: 堡盟工业相机的设计能够承受恶劣的环境,并且经久耐用。它们能抵抗冲击和振动,并能在极端温度下工作,使它们适合在工业和制造业环境中使用。


Baumer工业相机的高速同步采集功能的行业应用

汽车行业: 在汽车行业,高速相机被用来捕捉移动物体的图像,如车辆、行人和骑自行车的人。这些数据被用于各种应用,包括避免碰撞系统、高级驾驶辅助系统和自动停车系统。


制造行业: 在制造业中,高速相机被用来监测装配线和流程,检查缺陷,并确保质量控制。它们还被用来捕捉快速移动的机器和设备的图像,用于维护和排除故障。


制药业: 在制药业,高速相机被用来捕捉药物开发和测试过程的图像,包括分析液体、气溶胶和悬浮液中颗粒的行为。


体育行业: 在体育行业,高速相机被用来捕捉运动员运动中的图像,使教练和训练员能够分析技术并作出调整,以达到最佳表现。


航空航天工业: 在航天工业中,高速相机被用来捕捉飞机在测试和开发过程中的图像,包括分析风洞测试和高速飞行。


这些只是多工业相机的高速同步采集功能的几个行业应用。该技术在各行业还有很多应用。

目录
相关文章
|
7月前
|
数据采集 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
66 0
|
4月前
|
算法框架/工具 C++ Python
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
356 0
|
7月前
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
85 0
|
1月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
51 2
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
104 5
|
1月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
92 4
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
111 4
|
2月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
32 4
|
2月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
32 4
|
2月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
29 1