某些時候我們可能會有將HImage轉成Bitmap的需求
例如可能想透過Picturebox察看結果但不想使用HalconWindow元件
下面為轉換的方式,三通道彩圖或是灰階圖都適用
原理大致上是利用指標(Pointer)取出像素色彩數值,但彩圖在HImage與Bitmap中RGB的排列方式並不相同
在Bitmap中,32bit位元像素的排列方式為BGRA BGRA BGRA
但在HImage則是 BBBB GGGG RRRR
所幸的是,我們能夠透過函式GetImagePointer3取得每個色彩的指標起始位置
這使的轉換會變得相當容易
灰階圖則是相對單純許多
程式碼會註解解說每一行的功能
/// <summary>
/// 將Halcon Image轉成Bitmap,不適用多通道影像(Channel>3)
/// </summary>
/// <param name="ho_Image">Halcon Image</param>
/// <returns></returns>
public Bitmap HoImageToBitmap(HObject ho_Image)
{
if (ho_Image == null)
throw new ArgumentNullException("ho_Image不能為null");
Bitmap bmp = null;
BitmapData bitmapData = new BitmapData();
Rectangle rect;
bool isColor = false;
HTuple hv_channels;
HTuple hv_type;
HTuple hv_Width;
HTuple hv_Height;
HTuple hv_point = null; //灰階用指標
HTuple hv_pointerRed = null; //彩圖用指標R
HTuple hv_pointerGreen = null; //彩圖用指標G
HTuple hv_pointerBlue = null; //彩圖用指標B
//確認影像頻道 1:灰階 3:彩圖 other:不允許轉換
HOperatorSet.CountChannels(ho_Image, out hv_channels);
if ((int)hv_channels == 1)
isColor = false;
else if ((int)hv_channels == 3)
isColor = true;
else
Throw new System.ArgumentException("影像為多通道圖(Channel>3)");
var pixelFormat =
(isColor) ? PixelFormat.Format32bppRgb : PixelFormat.Format8bppIndexed;
//取得色彩起始位置
if (isColor)
HOperatorSet.GetImagePointer3(ho_Image, out hv_pointerRed, out hv_pointerGreen,
out hv_pointerBlue, out hv_type, out hv_Width, out hv_Height);
else
HOperatorSet.GetImagePointer1(ho_Image, out hv_point, out hv_type,
out hv_Width, out hv_Height);
//前處理部分,建立空的Bitmap與記憶體鎖定位置
bmp = new Bitmap((int)hv_Width, (int)hv_Height, pixelFormat);
rect = new Rectangle(0, 0, hv_Width, hv_Height);
bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, bmp.PixelFormat);
unsafe
{
if (isColor)
{
//取得HImage色彩與Bitmap的起始位置
byte* p = (byte*)(void*)bitmapData.Scan0;
byte* hv_R = (byte*)hv_pointerRed.I;
byte* hv_G = (byte*)hv_pointerGreen.I;
byte* hv_B = (byte*)hv_pointerBlue.I;
for (int j = 0; j < (int)hv_Height; j++)
{
for (int i = 0; i < (int)hv_Width; i++)
{
//依序填入Bitmap之後移動指標
p[0] = (byte)hv_B[0]; ++p; ++hv_B;
p[0] = (byte)hv_G[0]; ++p; ++hv_G;
p[0] = (byte)hv_R[0]; ++p; ++hv_R;
p[0] = (byte)255; ++p;
}
}
}
else
{
//灰階用調色盤前置
ColorPalette grayPalette;
using (Bitmap tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
grayPalette = tempBmp.Palette;
for (int i = 0; i < 256; i++)
grayPalette.Entries[i] = Color.FromArgb(i, i, i);
byte* p = (byte*)(void*)bitmapData.Scan0;
byte* hv_p = (byte*)hv_point.I;
for (int j = 0; j < (int)hv_Height; j++)
{
for (int i = 0; i < (int)hv_Width; i++)
{
p[0] = (byte)hv_p[0];
++p; ++hv_p;
}
}
//更改調色盤
bmp.Palette = grayPalette;
}
bmp.UnlockBits(bitmapData);
}
ho_Image.Dispose();
return bmp;
}
參考資料
網誌管理員已經移除這則留言。
回覆刪除