Baumer工业相机堡盟工业相机如何通过BGAPI SDK直接实现Mono16位深度的图像保存(C#)
Baumer工业相机
Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。
Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩展性等特点。
Baumer工业相机通过使用BGAPI SDK进行开发时,在C++环境可以直接实现位深度为16的图像保存。
Baumer工业相机保存位深度12/16位图像的技术背景
工业相机通常用于需要高质量图像的分析和检查的专业环境中。这些相机被设计用来捕捉16比特的高比特深度的图像,与低比特深度的图像相比,可以捕捉到更大范围的色彩和细节。
保存位深16位图像的工业相机的技术背景涉及几个关键部分。首先,相机的图像传感器必须能够捕捉到高比特深度的图像。这是通过使用高质量的图像传感器来实现的,该传感器能够以每像素16比特的分辨率捕获数据。
其次,相机的电子设备必须能够处理和存储高比特深度的图像数据。这意味着相机需要有一个高速处理器和足够的内存来处理所产生的大量图像数据。
第三,相机的软件必须能够支持16位图像的保存。这意味着相机的固件和软件接口必须被设计成能够处理16位图像所产生的更大的文件尺寸,并且还能与工业标准文件格式如TIFF和RAW兼容。
总的来说,保存16位深度图像的工业相机的技术背景涉及高质量的图像传感器、强大的电子器件和专门的软件的组合,这些都是为了处理捕捉和存储高位深度图像的独特需求。
这里主要描述如何在C#的平台下通过BGAPI SDK直接实现Mono16图像格式的保存功能的核心代码
代码案例分享
本文介绍使用BGAPI SDK对Baumer的工业相机进行开发时,直接实现Mono12或者Mono16图像格式的保存功能
如下为核心代码实现步骤:
1:引用合适的类文件
C#环境下核心代码如下所示:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
using CSCameraDemo.Properties;
using System.Globalization;
using WindowsFormsApplication1;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing.Imaging;
using BGAPI2;
2:通过BGAPI SDK直接保存Mono12/16图像
下面为在在C#环境开启相机连接相机后通过转换图像格式实现Mono12或者Mono16图像格式保存的核心代码。
如下所示:
SystemList
Open a System
Get the InterfaceList and fill it Open an Interface
Get the DeviceList and fill it
Open a Device
void mDataStream_NewBufferEvent(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)
{
//MessageBox.Show("Error: Image is incomplete!");
//queue buffer again
mBufferFilled.QueueBuffer();
}
else
{
#region//获取当前FrameID
FrameIDInt = (int)mBufferFilled.FrameID;
OnNotifySetFrameID(FrameIDInt.ToString());
#endregion
//将相机内部图像内存数据转为bitmap数据
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));
#region//Mono图像数据转换。彩色图像数据转换于此不同
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;
#endregion
long currenttime = (long)mBufferFilled.Timestamp;
DateTime sdasd = GetTime(currenttime, true);
#region//回调函数保存图像功能
if (bSaveImg)
{
//使用bitmap自带函数保存
string strtime = DateTime.Now.ToString("yyyyMMddhhmmssfff");
string saveimagepath = pImgFileDir +"\\"+ strtime + ".jpg";
// bitmap.Save(saveimagepath, System.Drawing.Imaging.ImageFormat.Bmp);
//使用opencv进行保存图像
if (mBufferFilled.PixelFormat == "Mono8")
{
OpenCvSharp.Mat matgray = OpenCvSharp.Extensions.BitmapConverter.ToMat(bitmap);//用bitmap转换为mat
matgray.SaveImage("opencv_image.png");
Cv2.ImWrite("opencvcv_image_Clone.png", matgray);
Cv2.ImWrite(saveimagepath, matgray);
}
//将相机中原始图像数据通过BGAPI SDK直接保存为16位深度的图像
if (mBufferFilled.PixelFormat.Contains("Mono12"))
{
short[] mImageBuffer16Copy = new short[(uint)((uint)mBufferFilled.Width * (uint)mBufferFilled.Height * 1)];
Marshal.Copy((IntPtr)mBufferFilled.MemPtr, mImageBuffer16Copy, 0, (int)((int)mBufferFilled.Width * (int)mBufferFilled.Height * 1));
//convert Mono12 to Mono16
uint length = (uint)((uint)mBufferFilled.Width * (uint)mBufferFilled.Height) * 1;
for (uint l = 0; l < length; l++)
{
mImageBuffer16Copy[l] = (short)(mImageBuffer16Copy[l] << 4);
}
saveimagepath = pImgFileDir + "\\" + strtime + "-Mono16.png";
saveMono16Tiff(saveimagepath , mImageBuffer16Copy, (int)mBufferFilled.Width, (int)mBufferFilled.Height * 1);
}
bSaveImg = false;//变量控制单次保存图像
}
#endregion
#region//bitmap的图像数据复制pBitmap
Bitmap clonebitmap = (Bitmap)bitmap.Clone();
BitmapData data = clonebitmap.LockBits(new Rectangle(0, 0, clonebitmap.Width, clonebitmap.Height), ImageLockMode.ReadOnly, clonebitmap.PixelFormat);
clonebitmap.UnlockBits(data);
pBitmap = clonebitmap;
#endregion
#region//将pBitmap图像数据显示在UI界面PictureBox控件上
prcSource.X = 0;prcSource.Y = 0;
prcSource.Width = (int)mBufferFilled.Width;prcSource.Height = (int)mBufferFilled.Height;
System.Drawing.Graphics graph = System.Drawing.Graphics.FromHwnd(pictureBoxA.Handle);
graph.DrawImage(pBitmap, prcPBox, prcSource, GraphicsUnit.Pixel);
#endregion
clonebitmap.Dispose(); //清除临时变量clonebitmap所占内存空间
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;
}
3:使用BGAPI SDK的图像直接转换Mono12/16图像并保存的功能
下面为在在C#环境开启相机连接相机后通过BGAPI SDK直接实现Mono12或者Mono16图像格式保存的核心代码。
如下所示:
public static void saveMono16Tiff(string fileName, short[] shortarray, int imagewidth, int imageheight)
{
FileStream FileST = new FileStream(fileName, FileMode.Create);
// Create the writer for data.
BinaryWriter binWriter = new BinaryWriter(FileST);
// Write data to Test.data.
ushort data16 = 0;
uint data32 = 0;
uint sizeX = (uint)imagewidth;
uint sizeY = (uint)imageheight;
int imagelength2 = imagewidth * imageheight;
// TIFF identifier and count of directory entries
//================================================
data16 = 0x4949; // identifier "II" for little-endian byte order
binWriter.Write(data16);
data16 = 42; // tiff identifier 42
binWriter.Write(data16);
data32 = 8; // offset for the first IFD
binWriter.Write(data32);
data16 = 12; // number of directory entries
binWriter.Write(data16);
// 1. entry: ImageWidth (number of columns)
//==========================================
data16 = 0x100; // tag: 100.H
binWriter.Write(data16);
data16 = 4; // type: LONG
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = sizeX; // value: horizontal image size
binWriter.Write(data32);
// 2. entry: ImageLength (number of rows)
//=======================================
data16 = 0x101; // tag: 101.H
binWriter.Write(data16);
data16 = 4; // type: LONG
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = sizeY; // value: horizontal image size
binWriter.Write(data32);
// 3. entry: BitsPerSample
//=========================
data16 = 0x102; // tag: 102.H
binWriter.Write(data16);
data16 = 3; // type: SHORT
binWriter.Write(data16);
data32 = 1; // count: 1 == SamplesPerPixel Mono16
binWriter.Write(data32);
data32 = 16; // SamplesPerPixel == 1 => value: 16 (16 bps => NOT BASELINE!)
binWriter.Write(data32);
// 4. entry: Compression
//=======================
data16 = 0x103; // tag: 103.H
binWriter.Write(data16);
data16 = 3; // type: SHORT
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = 1; // value: 1 (no compression)
binWriter.Write(data32);
// 5. entry: PhotometricInterpretation
//======================================
data16 = 0x106; // tag: 106.H
binWriter.Write(data16);
data16 = 3; // type: SHORT
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = 1; // SamplesPerPixel == 1 => value: 1 (BlackIsZero)
binWriter.Write(data32);
// 6. entry: StripOffsets
//========================
data16 = 0x111; // tag: 111.H
binWriter.Write(data16);
data16 = 4; // type: LONG
binWriter.Write(data16);
data32 = 1; // count: 1 == StripsPerImage
binWriter.Write(data32);
data32 = 174; // value = 8 + 2 + 12*12 + 4 + 8 + 8 = 174
binWriter.Write(data32);
// 7. entry: SamplesPerPixel
//===========================
data16 = 0x115; // tag: 115.H
binWriter.Write(data16);
data16 = 3; // type: SHORT
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32); ;
data32 = 1; // SamplesPerPixel == 1 Mono16
binWriter.Write(data32);
// 8. entry: RowsPerStrip
//========================
data16 = 0x116; // tag: 116.H
binWriter.Write(data16);
data16 = 4; // type: LONG
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = sizeY; // value: vertical image size (one strip only)
binWriter.Write(data32);
// 9. entry: StripByteCounts (For each strip, the number of bytes in the strip after compression.)
//================================================================================================
data16 = 0x117; // tag: 117.H
binWriter.Write(data16);
data16 = 4; // type: LONG
binWriter.Write(data16);
data32 = 1; // count: 1 == StripsPerImage
binWriter.Write(data32);
data32 = 2 * 1 * sizeX * sizeY; // value = 2* 1 * SizeX * SizeY
binWriter.Write(data32);
// 10. entry: XResolution (The number of pixels per ResolutionUnit in the ImageWidth direction.)
//================================================================================================
data16 = 0x11A; // tag: 11A.H
binWriter.Write(data16);
data16 = 5; // type: RATIONAL
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = 158; // offset to value = 8 + (2 + 12*12 + 4) = 158
binWriter.Write(data32);
// 11. entry: YResolution (The number of pixels per ResolutionUnit in the ImageLength direction.)
//================================================================================================
data16 = 0x11B; // tag: 11B.H
binWriter.Write(data16);
data16 = 5; // type: RATIONAL
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = 166; // offset to value = 8 + (2 + 12*12 + 4) + 8 = 166
binWriter.Write(data32);
// 12. entry: ResolutionUnit (The unit of measurement for XResolution and YResolution.)
//=====================================================================================
data16 = 0x128; // tag: 128.H
binWriter.Write(data16);
data16 = 3; // type: SHORT
binWriter.Write(data16);
data32 = 1; // count: 1
binWriter.Write(data32);
data32 = 2; // value: 2 (Inch) => dpi
binWriter.Write(data32);
data32 = 0; // offset of next IFD: none
binWriter.Write(data32);
// write IFD values longer than 4 byte
//======================================
data32 = 72; // XResolution numerator: 72 => 72 dpi (a common value..)
binWriter.Write(data32);
data32 = 1; // XResolution denominator: 1
binWriter.Write(data32);
data32 = 72; // YResolution numerator: 72 => 72 dpi (a common value..)
binWriter.Write(data32);
data32 = 1; // YResolution denominator: 1
binWriter.Write(data32);
// end of header save to file
// save image data (converted from Mono12 to Mono16) to file
for (int i = 0; i < imagelength2; i++)
{
data16 = (ushort)shortarray[i];
binWriter.Write(data16);
}
// close file
binWriter.Close();
FileST.Close();
return;
} // end of saveMono16Tiff()
工业相机使用位深度12/16位图像的优点
更好的图像细节:12/16位图像可以捕捉到更多的细节和颜色深度,提供更高的图像质量。
更广泛的动态范围:12/16位图像允许在明暗变化很大的场景中捕捉到更多的细节和颜色,以及更好的光线控制。
更低的噪声:采用12/16位图像可以减少噪声,使得图像更加清晰。
更好的后期处理:12/16位图像可以在后期处理中更灵活地进行平滑、增加对比度和其他调整。
因此,工业相机使用12/16位图像可以提供更高质量的图像,更好的细节和颜色控制,并为后期处理提供更多的灵活性。
工业相机使用位深度12/16位图像的行业应用
-
医疗成像:工业相机可用于各种医疗成像应用,例如X射线成像,MRI和CT扫描。这些应用需要16位图像位深度来提供高质量的成像结果。
-
汽车制造:工业相机可以用于汽车制造中的各种应用,例如质量控制和检查。这些应用需要高分辨率和16位图像位深度,以检测并处理微小的缺陷或问题。
-
机器人视觉:工业相机的高速度和高精度对于机器人视觉应用非常重要。机器人需要能够识别和定位目标,同时能够处理16位图像位深度的高质量图像。
-
智能交通系统:工业相机也可以用于智能交通系统中。例如,交通监控摄像机需要高质量的图像以便能够识别和跟踪车辆,行人和其他交通标志。
总之,工业相机使用16位图像位深度的行业应用范围非常广泛,它们可以用于各种不同的应用,以提供高质量的成像结果和精确的图像处理功能。