C# BitmapData和Marshal.Copy()用法

C# BitmapData和Marshal.Copy()用法

//此函数用法例子如下:

<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:18px;">public static byte[] GetGrayArray(Bitmap srcBmp, Rectangle rect){//将Bitmap锁定到系统内存中,获得BitmapData//这里的第三个参数确定了该图像信息时rgb存储还是Argb存储BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行IntPtr srcPtr = srcBmpData.Scan0;//将Bitmap对象的信息存放到byte数组中int scanWidth = srcBmpData.Width * 3;int src_bytes = scanWidth * rect.Height;//int srcStride = srcBmpData.Stride;byte[] srcValues = new byte[src_bytes];byte[] grayValues = new byte[rect.Width * rect.Height];//RGB[] rgb = new RGB[srcBmp.Width * rows];//复制GRB信息到byte数组Marshal.Copy(srcPtr, srcValues, 0, src_bytes);//LogHelper.OutputArray(srcValues, rect.Width * 3, rect.Height, true);//Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);//解锁位图srcBmp.UnlockBits(srcBmpData);//灰度化处理int m = 0, j = 0;int k = 0;byte gray;//根据Y = 0.299*R + 0.587*G + 0.114*B,intensity为亮度for (int i = 0; i < rect.Height; i++) //行{for (j = 0; j < rect.Width; j++) //列{//注意位图结构中RGB按BGR的顺序存储k = 3 * j;gray = (byte)(srcValues[i * scanWidth + k + 2] * 0.299+ srcValues[i * scanWidth + k + 1] * 0.587+ srcValues[i * scanWidth + k + 0] * 0.114);grayValues[m] = gray; //将灰度值存到byte一维数组中m++;}}return grayValues;}</span></span>/*以上方法,主要是实现一个图像指定矩形区域的信息进行处理,以一维数组形式返回指定矩形区域的灰度值,此方法会遇到一个很棘手的问题假设一张图像的大小256*256,想要处理图像的上下部分区域为256*10,左右部分区域10*256的信息,则创建矩形区域为:*/// 上部分区域:Rectangle rectTop = new Rectangle(0,0,256,10);// 下部分区域:Rectangle rectBottom = new Rectangle(0,256-10,256,10);// 左部分区域:Rectangle rectLeft = new Rectangle(0,0,10,256);// 有部分区域:Rectangle rectRight = new Rectangle(256-10,0,10,256);

/*此时上下部分没有问题,左右部分则会出现问题,原因很简单阐述如下:是BitmapData,Marshal.Copy()函数造成的C#处理图像时使用BitmapData,这个是将处理的图像锁定到内存中,为了提高效率,将图像锁定要内存IntPtr srcPtr = srcBmpData.Scan0;这个是指向锁定图像的第一个地址,然后按照顺序读取像素数据,这时,左右部分区域的宽度只有10,如果这一行读取完之后,应该此时换行读取下一行像素数据,但是实际上它没有,而是一直按照顺序读取,没有换行,此时问题就出现了,因为左区域是图像的一部分,整个图像比方如下:“-”表示左区域,,即要处理的部分;“+”表示图像的剩余部分—+++++++++++++++++++++++—+++++++++++++++++++++++—+++++++++++++++++++++++—+++++++++++++++++++++++—+++++++++++++++++++++++—+++++++++++++++++++++++扫描时第一行读取到第三个“-”号之后,应该换行,但是没有,它继续读取“++++”,一直读取到行尾,这才换行,问题就是这么产生的,上图如果没有理解的,接下来我画一个图如下:

思考一下,两种办法如下[A]首先,想到的最好的办法我要锁定哪一部分区域就要取得相应区域的像素数据,但是目前这个我没有实现[B]其次,我用了两外一种方法解决了,就是将源图像的要计算的区域或者要处理的区域图像裁切好,因为源图像后面是要用的,所以裁切后得到的图像另保存之,传递给方法,然后将上述方法修改为*/

<span style="font-family:Microsoft YaHei;font-size:14px;"><span style="font-family:Microsoft YaHei;font-size:18px;">///这里的srcBmp是裁切后要处理的区域的图像public static byte[] GetGrayArray(Bitmap srcBmp){//将Bitmap锁定到系统内存中,获得BitmapData//这里的第三个参数确定了该图像信息时rgb存储还是Argb存储Rectangle rect = new Rectangle(0,0,srcBmp.Width,srcBmp.Height); //表示要锁定全图BitmapData srcBmpData = srcBmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);//位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行IntPtr srcPtr = srcBmpData.Scan0;//将Bitmap对象的信息存放到byte数组中int scanWidth = srcBmpData.Width * 3;int src_bytes = scanWidth * rect.Height;//int srcStride = srcBmpData.Stride;byte[] srcValues = new byte[src_bytes];byte[] grayValues = new byte[rect.Width * rect.Height];//RGB[] rgb = new RGB[srcBmp.Width * rows];//复制GRB信息到byte数组Marshal.Copy(srcPtr, srcValues, 0, src_bytes);//LogHelper.OutputArray(srcValues, rect.Width * 3, rect.Height, true);//Marshal.Copy(dstPtr, dstValues, 0, dst_bytes);//解锁位图srcBmp.UnlockBits(srcBmpData);//灰度化处理int m = 0, j = 0;int k = 0;byte gray;//根据Y = 0.299*R + 0.587*G + 0.114*B,intensity为亮度for (int i = 0; i < rect.Height; i++) //行{for (j = 0; j < rect.Width; j++) //列{//注意位图结构中RGB按BGR的顺序存储k = 3 * j;gray = (byte)(srcValues[i * scanWidth + k + 2] * 0.299+ srcValues[i * scanWidth + k + 1] * 0.587+ srcValues[i * scanWidth + k + 0] * 0.114);grayValues[m] = gray; //将灰度值存到byte一维数组中m++;}}return grayValues;}</span></span>

//这样也能解决上述问题,求赐教方法[A]的实现,谢谢,这个问题先记录到此。

切忌贪婪,恨不得一次玩遍所有传说中的好景点,

C# BitmapData和Marshal.Copy()用法

相关文章:

你感兴趣的文章:

标签云: