How to go through each and every pixel of an image efficiently?

專案名稱: SpeedUpPixelAcess

image

Unmaged code:

第一種方式: MIplImage

(1) MIplImage: managed structure equivalent to IplImage

利用Marshal.PtrToStructure指向來源影像指標img.Ptr, 資料結構型態為 MIplImage,

記得前面強迫轉型(MIplImage)

(2) IntPtr intPtr = mImg.ImageData;
C#利用IntPtr指標型態指向 ImageData: 存放影像像素資料起始位置

(3) byte* ptr = (byte*)intPtr.ToPointer();

影像像素資料為byte, (3)表示將C# intPtr格式轉成C++的byte*指標格式

(4) 可以將(2)(3)變成byte* ptr = (byte*)mImg.ImageData.ToPointer();  

再次強調 mImg資料型態為MIplImage

private static void RemoveBGUnmanagedVersion1(Image<Bgr, byte> img)
{
MIplImage mImg = (MIplImage)Marshal.PtrToStructure(img.Ptr, typeof(MIplImage));
int hei = img.Height;
int wid = img.Width;
int i, j;
unsafe
{
//IntPtr intPtr = mImg.ImageData;
//byte* ptr = (byte*)intPtr.ToPointer();
byte* ptr = (byte*)mImg.ImageData.ToPointer();
for (j = 0; j < hei; j++)
for (i = 0; i < wid; i++)
{
ptr[0] = 0; // remove Blue channel
ptr++;
ptr[0] = 0; // remove Green channel
ptr++;
ptr++; // do nothing to Red channel
}
}
}

第二種方式: MCvMat

類似第一種方法MIplImage

(1) MCvMat: Mananged structure equivalent to CvMat

利用Marshal.PtrToStructure指向來源影像指標img.Mat.Ptr, 資料結構型態為 MCvMat,

記得前面強迫轉型(MCvMat)

(2) byte* ptr = (byte*)mImg.Data.ToPointer();    再次強調:其中mImg資料型態為MCvMat

影像像素資料為byte, (3)表示將C# intPtr格式轉成C++的byte*指標格式

private static void RemoveBGUnmanagedVersion12(Image<Bgr, byte> img)
{
MCvMat mImg = (MCvMat)Marshal.PtrToStructure(img.Mat.Ptr, typeof(MCvMat));
int hei = img.Height;
int wid = img.Width;
int i, j;
unsafe
{
byte* ptr = (byte*)mImg.Data.ToPointer();
for (j = 0; j < hei; j++)
for (i = 0; i < wid; i++)
{
ptr[0] = 0; // remove Blue channel
ptr++;
ptr[0] = 0; // remove Green channel
ptr++;
ptr++; // do nothing to Red channel
}
}
}

第三種方式: BitmapData

(1) 採用Image裡面成員Bitmap屬性, 搭配BitmapData資料格式進行感性區域(ROI)內的像素操作, 一般來說

ROI即原始影像大小new Rectangle(0, 0, wid, hei)

(2) BitmapData bmpData = bmp.LockBits(…) 利用LockBits將記憶體中的資料鎖住, 並回傳BitmapData

(3) byte* ptr = (byte*)bmpData.Scan0.ToPointer(); 取得影像陣列起始指標位址,即Scan0.ToPointer

(4) 接下來就可以針對BGR進行讀寫囉

(5) 全部完成後, 將記憶體中資料解鎖:   bmp.UnlockBits(bmpData);
        

private static void RemoveBGUnmanagedVersion2(Image<Bgr, byte> img)
{
int hei = img.Height;
int wid = img.Width;
Bitmap bmp = img.Bitmap;
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, wid, hei), ImageLockMode.ReadOnly, img.Bitmap.PixelFormat);


int i, j;

unsafe
{
//IntPtr bmpDataScan0 = bmpData.Scan0;
//byte* ptr = (byte*)bmpDataScan0.ToPointer();
byte* ptr = (byte*)bmpData.Scan0.ToPointer();
for (j = 0; j < hei; j++)
{
for (i = 0; i < wid; i++)
{
try
{
ptr[0] = 0; // remove Blue channel
ptr++;
ptr[0] = 0; // remove Green channel
ptr++;
ptr++; // do nothing to Red channel
}
catch (Exception exception) { MessageBox.Show(exception.Message); }
}
}

try
{
bmp.UnlockBits(bmpData);
}
catch (Exception exception) {
MessageBox.Show(exception.Message);
}

}
}

==========================================================

Managed code:

第一種方式

像素排列方式: img.Data[row, column, channel]

private static void RemoveBGChannelsMangedVersion1(Image<Bgr, byte> img)
{
int hei = img.Height;
int wid = img.Width;
int i, j;
for (j = 0; j < hei; j++)
for (i = 0; i < wid; i++)
{
img.Data[j, i, 0] = 0; // remove Blue channel
img.Data[j, i, 1] = 0; // remove Green channel
}
}

第二種方式

private static void RemoveBGChannelsMangedVersion2(Image<Bgr, byte> img)
{
int hei = img.Height;
int wid = img.Width;
int i, j;
byte[, ,] pImg = img.Data;
for (j = 0; j < hei; j++)
for (i = 0; i < wid; i++)
{
pImg[j, i, 0] = 0; // remove Blue channel
pImg[j, i, 1] = 0; // remove Green channel
//pImgCopy[j, i, 2];
}
}

==========================================================

彩色轉灰階

image

private static void RGB2Gray(Bitmap src)
{
int wid = src.Width;
int hei = src.Height;
int i, j;
BitmapData bmpData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, src.PixelFormat);
unsafe
{
byte* ptr = (byte*)bmpData.Scan0;
double gray;
for (j = 0; j < hei; j++)
for (i = 0; i < wid; i++)
{
gray = 0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0];
ptr[0] = ptr[1] = ptr[2] = (byte)gray;
ptr+=3;
}
}
src.UnlockBits(bmpData);
}

pixel[i] – pixel[i+1] + 128

image

int wid = src.Width;
int hei = src.Height;
int i, j;
BitmapData bmpData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite, src.PixelFormat);
unsafe
{
byte* ptr = (byte*)bmpData.Scan0;
byte* ptrNext = ptr+3;

double gray, grayNext;
int total = hei * wid;
//for (j = 0; j < hei; j++)
// for (i = 0; i < wid; i++)
for(i=0; i<total-1;i++)
{
gray = 0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0];
grayNext = 0.299 * ptrNext[2] + 0.587 * ptrNext[1] + 0.114 * ptrNext[0];
ptr[0] = ptr[1] = ptr[2] = (byte)(gray - grayNext+128);
ptr += 3;
ptrNext = ptr + 3;
}
}
src.UnlockBits(bmpData);

參考資料:

1.C# 影像處理的速度極限
2.[C#] 圖片存檔(在 GDI+ 中發生泛型錯誤)

3.[C#] 濾鏡筆記 – LockBits影像處理 + 浮雕效果

arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(1) 人氣()