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;
}
分类:
c#
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义