最近用c#做視覺的專案,需要將彩色影像轉換為灰度影像,考慮到性能問題,嘗試了下定義Intptr作為資料快取中轉,并用new Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)的形式回歸bitmap影像,雖然性能得到了大幅度的提升,但定義的Intptr無法釋放,狂吃記憶體,不知該如何解決?
具體程序為:
1)通過System.Runtime.InteropServices.Marshal.AllocHGlobal(int cb)定義一個intptr
2)相關資料計算到intptr的記憶體空間中
3)用new Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)將intptr轉化為Bitmap影像
此時產生一個問題,如果呼叫System.Runtime.InteropServices.Marshal.FreeHGlobal(System.IntPtr)釋放intptr的記憶體,新的bitmap影像損壞,如果不釋放intptr的記憶體,系統記憶體瘋狂被吃掉
代碼如下:
public static void ColortoGray(ref Bitmap ImageScr,ref Bitmap ImageDst)
{
int height = ImageScr.Height;
int width = ImageScr.Width;
int offsetDst = width / 4 * 4 + 4 - width;
if (offsetDst == 4)
offsetDst = 0;
int strideDst = width + offsetDst;
int num = strideDst * height;
IntPtr intptrbuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(num);
BitmapData dataScr = ImageScr.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, ImageScr.PixelFormat);
int offsetScr = dataScr.Stride - width * 3;
unsafe
{
byte* ptrScr = (byte*)dataScr.Scan0.ToPointer();
byte* ptrDst = (byte*)intptrbuffer.ToPointer();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
*ptrDst = (byte)(0.114 * (*ptrScr) + 0.587 * (*(ptrScr + 1)) + 0.299 * (*(ptrScr + 2)));
ptrDst++;
ptrScr += 3;
}
ptrDst += offsetDst;
ptrScr += offsetScr;
}
}
ImageScr.UnlockBits(dataScr);
if (ImageDst != null)
{
ImageDst.Dispose();//釋放影像資源
}
imageDst= new Bitmap(width, height, strideDst,PixelFormat.Format8bppIndexed, intptrbuffer);
//System.Runtime.InteropServices.Marshal.FreeHGlobal(intptrbuffer);//釋放intptrbuffer記憶體,
//設定調色板
ColorPalette palette = ImageDst.Palette;
for (int i = 0; i < palette.Entries.Length; i++)
palette.Entries[i] = Color.FromArgb(255, i, i, i);
ImageDst.Palette = palette;
}
個人理解上新的bitmap影像應該把intptr占用了,但是重復呼叫該段代碼時,由于ImageDst是上次呼叫該函式通過intptr產生的影像,但通過 ImageDst.Dispose()釋放影像資源時,intptr的記憶體并沒有釋放掉
其實定義一個byte[] buffer=new byte[num]來代替intptr作為中轉快取也是沒有問題的,但是性能上差了將近20%的樣子,個人比較好奇的是,通過intptr的形式在c#中該如何實作這個功能,畢竟性能差的挺多的
uj5u.com熱心網友回復:
如果灰度影像是用來顯示的,就不用麻煩索引色(顯示的時候內部還要轉換回去)。還可能會更快一些。public static Bitmap ToGrayscale(Bitmap src)
{
var dst = new Bitmap(src.Width, src.Height);
using (var g = Graphics.FromImage(dst))
{
var ias = new ImageAttributes();
var m = new ColorMatrix();
m[0, 0] = m[0, 1] = m[0, 2] = 0.299f;
m[1, 0] = m[1, 1] = m[1, 2] = 0.587f;
m[2, 0] = m[2, 1] = m[2, 2] = 0.114f;
ias.SetColorMatrix(m);
g.DrawImage(src, new Rectangle(Point.Empty, src.Size), 0, 0, src.Width, src.Height, GraphicsUnit.Pixel, ias);
}
return dst;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/93488.html
標籤:C#
