C#图片灰度处理(位深度24→位深度8),用灰度数组byte[]新建一个8位灰度图像Bitmap 。
#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 。的更多相关文章
- C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)
C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> / ...
- C#图片灰度处理(位深度24→位深度8)
#region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> /// <param name=&qu ...
- 图像转置的SSE优化(支持8位、24位、32位),提速4-6倍。
一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...
- SSE图像算法优化系列四:图像转置的SSE优化(支持8位、24位、32位),提速4-6倍
一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...
- 一位ML工程师构建深度神经网络的实用技巧
一位ML工程师构建深度神经网络的实用技巧 https://mp.weixin.qq.com/s/2gKYtona0Z6szsjaj8c9Vg 作者| Matt H/Daniel R 译者| 婉清 编辑 ...
- Linux特殊权限位suid、sgid深度详细及实践
特殊权限位基本说明: Linux系统基本权限位为9位权限,但还有额外3位权限位,共12位权限: suid s(有x) S 4 用户对应的权限位(用户对应的3位上) sgid ...
- 怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图?
分类: OpenCV [Q1]怎么样用opencv将彩色图片转化成像素值只有0和255的灰度图? 进行灰度化,IplImage* pImg = cvLoadImage( "C:\\1.b ...
- 第16章 调色板管理器_16.4 一个DIB位图库的实现(1)
16.4.1自定义的 DIBSTRUCT结构体 字段 含义 PBYTE *ppRow ①指向位图视觉上最上面的一行像素.(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问 ...
- 64位平台支持大于2 GB大小的数组
64位平台支持大于2 GB大小的数组 64位平台.NET Framework数组限制不能超过2GB大小.这种限制对于需要使用到大型矩阵和向量计算的工作人员来说,是一个非常大问题. 无论RAM容量有多大 ...
随机推荐
- 小强的HTML5移动开发之路(35)——jQuery中的过滤器详解
1.基本过滤选择器 :first :last :not(selector) :selector匹配的节点之外的节点 :even :偶数 :odd :奇数 :eq(index) :gt(index) : ...
- WPF中自动增加行(动画)的TextBox
原文:WPF中自动增加行(动画)的TextBox WPF中自动增加行(动画)的TextBox WPF中的Textbox控件是可以自动换行的,只要设置TextWrapping属性为"Wrap& ...
- 无法写入预编译头文件,由于 IO 设备错误,无法运行此项请求的错误的解决
作者:朱金灿 来源:http://blog.csdn.net/clever101 早上查看服务器每日构建的情况,发现出现一个诡异的错误: fatal error C1085: 无法写入预编译头文件:& ...
- Docker + .NET Core(二)
原文:Docker + .NET Core(二) 前言: 环境:centos7.5 64 位 正文: 首先我们在宿主机上安装 .NET Core SDK sudo rpm --import https ...
- 【u115】&&【t031】 01迷宫
01迷宫(maze01) Time Limit: 1 second Memory Limit: 128 MB [问题描述] 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相 ...
- sparksql hive作为数据源
根据官方文档的说法,要把hive-site.xml,core-site.xml,hdfs-site.xml拷贝到spark的conf目录下,保证mysql已经启动 java public class ...
- 【30.00%】【vijos 1909】寻找道路
描述 在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到 终点的路径,该路径满足以下条件: 路径上的所有点的出边所指向的点都直接或间接与终点连通. 在满足条件 1 的情 ...
- WPF 插拔触摸设备触摸失效
原文:WPF 插拔触摸设备触摸失效 最近使用 WPF 程序,在不停插拔触摸设备会让 WPF 程序触摸失效.通过分析 WPF 源代码可以找到 WPF 触摸失效的原因. 在 Windows 会将所有的 H ...
- Linux四个常用的指挥机关处理具体的解释
原版的Blog.转载请注明出处 http://blog.csdn.net/hello_hwc?viewmode=contents 权限 对于文件 r 可读 w 可写 x 可运行 对于文件夹 r 能够列 ...
- VSCode 小鸡汤 第00期 —— 安装和入门
简介 这将是一个新的系列,将会以 Visual Studio Code(后文都简称为 VSCode 啦)的操作,环境配置,插件介绍为主,为大家不定期的介绍 VSCode 的一些操作技巧,所以取名 VS ...