原文:C#图片灰度处理(位深度24→位深度8)

#region 灰度处理
/// <summary>
/// 将源图像灰度化,并转化为8位灰度图像。
/// </summary>
/// <param name="original"> 源图像。 </param>
/// <returns> 8位灰度图像。 </returns>
public static Bitmap RgbToGrayScale(Bitmap original)
{
if (original != null)
{
// 将源图像内存区域锁定
Rectangle rect = new Rectangle(, , original.Width, original.Height);
BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly,
PixelFormat.Format24bppRgb); // 获取图像参数
int width = bmpData.Width;
int height = bmpData.Height;
int stride = bmpData.Stride; // 扫描线的宽度,比实际图片要大
int offset = stride - width * ; // 显示宽度与扫描线宽度的间隙
IntPtr ptr = bmpData.Scan0; // 获取bmpData的内存起始位置的指针
int scanBytesLength = stride * height; // 用stride宽度,表示这是内存区域的大小 // 分别设置两个位置指针,指向源数组和目标数组
int posScan = , posDst = ;
byte[] rgbValues = new byte[scanBytesLength]; // 为目标数组分配内存
Marshal.Copy(ptr, rgbValues, , scanBytesLength); // 将图像数据拷贝到rgbValues中
// 分配灰度数组
byte[] grayValues = new byte[width * height]; // 不含未用空间。
// 计算灰度数组 byte blue, green, red, YUI; for (int i = ; i < height; i++)
{
for (int j = ; j < width; j++)
{ blue = rgbValues[posScan];
green = rgbValues[posScan + ];
red = rgbValues[posScan + ];
YUI = (byte)(0.229 * red + 0.587 * green + 0.144 * blue);
//grayValues[posDst] = (byte)((blue + green + red) / 3);
grayValues[posDst] = YUI;
posScan += ;
posDst++; }
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
} // 内存解锁
Marshal.Copy(rgbValues, , ptr, scanBytesLength);
original.UnlockBits(bmpData); // 解锁内存区域 // 构建8位灰度位图
Bitmap retBitmap = BuiltGrayBitmap(grayValues, width, height);
return retBitmap;
}
else
{
return null;
}
} /// <summary>
/// 用灰度数组新建一个8位灰度图像。
/// </summary>
/// <param name="rawValues"> 灰度数组(length = width * height)。 </param>
/// <param name="width"> 图像宽度。 </param>
/// <param name="height"> 图像高度。 </param>
/// <returns> 新建的8位灰度位图。 </returns>
private static Bitmap BuiltGrayBitmap(byte[] rawValues, int width, int height)
{
// 新建一个8位灰度位图,并锁定内存区域操作
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
BitmapData bmpData = bitmap.LockBits(new Rectangle(, , width, height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); // 计算图像参数
int offset = bmpData.Stride - bmpData.Width; // 计算每行未用空间字节数
IntPtr ptr = bmpData.Scan0; // 获取首地址
int scanBytes = bmpData.Stride * bmpData.Height; // 图像字节数 = 扫描字节数 * 高度
byte[] grayValues = new byte[scanBytes]; // 为图像数据分配内存 // 为图像数据赋值
int posSrc = , posScan = ; // rawValues和grayValues的索引
for (int i = ; i < height; i++)
{
for (int j = ; j < width; j++)
{
grayValues[posScan++] = rawValues[posSrc++];
}
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
} // 内存解锁
Marshal.Copy(grayValues, , ptr, scanBytes);
bitmap.UnlockBits(bmpData); // 解锁内存区域 // 修改生成位图的索引表,从伪彩修改为灰度
ColorPalette palette;
// 获取一个Format8bppIndexed格式图像的Palette对象
using (Bitmap bmp = new Bitmap(, , PixelFormat.Format8bppIndexed))
{
palette = bmp.Palette;
}
for (int i = ; i < ; i++)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
// 修改生成位图的索引表
bitmap.Palette = palette; return bitmap;
}
#endregion

C#图片二值化处理(位深度8→位深度1)

#region 二值化
/*
1位深度图像 颜色表数组255个元素 只有用前两个 0对应0 1对应255
1位深度图像每个像素占一位
8位深度图像每个像素占一个字节 是1位的8倍
*/
/// <summary>
/// 将源灰度图像二值化,并转化为1位二值图像。
/// </summary>
/// <param name="bmp"> 源灰度图像。 </param>
/// <returns> 1位二值图像。 </returns>
public static Bitmap GTo2Bit(Bitmap bmp)
{
if (bmp != null)
{
// 将源图像内存区域锁定
Rectangle rect = new Rectangle(, , bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly,
PixelFormat.Format8bppIndexed); // 获取图像参数
int leng, offset_1bit = ;
int width = bmpData.Width;
int height = bmpData.Height;
int stride = bmpData.Stride; // 扫描线的宽度,比实际图片要大
int offset = stride - width; // 显示宽度与扫描线宽度的间隙
IntPtr ptr = bmpData.Scan0; // 获取bmpData的内存起始位置的指针
int scanBytesLength = stride * height; // 用stride宽度,表示这是内存区域的大小
if (width % == )
{
leng = width / ;
}
else
{
leng = width / + ( - (width / % ));
if (width % != )
{
offset_1bit = leng - width / ;
}
else
{
offset_1bit = leng - width / ;
}
} // 分别设置两个位置指针,指向源数组和目标数组
int posScan = , posDst = ;
byte[] rgbValues = new byte[scanBytesLength]; // 为目标数组分配内存
Marshal.Copy(ptr, rgbValues, , scanBytesLength); // 将图像数据拷贝到rgbValues中
// 分配二值数组
byte[] grayValues = new byte[leng * height]; // 不含未用空间。
// 计算二值数组
int x, v, t = ;
for (int i = ; i < height; i++)
{
for (x = ; x < width; x++)
{
v = rgbValues[posScan];
t = (t << ) | (v > ? : ); if (x % == )
{
grayValues[posDst] = (byte)t;
posDst++;
t = ;
}
posScan++;
} if ((x %= ) != )
{
t <<= - x;
grayValues[posDst] = (byte)t;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
posDst += offset_1bit;
} // 内存解锁
Marshal.Copy(rgbValues, , ptr, scanBytesLength);
bmp.UnlockBits(bmpData); // 解锁内存区域 // 构建1位二值位图
Bitmap retBitmap = twoBit(grayValues, width, height);
return retBitmap;
}
else
{
return null;
}
} /// <summary>
/// 用二值数组新建一个1位二值图像。
/// </summary>
/// <param name="rawValues"> 二值数组(length = width * height)。 </param>
/// <param name="width"> 图像宽度。 </param>
/// <param name="height"> 图像高度。 </param>
/// <returns> 新建的1位二值位图。 </returns>
private static Bitmap twoBit(byte[] rawValues, int width, int height)
{
// 新建一个1位二值位图,并锁定内存区域操作
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
BitmapData bmpData = bitmap.LockBits(new Rectangle(, , width, height),
ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed); // 计算图像参数
int offset = bmpData.Stride - bmpData.Width / ; // 计算每行未用空间字节数
IntPtr ptr = bmpData.Scan0; // 获取首地址
int scanBytes = bmpData.Stride * bmpData.Height; // 图像字节数 = 扫描字节数 * 高度
byte[] grayValues = new byte[scanBytes]; // 为图像数据分配内存 // 为图像数据赋值
int posScan = ; // rawValues和grayValues的索引
for (int i = ; i < height; i++)
{
for (int j = ; j < bmpData.Width / ; j++)
{
grayValues[posScan] = rawValues[posScan];
posScan++;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
} // 内存解锁
Marshal.Copy(grayValues, , ptr, scanBytes);
bitmap.UnlockBits(bmpData); // 解锁内存区域 // 修改生成位图的索引表
ColorPalette palette;
// 获取一个Format8bppIndexed格式图像的Palette对象
using (Bitmap bmp = new Bitmap(, , PixelFormat.Format1bppIndexed))
{
palette = bmp.Palette;
}
for (int i = ; i < ; i = +)
{
palette.Entries[i] = Color.FromArgb(i, i, i);
}
// 修改生成位图的索引表
bitmap.Palette = palette; return bitmap;
}
#endregion

C#图片灰度处理(位深度24→位深度8),用灰度数组byte[]新建一个8位灰度图像Bitmap 。的更多相关文章

  1. C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)

    C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> / ...

  2. C#图片灰度处理(位深度24→位深度8)

    #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> /// <param name=&qu ...

  3. 图像转置的SSE优化(支持8位、24位、32位),提速4-6倍。

    一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...

  4. SSE图像算法优化系列四:图像转置的SSE优化(支持8位、24位、32位),提速4-6倍

    一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...

  5. 一位ML工程师构建深度神经网络的实用技巧

    一位ML工程师构建深度神经网络的实用技巧 https://mp.weixin.qq.com/s/2gKYtona0Z6szsjaj8c9Vg 作者| Matt H/Daniel R 译者| 婉清 编辑 ...

  6. Linux特殊权限位suid、sgid深度详细及实践

    特殊权限位基本说明: Linux系统基本权限位为9位权限,但还有额外3位权限位,共12位权限: suid    s(有x)     S    4   用户对应的权限位(用户对应的3位上) sgid  ...

  7. 怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图?

      分类: OpenCV [Q1]怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图? 进行灰度化,IplImage* pImg = cvLoadImage( "C:\\1.b ...

  8. 第16章 调色板管理器_16.4 一个DIB位图库的实现(1)

    16.4.1自定义的 DIBSTRUCT结构体 字段 含义 PBYTE *ppRow ①指向位图视觉上最上面的一行像素.(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问 ...

  9. 64位平台支持大于2 GB大小的数组

    64位平台支持大于2 GB大小的数组 64位平台.NET Framework数组限制不能超过2GB大小.这种限制对于需要使用到大型矩阵和向量计算的工作人员来说,是一个非常大问题. 无论RAM容量有多大 ...

随机推荐

  1. 【hdu 1527】取石子游戏

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...

  2. java 替换json字符串中间的引号保留两边的引号,避免json校验失败

    一.json概要 JSON(JavaScript Object Notation, JS 对象标记)-一种轻量级的数据交换标准(相对xml),独立于编程语言.具体以逗号分隔的key:value键值对的 ...

  3. 高CPU、数据库无法读写

    高CPU.数据库无法读写的真凶   有兴趣的同学可以参考如下系列文章,都是针对dump分析的实战和总结: Windbg DUMP分析(原创汇总) http://www.cnblogs.com/Love ...

  4. asp.net webform中的ext.net使用

    ext.net是对ext.js进行封装的net控件库,能够砸webform 和mvc中使用,从今天器我会对这一年多的ext.net开发进行一些对应的总结. 首先针对ext.net进行引用: <% ...

  5. Java冒泡排序与直接选择排序代码随笔

    冒泡排序:延申的有很多种,有的是先确定最大值放到后面,有的是先确定最小值放到前边,还有就是反过来,先确定最小值的位置,但是本质都是:不断两两比较,交换位置...第一趟确定一个最大(最小)值放到前边(后 ...

  6. js Map 遍历

    1. 在知道的key的情况下遍历map自然就跟数组一样的访. 2.在不知道key的情况下遍历map(此情况更多吧)    2.1  for(var key in Map){  };  //第一种   ...

  7. 美国是一个"愚蠢而落后的国度"--大家千万别去

    看到一篇文章,写的很诙谐风趣,已经被转载无数遍但却不知道原出处.读过之后又值得我们深思.和大家一起分享: 来美国已多时了.我后悔当初的选择.一直都被西方媒体所蒙蔽欺骗,让我错误地以为美国是一个现代化国 ...

  8. Android开发者的演示工具——asm.jar

    作为Android开发者,我们有时候需要给客户或者其他人演示我们的Android作品.我们可以使用类似豌豆荚.360手机助手这样的软件,今天我来介绍一个Android开发者的演示工具--asm.jar ...

  9. Windows下curl使用

    一.简介 在上一篇中我们涉及到了一个在Ubuntu下使用的curl命令,而且使用这个命令来模拟server的功能来向谷歌的C2DMserver发送数据. 以下简单的来说下在Windows下相同的使用c ...

  10. 反编译Jar包

    Jar 包(Java Archive)是对 Java 程序的打包,它可能包含源码,也可能没有. 对于有包含源码的 Jar 包,在 Eclipse 工程里设定好 source code 路径后能直接查看 ...