Baumer工业相机
Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。
Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩展性等特点。
Baumer工业相机的BGAPI SDK可以在回调函数里实现高速存储图像到本地的功能。
Baumer工业相机SDK技术背景
Baumer工业相机的BGAPI SDK可以提供相机的图像原始数据,Halcon具有极为巨大的图像处理库,在图像处理领域非常强大,功能丰富,使用于工业视觉检测。
工业相机的SDK(Software Development Kit)是为了方便开发人员对工业相机进行控制和图像采集而提供的一套软件工具。而Halcon是一款强大的机器视觉软件,能够进行图像处理、分析、识别等多种任务。
有关于Baumer工业相机的全帧率存储问题,之前已经有相关的技术博客可以参考:
Baumer万兆网工业相机堡盟相机VLXT-28M.I如何做全帧率图像存储到本地
这里主要描述如何在C#的平台下实现对应的功能的核心代码
代码分析
本文介绍使用BGAPI SDK对Baumer工业相机进行开发时,使用回调函数BufferEvent进行图像保存在本地内存的方式进行高速存储的功能。
第一步:先注册SDK回调函数BufferEvent
C#环境下注册回调函数BufferEvent库代码如下所示:
foreach (BGAPI2.DataStream CurDataStream in ListDataStream) { CurDataStream.RegisterNewBufferEvent(BGAPI2.Events.EventMode.EVENT_HANDLER); CurDataStream.NewBufferEvent += new BGAPI2.Events.DataStreamEventControl.NewBufferEventHandler(mDataStream_NewBufferEvent2TestSpeed); CurDataStream.StartAcquisition(); }
第二步:在回调函数里进行图像保存到电脑内存
后续进行图像保存到内存的核心代码,如下所示:
void mDataStream_NewBufferEvent2TestSpeed(object sender, BGAPI2.Events.NewBufferEventArgs mDSEvent) { try { BGAPI2.Buffer mBufferFilled = null; mBufferFilled = mDSEvent.BufferObj; if (mBufferFilled == null) { MessageBox.Show("Error: Buffer Timeout after 1000 ms!"); } else if (mBufferFilled.IsIncomplete == true) { mBufferFilled.QueueBuffer(); // queue buffer again } else { #region//Bitmap图像转换(不再使用) //if (!FullSaveOpen.Checked) if (0 == 1) { IntPtr imagebuffer = new IntPtr(); BGAPI2.Image pImage = pImgProcessor.CreateImage((uint)mBufferFilled.Width, (uint)mBufferFilled.Height, mBufferFilled.PixelFormat, mBufferFilled.MemPtr, mBufferFilled.MemSize); BGAPI2.Image pTranImage = null; pTranImage = pImgProcessor.CreateTransformedImage(pImage, "Mono8"); int w = 0; int h = 0; w = (int)pTranImage.Width; h = (int)pTranImage.Height; imagebuffer = pTranImage.Buffer; #region//获取当前像素类型黑白或者彩色 string PixelFormatstr = mBufferFilled.PixelFormat; if (PixelFormatstr.Contains("Mono8")) { if (bFirstFrame) { pImgBits = new Byte[w * h]; //actform.pBitmap = new Bitmap(w,h,PixelFormat.Format8bppIndexed); //pBitmap = new System.Drawing.Bitmap(w,h,System.Drawing.Imaging.PixelFormat.Format8bppIndexed); // actform.pBitmap = new System.Drawing.Bitmap(w,h,System.Drawing.Imaging.PixelFormat.Format8bppIndexed); pBitmap = new System.Drawing.Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); prcSource.X = 0; prcSource.Y = 0; prcSource.Width = w; prcSource.Height = h; bFirstFrame = false; } } else { //Now you have the Imagebuffer and can do everything with it you want if (bFirstFrame) { pImgBits = new Byte[w * h * 3]; //actform.pBitmap = new Bitmap(w,h,PixelFormat.Format8bppIndexed); //pBitmap = new System.Drawing.Bitmap(w,h,System.Drawing.Imaging.PixelFormat.Format8bppIndexed); // actform.pBitmap = new System.Drawing.Bitmap(w,h,System.Drawing.Imaging.PixelFormat.Format8bppIndexed); pBitmap = new System.Drawing.Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format24bppRgb); prcSource.X = 0; prcSource.Y = 0; prcSource.Width = w; prcSource.Height = h; bFirstFrame = false; } } #endregion System.Drawing.Imaging.BitmapData bmpdata; System.Drawing.Imaging.BitmapData bmpdata2; if (PixelFormatstr.Contains("Mono8")) { System.Drawing.Imaging.ColorPalette palette = pBitmap.Palette; for (int i = 0; i < 256; i++) { palette.Entries[i] = Color.FromArgb(255, i, i, i); } pBitmap.Palette = palette; } if (PixelFormatstr.Contains("Mono8")) bmpdata = pBitmap.LockBits(prcSource, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); else bmpdata = pBitmap.LockBits(prcSource, System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb); if (PixelFormatstr.Contains("Mono8")) { System.Runtime.InteropServices.Marshal.Copy(imagebuffer, pImgBits, 0, w * h); System.Runtime.InteropServices.Marshal.Copy(pImgBits, 0, bmpdata.Scan0, w * h); } else { System.Runtime.InteropServices.Marshal.Copy(imagebuffer, pImgBits, 0, w * h * 3); System.Runtime.InteropServices.Marshal.Copy(pImgBits, 0, bmpdata.Scan0, w * h * 3); } pBitmap.UnlockBits(bmpdata); pBitmap_Cur1 = pBitmap; } #endregion #region//获取当前FrameID int FrameIDInt = (int)mBufferFilled.FrameID; if (FrameIDInt ==1) { bFirstFrame = true; } //OnNotifySetFrameID(FrameIDInt.ToString()); #endregion #region//显示图像会影响回调函数保存图像 //if (!FullSaveOpen.Checked) //{ // System.Drawing.Graphics graph = System.Drawing.Graphics.FromHwnd(pictureBoxA.Handle); // graph.DrawImage(pBitmap, prcPBox, prcSource, GraphicsUnit.Pixel); //} #endregion #region//新buffer深层复制给与图像显示 LowBuffer2 LowBuffer2Instance = new LowBuffer2(); LowBuffer2Instance.Width = mBufferFilled.Width; LowBuffer2Instance.Height = mBufferFilled.Height; LowBuffer2Instance.PixelFormat = mBufferFilled.PixelFormat; LowBuffer2Instance.MemPtr = mBufferFilled.MemPtr; LowBuffer2Instance.MemSize = mBufferFilled.MemSize; LowBuffer2Instance.FrameID = mBufferFilled.FrameID; DisplayLowBuffer = LowBuffer2Instance; #endregion #region//保存图像功能模块(重要) if (bSaveImg) { //bSaveImg = false; String strPath; String strtime; strtime = DateTime.Now.ToString("yyyyMMddhhmmssfff") + "-" + FrameIDInt; strPath = pImgFileDir + "\\" + strtime + "-" + FrameIDInt + ".bmp"; #region//不用代码 //Thread SaveImagesThread1 = new Thread((ThreadStart)delegate() { pBitmap_Cur.Save(strPath, System.Drawing.Imaging.ImageFormat.Bmp); ; }); //SaveImagesThread1.Start(); //SaveImagesThread1.Join(); //pBitmap_Cur.Save(strPath, System.Drawing.Imaging.ImageFormat.Bmp); #endregion #region//测试控制部分 countsavetime = countsavetime + 1; if (countsavetime > 100) { int stoppoint = 0; } if (SaveTrigger) { dt1 = System.DateTime.Now; SaveTrigger = false; } #endregion //回调函数中直接将buffer转为Bitmap #region//Convert BGAPI2.Buffer to Bitmap(it will reduce the additional cost time of callback function) System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap((int)mBufferFilled.Width, (int)mBufferFilled.Height, (int)mBufferFilled.Width, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, (IntPtr)((ulong)mBufferFilled.MemPtr + mBufferFilled.ImageOffset)); System.Drawing.Imaging.ColorPalette palette = bitmap.Palette; int nColors = 256; for (int ix = 0; ix < nColors; ix++) { uint Alpha = 0xFF; uint Intensity = (uint)(ix * 0xFF / (nColors - 1)); palette.Entries[ix] = System.Drawing.Color.FromArgb((int)Alpha, (int)Intensity, (int)Intensity, (int)Intensity); } bitmap.Palette = palette; string filenameBMP = mBufferFilled.Parent.Parent.Model + "_ImageMono8_" + mBufferFilled.FrameID + "_time_" + mBufferFilled.Timestamp + ".bmp"; string filenameBMP2 = strPath; //使用这种方法可以确保图片的连续性,规避下面方法的问题,也不会丢失图片 #region//Copy the Bitmap to a new Bitmap instance and add it to the list of bitmaps(memory) Bitmap clone = (Bitmap)bitmap.Clone(); BitmapData data = clone.LockBits(new Rectangle(0, 0, clone.Width, clone.Height), ImageLockMode.ReadOnly, clone.PixelFormat); clone.UnlockBits(data); actform.listOfBitMaps.Add(clone); #endregion #region//使用这种方法会导致丢几张图片,并且图片拍摄和实际时间对不上:如记录0-3s的图像,结果存取的是3-6s的图像(不用) //Bitmap newmemory = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat); //actform.listOfBitMaps.Add(newmemory); #endregion #region//使用这种方法可以确保图片的连续性,但是由于bitmap.save本身的存储需要时间因此无法达到满帧的速度(不用) //bitmap.Save(filenameBMP2, System.Drawing.Imaging.ImageFormat.Bmp); #endregion #region//存储当前图片时间戳作为名称,与图片对应起来 actform.listNameOfBitMaps.Add(strtime); #endregion #endregion #region//测试部分lowBuffer LowBuffer LowBufferInstance = new LowBuffer(); LowBufferInstance.Width = mBufferFilled.Width; LowBufferInstance.Height = mBufferFilled.Height; LowBufferInstance.PixelFormat = mBufferFilled.PixelFormat; LowBufferInstance.MemPtr = mBufferFilled.MemPtr; LowBufferInstance.MemSize = mBufferFilled.MemSize; LowBuffer LowBufferInstance2 = LowBufferInstance.Clone(); actform.listOfLowBuffer.Add(LowBufferInstance2); #endregion } #endregion mBufferFilled.QueueBuffer(); } } catch (BGAPI2.Exceptions.IException ex) { { string str2; str2 = string.Format("ExceptionType:{0}! ErrorDescription:{1} in function:{2}", ex.GetType(), ex.GetErrorDescription(), ex.GetFunctionName()); MessageBox.Show(str2); } } return; }
工业相机图像保存电脑内存的方式存储的优点
将工业相机图像存储在计算机内存中,而不是传统的存储形式,如胶片或磁带,有几个优点:
更快的访问: 检索存储在计算机内存中的图像可以立即完成,而从胶片或磁带中寻找和检索图像可能是费时和乏味的。
提高图像质量: 存储在计算机内存中的数字图像不会像胶片那样受到物理损坏或老化的影响,从而可以获得更好的图像质量并保持原始图像的完整性。
更容易分享: 数字图像可以很容易地以数字方式分享和传输到其他设备或在互联网上,使之更容易与他人合作开展工业项目。
增加存储容量: 与传统的存储形式相比,计算机内存允许更大的存储容量。工业相机图像可以很容易地存储在硬盘、固态驱动器和USB闪存驱动器上。
成本效益高: 虽然购买计算机内存存储设备的初始成本可能高于传统的存储方式,但由于不需要物理存储空间,维护和管理数字图像的长期成本往往更低。