Baumer工业相机堡盟工业相机如何通过BGAPI SDK将相机图像数据用二进制的方式保存到本地(C++)

简介: Baumer工业相机堡盟工业相机如何通过BGAPI SDK将相机图像数据用二进制的方式保存到本地(C++)

Baumer工业相机

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


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

Baumer工业相机中原始图像可以通过BGAPI SDK和其它图像处理库进行联合保存成各种格式的图像,比如和Halcon联合、比如和OpenCV联合、比如和GDI+图像库联合等等,若在高速采图领域,任何的图像转换过程可能都会造成效率的降低,因此直接保存原始数据的图像是最为快速的。


Baumer工业相机将图像保存为二进制图像的技术背景

工业相机通常通过一个传感器实时捕捉高分辨率的图像,该传感器将光转换为电信号。这些信号然后由相机的图像处理硬件和软件转换成数字二进制图像。二进制图像由黑色和白色像素组成,每个像素由一个比特表示,要么是0,要么是1,0代表黑色像素,1代表白色像素。


工业相机经常使用二进制图像,因为它们在某些应用中更有效,更容易处理。二进制图像比彩色图像或灰度图像占用的存储空间更少。这使它们成为需要存储或传输大量图像的应用的理想选择,例如在制造业质量控制或安全监控中。二进制图像也更容易使用算法和软件进行分析和处理,这对检测缺陷、跟踪物体和识别图像数据中的模式很有帮助。


总的来说,工业相机将图像保存为二进制图像的技术背景是基于工业和制造业应用中对高速、有效处理大量图像数据的需要。


有关于Baumer万兆网工业相机堡盟相机VLXT-28M.I如何做全帧率图像存储到本地的介绍,之前已经有相关的技术博客可以参考:


Baumer万兆网工业相机堡盟相机VLXT-28M.I如何做全帧率图像存储到本地


这里主要描述如何在C++的平台下实现通过BGAPI SDK实现二进制保存图像功能的核心代码


代码分析

本文介绍使用BGAPI SDK对Baumer的工业相机进行开发时,使用通过BGAPI SDK获取相机的原始图像数据Byte*,然后直接将图像数据转为二进制图像保存到本地。

一般讲Byte图像数据转换为二进制进行保存可以分为以下几步:

1、将Byte图像加载到内存中,即创建一个字节数组来保存数据。

2、确定图像的尺寸(宽度和高度),并计算出像素总数。

3、分配第二个相同大小的字节数组来保存二进制数据。

4、循环浏览图像中的每个像素,将其颜色值从字节转换成二进制(0或1)

5、将二进制数据阵列存储在一个文件或数据库中,用于本地存储。


如下为核心代码实现步骤:


第一步:先转换Byte*图像为二进制图像

C++环境下将Byte*图像保存为二进制图像如下所示:

unsigned char* imageData = // Byte*图像数据
int imageSize = // 图像数据的大小
std::vector<unsigned char> binaryData(imageSize * 8);
for (int i = 0; i < imageSize; i++) {
    for (int j = 0; j < 8; j++) {
        binaryData[i * 8 + j] = (imageData[i] >> j) & 1;
    }
}

第二步:在回调函数里进行Buffer图像转换为二进制图像进行保存

下面为在在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 strtime;
    strtime.Format(_T("\\%4d%2d%2d%2d%2d%2d"),time.GetYear(),time.GetMonth(),time.GetDay(),time.GetHour(),time.GetMinute(),time.GetSecond());
    CString  strpath = pDlg->m_strDirectory+strtime+".jpg";
    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 
    // 将Bitmap对象转换为Image对象
    Image* img = (Image*)m_pBitmap.GetThumbnailImage(width, height, NULL, NULL);
    //将Image图像进行JPEG图像压缩,压缩质量80
    CString OutputImagePath = _T("CompressedImage.jpg")
    CompressImage(img , OutputImagePath , 80);
    #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());  
  } 
}

第三步:将二进制数据保存为图像文件

下面为使用将二进制数据保存为图像文件算法的核心代码,如下所示:

