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工业相机的高速同步采集功能的行业应用

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


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


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


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


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


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

目录
相关文章
|
3月前
|
数据采集 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
29 0
|
3月前
|
编解码 监控 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能(C++)
49 0
|
3月前
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
33 0
|
1月前
|
存储 缓存 调度
C++医院医学影像PACS系统源码 影像采集 DICOM影像
支持对财务及工作量信息进行统计; 支持对任意的检查类别,检查设备按照不同的检查项目(包括送检医生,送检;科室,检查类别,报告医生工作量等)进行任意时间段的统计; 可以按照检查类型,检查设备,检查项目,统计范围和日期范围等进行组合统计。
15 1
|
5天前
|
存储 编译器 C语言
c++的学习之路:5、类和对象(1)
c++的学习之路:5、类和对象(1)
19 0
|
5天前
|
C++
c++的学习之路:7、类和对象(3)
c++的学习之路:7、类和对象(3)
19 0
|
4天前
|
设计模式 Java C++
【C++高阶(八)】单例模式&特殊类的设计
【C++高阶(八)】单例模式&特殊类的设计
|
4天前
|
编译器 C++
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象
【C++基础(八)】类和对象(下)--初始化列表,友元,匿名对象
|
8天前
|
存储 安全 C语言
【C++】string类
【C++】string类
|
存储 编译器 Linux
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”