c#真彩图转成灰度图
/// <summary>
/// 根据图片路径, 返回一张灰度图
/// </summary>
/// <param name="strPicPath">图片路径</param>
/// <returns>灰度图对象</returns>
public Image GetGrayPicture(string strPicPath)
{
/*
* Stride: 图像扫描宽度
* 图像在内存里是按行存储的。扫描行宽度就是存储一行像素,用了多少字节的内存。
* 比如一个101×200大小的图像,每个像素是32位的(也就是每个像素4个字节),那么实际每行占用的内存大小是101*4=404个字节。
* 然后一般的图像库都会有个内存对齐。假设按照8字节对齐,那么404按照8字节对齐的话,实际是408个字节。这408个字节就是扫描行宽度。
*
* Interop: 托管/非托管代码之间的互操作
*
* Marshal: 类提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,
* 此外还提供了在与非托管代码交互时使用的其他杂项方法
*/
// Create a new bitmap.
Bitmap bitmap = new Bitmap(strPicPath);
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
// Lock the bitmap's bits.
//转成24rgb颜色 24色就是由r g b, 三个颜色, 每个颜色各用一字节(8位)表示亮度
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
int iStride = bmpData.Stride; //图片一行象素所占用的字节
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int iBytes = iStride * bitmap.Height;
byte[] rgbValues = new byte[iBytes];
// Copy RGB values into the Array
Marshal.Copy(ptr, rgbValues, 0, iBytes);
for (int y = 0; y < bmpData.Height; ++y)
{
for (int x = 0; x < bmpData.Width; ++x)
{
//图像(x, y)坐标坐标中第1个像素中rgbValues中的索引位置(这儿x,y是从0开始记的)
//rgbValues每行是扫描宽个字节, 不是bitmap.Width * 3
int iThird = iStride * y + 3 * x;
byte avg = (byte)((rgbValues[iThird] + rgbValues[iThird + 1] + rgbValues[iThird + 2]) / 3);//转化成灰度
rgbValues[iThird] = avg;
rgbValues[iThird + 1] = avg;
rgbValues[iThird + 2] = avg;
}
}
// copy到原来图像中
Marshal.Copy(rgbValues, 0, ptr, rgbValues.Length);
// Unlock the bits.
bitmap.UnlockBits(bmpData);
return bitmap;
}
/// 根据图片路径, 返回一张灰度图
/// </summary>
/// <param name="strPicPath">图片路径</param>
/// <returns>灰度图对象</returns>
public Image GetGrayPicture(string strPicPath)
{
/*
* Stride: 图像扫描宽度
* 图像在内存里是按行存储的。扫描行宽度就是存储一行像素,用了多少字节的内存。
* 比如一个101×200大小的图像,每个像素是32位的(也就是每个像素4个字节),那么实际每行占用的内存大小是101*4=404个字节。
* 然后一般的图像库都会有个内存对齐。假设按照8字节对齐,那么404按照8字节对齐的话,实际是408个字节。这408个字节就是扫描行宽度。
*
* Interop: 托管/非托管代码之间的互操作
*
* Marshal: 类提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,
* 此外还提供了在与非托管代码交互时使用的其他杂项方法
*/
// Create a new bitmap.
Bitmap bitmap = new Bitmap(strPicPath);
Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
// Lock the bitmap's bits.
//转成24rgb颜色 24色就是由r g b, 三个颜色, 每个颜色各用一字节(8位)表示亮度
BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
int iStride = bmpData.Stride; //图片一行象素所占用的字节
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int iBytes = iStride * bitmap.Height;
byte[] rgbValues = new byte[iBytes];
// Copy RGB values into the Array
Marshal.Copy(ptr, rgbValues, 0, iBytes);
for (int y = 0; y < bmpData.Height; ++y)
{
for (int x = 0; x < bmpData.Width; ++x)
{
//图像(x, y)坐标坐标中第1个像素中rgbValues中的索引位置(这儿x,y是从0开始记的)
//rgbValues每行是扫描宽个字节, 不是bitmap.Width * 3
int iThird = iStride * y + 3 * x;
byte avg = (byte)((rgbValues[iThird] + rgbValues[iThird + 1] + rgbValues[iThird + 2]) / 3);//转化成灰度
rgbValues[iThird] = avg;
rgbValues[iThird + 1] = avg;
rgbValues[iThird + 2] = avg;
}
}
// copy到原来图像中
Marshal.Copy(rgbValues, 0, ptr, rgbValues.Length);
// Unlock the bits.
bitmap.UnlockBits(bmpData);
return bitmap;
}