int width = // 图像的宽度
int height = // 图像的高度
std::ofstream outFile("binary_image.bmp", std::ios::binary);
if (outFile) {
    // BMP文件头
    char bmpFileHeader[14] = { 'B', 'M', 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0 };
    // BMP信息头
    char bmpInfoHeader[40] = { 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    // 计算图像数据的大小
    int imageDataSize = ((width * height * 1 + 31) / 32) * 4;
    // BMP文件头中的文件大小
    *(int*)&bmpFileHeader[2] = 54 + imageDataSize;
    // BMP信息头中的图像宽度
    *(int*)&bmpInfoHeader[4] = width;
    // BMP信息头中的图像高度
    *(int*)&bmpInfoHeader[8] = height;
    // BMP信息头中的图像数据大小
    *(int*)&bmpInfoHeader[20] = imageDataSize;
    // 写入BMP文件头和BMP信息头
    outFile.write(bmpFileHeader, 14);
    outFile.write(bmpInfoHeader, 40);
    // 写入图像数据
    for (int i = height - 1; i >= 0; i--) {
        for (int j = 0; j < width; j++) {
            unsigned char pixel = 255 * binaryData[i * width + j];
            outFile.write((char*)&pixel, 1);
        }
        // 每行的字节数必须是4的倍数
        int paddingSize = ((width * 1 + 3) / 4) * 4 - width;
        if (paddingSize > 0) {
            char padding[3] = { 0, 0, 0 };
            outFile.write(padding, paddingSize);
        }
    }
    outFile.close();
}

工业相机通过SDK将图像保存二进制图像的优点

减少了存储空间: 与全色或灰度图像相比,二进制图像占用的存储空间要少得多。这意味着你可以在你的设备上存储更多的图像,这对内存有限的设备特别有用。


更快的处理: 二进制图像比全色或灰度图像更容易被计算机处理。这意味着你的图像分析软件可以更快地分析图像,允许更快的决策和更有效的数据处理。


提高准确性:由于二进制图像更简单,它们更容易准确分析。这对图像识别软件特别有用,因为二进制图像可以使它更容易区分图像中的物体或特征。


一致性: 因为二元图像仅由黑白像素组成,它们的视觉外观更加统一。这使得它们更容易与其他图像进行比较,并为图像分析建立一个标准。


兼容性: 许多图像分析软件是专门为处理二进制图像而设计的,使它们成为需要精确和一致的图像分析的工业相机的理想格式。这意味着通过SDK使用二进制图像可以提高你的相机与其他软件应用的兼容性。


工业相机通过SDK将图像保存二进制图像的行业应用

质量控制和检查: 二进制图像可用于各种工业制造过程中的缺陷检测和分类,如半导体、电子、汽车和制药行业。


监视和安全: 二进制图像被广泛用于监控系统,以检测异常情况,识别人脸,或跟踪移动的物体。


医学成像: 二元图像通常用于医学成像模式,如X射线、CT和MRI,以分割和分析感兴趣的病理区域。


机器人学和自动化: 二进制图像可用于机器人技术,用于工业环境中的物体识别、跟踪和定位,如仓库、工厂和物流中心。


农业和环境监测: 二进制图像可用于分析作物健康,识别植物疾病,检测害虫,或监测森林火灾、洪水和自然灾害。


综上所述,通过SDK使用工业相机和二进制图像处理,可以提高各种应用的准确性、速度和可靠性,从而使不同行业受益匪浅。

目录
相关文章
|
21小时前
|
存储 安全 算法
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
【C/C++ 数据发送结构设计】C++中的高效数据发送:多态、类型擦除与更多解决方案
80 0
|
21小时前
|
C++
C++ 访问说明符详解:封装数据,控制访问,提升安全性
C++ 中的访问说明符(public, private, protected)用于控制类成员的可访问性,实现封装,增强数据安全性。public 成员在任何地方都可访问,private 只能在类内部访问,protected 则允许在类及其派生类中访问。封装提供数据安全性、代码维护性和可重用性,通过 setter/getter 方法控制对私有数据的访问。关注公众号 `Let us Coding` 获取更多内容。
26 1
|
21小时前
|
开发工具 对象存储 Android开发
对象存储oss使用问题之C++使用OSS SDK时遍历OSS上的文件时崩溃如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
30 0
|
21小时前
|
安全 搜索推荐 Linux
Linux C++ 环境下数据高效备份策略:全面指南与最佳实践
Linux C++ 环境下数据高效备份策略:全面指南与最佳实践
37 1
|
21小时前
|
存储 机器学习/深度学习 算法
【C/C++ 查找算法】深入探索数据查找算法:原理、数学模型与C/C++实现
【C/C++ 查找算法】深入探索数据查找算法:原理、数学模型与C/C++实现
56 0
|
21小时前
|
JavaScript Java Maven
云效产品使用常见问题之android sdk 构建出aar后,上传到私有maven仓库失败如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
21小时前
|
安全 开发工具 Android开发
几个Flutter常见诊断错误与解决Android toolchain - develop for Android devices X Unable to locate Android SDK
几个Flutter常见诊断错误与解决Android toolchain - develop for Android devices X Unable to locate Android SDK
445 0
|
7月前
|
API 开发工具 Android开发
解决 Android App 上架 Google play后 ,签名变更,第三方sdk无法登录
解决 Android App 上架 Google play后 ,签名变更,第三方sdk无法登录
153 0
|
21小时前
|
开发工具 Android开发
Android获取SDK的版本信息
Android获取SDK的版本信息
46 0
|
5月前
|
编解码 Java 开发工具
Android端接入视频生产 Java SDK
Android端接入视频生产 Java SDK
43 1