Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取每张图像的微秒时间和FrameID(C++)

简介: Baumer工业相机堡盟工业相机如何通过BGAPI SDK获取每张图像的微秒时间和FrameID(C++)

Baumer工业相机

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


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


Baumer工业相机中在一些需要同步的工业相机应用中,时间戳的准确性至关重要。BGAPI SDK可以提供一个精确的时钟源,以同步多个相机机并确保准确的时间戳。。


Baumer工业相机精确获取图像时间和FrameID技术背景

若要获取工业相机SDK获取图像的微秒时间和FrameID,通常需要一个支持硬件触发的相机和一个允许你访问时间戳和FrameID信息的软件API。


1. 硬件触发: 许多工业相机支持硬件触发,这允许你将相机的采集与外部触发信号同步。这可以帮助确保在你需要的确切时刻捕获图像,并将延迟或抖动降到最低。


2. 时间标记: 当图像被采集时,相机的硬件或软件通常会记录一个时间戳,表明曝光开始或结束的时间。这个时间戳可以用来计算捕获图像的精确时间。


3.FrameID:随着时间戳的出现,相机也可能为每一帧被捕获的图像分配一个独特的标识符。这可以帮助你跟踪哪些图像是按顺序拍摄的,特别是在你以高帧率获取图像时。


4. SDK API: 为了访问工业相机的时间戳和帧ID信息,你通常会使用相机制造商提供的SDK API。此API可能允许你设置摄像机的硬件触发,指定时间戳和帧ID的格式,并检索数据


一、工业相机FrameID是什么?

工业相机的帧标识(Frame Identifier)是分配给相机拍摄的每一帧或图像的唯一标识。


它用于跟踪和识别每一帧,以便进行分析、处理或储存。帧标识通常包括帧号、采集日期和时间、相机识别号和其他相关元数据等信息。


二、使用BGAPI SDK获取图像微秒时间和FrameID

1.获取SDK图像微秒级时间

在回调函数BufferHandler里使用并获取图像微秒级时间,代码如下(示例):

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);

2.获取SDK图像FrameID

代码如下(示例):

pDlg->FrameID= pBufferFilled->GetFrameID(); //获取当前图像FrameID
//保存图像名称
int FrameidNum = pDlg->FrameID;
strpath2.Format(_T("%s%d%s"),strpath,FrameidNum,_T(".jpg"));
pDlg->FullFrameSaveImageName.Add(strpath2);

3.BGAPI SDK在图像回调中获取微秒级和FrameID信息保存图像

代码如下(示例):

SystemList 
Open a System 
Get the InterfaceList and fill it Open an Interface 
Get the DeviceList and fill it 
Open a Device
//图像回调函数
//==================
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 //保存图像功能
    CString  strpath2;
    if(pDlg->m_bSaveImage)
    {
    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+"-";
    //保存图像名称
    int FrameidNum = pDlg->FrameID;
    strpath2.Format(_T("%s%d%s"),strpath,FrameidNum,_T(".jpg"));
    pDlg->FullFrameSaveImageName.Add(strpath2);
    }
    #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);
    if(pDlg->m_bSaveImage)
    {    
    //复制图像到新的指针空间
    Gdiplus::Bitmap* targetBitmap = pDlg->m_pBitmap->Clone(0, 0, pDlg->m_pBitmap->GetWidth(), pDlg->m_pBitmap->GetHeight(), pDlg->m_pBitmap->GetPixelFormat());
    //将新指针图像保存到图像数组
    pDlg->bitmapArray[ImageSaveCount] = targetBitmap;
    测试保存
    //CLSID pngClsid;
    //GetEncoderClsid(L"image/png", &pngClsid); // 获取 PNG 编码器的 CLSID    
    //targetBitmap->Save(strpath2, &pngClsid, NULL); // 保存为 PNG 格式的图像
    ImageSaveCount++;
    int TestNum = pDlg->FullFrameSaveImageName.GetCount();
    int timestamp1 =  pBufferFilled->GetTimestamp();     
    CTime time0 = CTime(timestamp1); // 将时间戳转换为CTime对象
    if(TestNum==500)
    {
      currentTimeEnd  = CTime::GetCurrentTime();
      // 计算时间差
      CTimeSpan timeDiff = currentTimeEnd - currentTimeStart;
      double seconds = timeDiff.GetTotalSeconds()*1000; // 获取时间间隔的总秒数
      pDlg->m_bSaveImage = false;
      //控制内存保存图像指令
      pDlg->ControlSaveImage = true;
      //pDlg->ReleaseImageFromMemory();
    }
    }
    #pragma endregion 
    #pragma region //将图像显示在PictureControl控件上,在高速存储时将图像显示界面将会导致Buffer出现覆盖现象,从而会出现FrameID不连续
    /*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());  
  } 
}

工业相机图像使用微秒级时间和FrameID保存效果

11.png


工业相机图像使用微秒级时间和FrameID的用处

使用微秒计时和FrameID的工业相机图像可用于各种目的,如:


1. 测量高速运动或快速移动的物体 - 微秒计时和FrameID可以精确测量运动的持续时间和速度。


2. 制造过程中的质量控制和检查 - 工业相机拍摄的高分辨率图像可用于缺陷检测、表面检查和产品验证。


3. 科学和工程领域的研究和开发 - 具有微秒级计时和FrameID的工业相机可以高速捕捉数据,为科学研究和工程实验提供精确的测量。


4. 交通监测和监控 - 工业相机可以高速和准确地捕捉移动的车辆、行人和其他物体的图像,使其适合用于交通监测和监控。


5. 体育分析和性能测量 - 工业相机上的微秒计时和FrameID可用于实时捕捉和分析运动员或体育设备的运动,为训练和优化提供宝贵的见解。


总的来说,带有微秒计时和FrameID的工业相机是精密测量、质量控制、科学研究以及在各种行业和应用中进行实时监测和分析的宝贵工具。


工业相机图像使用微秒时间和FrameID的行业应用

在工业相机图像中使用微秒时间和FrameID可以有各种行业应用,包括:


1. 制造业: 工业相机图像可用于监测和分析生产线,使制造商能够提高效率,减少缺陷,并提高整体生产力。微秒时间和FrameID的使用可以帮助跟踪特定组件或装配的进展,并确定潜在的问题或瓶颈。


2. 质量控制:高速工业相机能够以非常高的帧率捕捉图像,从而能够精确检查产品和部件的缺陷或异常。微秒级时间和FrameID的使用可以帮助确保准确和一致的测量和检查结果。


3. 医学成像: 高速工业相机可用于医疗成像应用,如超声、内窥镜和显微镜。高帧率和精确的图像时间可以使临床医生捕捉到动态过程的详细图像,并确定组织或细胞行为的微妙变化。


4. 航空航天和国防:工业相机图像可用于监测和分析航空航天和国防应用中的复杂系统,如飞机发动机、导弹制导系统和卫星部件。微秒级时间和FrameID的使用可以帮助实时识别潜在的故障或性能问题。


总的来说,在工业相机图像中使用微秒级时间和FrameID可以在各行业中实现广泛的应用,为分析和决策提供精确和可靠的数据。

目录
相关文章
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
250 0
|
数据采集 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Force IP强制修改网口IP功能(C++)
145 0
|
算法框架/工具 C++ Python
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角 或 旋转矩阵与欧拉角(Euler Angles)之间的相互转换,以及python和C++代码实现
1093 0
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C++)
175 0
|
8月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
4月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
96 0
|
4月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
173 0
|
6月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
186 12
|
7月前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
132 16
|
8月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)

热门文章

最新文章