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)的更多相关文章
- C#图片灰度处理(位深度24→位深度8),用灰度数组byte[]新建一个8位灰度图像Bitmap 。
原文:C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> ...
- C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)
C#图片灰度处理(位深度24→位深度8) #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> / ...
- 图像转置的SSE优化(支持8位、24位、32位),提速4-6倍。
一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...
- SSE图像算法优化系列四:图像转置的SSE优化(支持8位、24位、32位),提速4-6倍
一.前言 转置操作在很多算法上都有着广泛的应用,在数学上矩阵转置更有着特殊的意义.而在图像处理上,如果说图像数据本身的转置,除了显示外,本身并无特殊含义,但是在某些情况下,确能有效的提高算法效率,比如 ...
- MD5值转换(Hex 32位 <-> base64 24位)
关于MD5值的原理本文不在介绍,本文主要介绍MD5值的两种编码的相互转换(32位和BASE64编码的24位),实际应用过程中经常会涉及到两种编码的相互转换.快熟使用工具tomeko.net. C#示例 ...
- C#保存图片到文件夹区分8位和24位
1.保存图像--24位位图(显示的图像,包括增加结果到界面上的数据) Image image2 = default(Image); image2 = cogRecordDisplay1.CreateC ...
- 怎么把PNG图的位深度24位变成32位
在PS里把图片的变成层模式,不透明度设置成99%,在保存成PNG
- 颜色模式中8位,16位,24位,32位色彩是什么意思?会有什么区别?计算机颜色格式( 8位 16位 24位 32位色)<转>
颜色模式中8位,16位,24位,32位色彩是什么意思?会有什么区别简单地说这里说的位数和windows系统显示器设置中的颜色位数是一样的.表示的是能够显示出来的颜色的多少. 8位的意思是说,能够显示出 ...
- C# AES的128位、192位、256位加密
C# AES的128位.192位.256位加密 AES加密原理,这里就不解释了,自行百度.这里主要细说AES的CBC加密模式下的128位.192位.256位加密区别,参考 对称加密和分组加密中的四 ...
随机推荐
- TensorFlow 学习(十四)—— contrib
1. tensorflow.contrib.layers tf.contrib.layers.xavier_initializer():一种经典的权值矩阵的初始化方式:
- AJAX代码格式
var request; //XMLHttpRequest的创建 function createRequest(url){ if(window.XMLHttpRequest){ request = n ...
- 初始化NSDictionary:(工作经验)两种方法有时候效果不一样
方法1: NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; [dic setObject:[Hp_KeysArray obj ...
- SQL Server 存储过程之嵌套游标
下面是一个订单取消的含2个游标的存储过程 set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go ALTER PROCEDURE [dbo].[CancelOrde ...
- PAT 1061 - 1064 题解
这四道题来自 13 年 08 月 30 的 PAT 测试. 代码量不大,思路也比较直接.不过第一题的处理逻辑不太清晰,需要好好把握.稍有不慎就掉进坑里了(很多人被这道 20'的题坑了一个多小时心慌意乱 ...
- go-wingui 2018 全新 v2.0 版本发布,包含重大更新!
go-wingui 2018 全新 v2.0 版本发布,包含重大更新!使用新版CEF内核Chromium 63.0.3239.109,页面可以使用最新的css3,html5技术.使用delphi7重写 ...
- C++ Lambda表达式基本用法(言简意赅,非常清楚)
创建一个匿名函数并执行.Objective-C采用的是上尖号^,而C++ 11采用的是配对的方括号[].实例如下: 1 2 3 4 5 6 7 8 9 #include <iostream> ...
- 获取浏览器的ip以及省份
<script src="http://pv.sohu.com/cityjson?ie=utf-8"></script> <script type=& ...
- uva 11892 - ENimEN(推理)
题目链接:uva 11892 - ENimEN 题目大意:给定n堆石子的个数,两人轮流选择石子堆取石子,直到不能取为失败,附加条件,假设前一次操作,即队手的操作,没有将选中石子堆中的石子取完,那么当前 ...
- HDU-4249-A Famous Equation(DP)
Problem Description Mr. B writes an addition equation such as 123+321=444 on the blackboard after cl ...