C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)
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 二值化
#region Otsu阈值法二值化模块
/// <summary>
/// Otsu阈值
/// </summary>
/// <param name="b">位图流</param>
/// <returns></returns>
public Bitmap OtsuThreshold()
{
// 图像灰度化
// b = Gray(b);
int width = bitmap.Width;
int height = bitmap.Height;
byte threshold = ;
int[] hist = new int[];
int AllPixelNumber = , PixelNumberSmall = , PixelNumberBig = ;
double MaxValue, AllSum = , SumSmall = , SumBig, ProbabilitySmall, ProbabilityBig, Probability;
BitmapData bmpData = bitmap.LockBits(new Rectangle(, , width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)bmpData.Scan0;
int offset = bmpData.Stride - width * ;
for (int j = ; j < height; j++)
{
for (int i = ; i < width; i++)
{
hist[p[]]++;
p += ;
}
p += offset;
}
bitmap.UnlockBits(bmpData);
}
//计算灰度为I的像素出现的概率
for (int i = ; i < ; i++)
{
AllSum += i * hist[i]; // 质量矩
AllPixelNumber += hist[i]; // 质量
}
MaxValue = -1.0;
for (int i = ; i < ; i++)
{
PixelNumberSmall += hist[i];
PixelNumberBig = AllPixelNumber - PixelNumberSmall;
if (PixelNumberBig == )
{
break;
}
SumSmall += i * hist[i];
SumBig = AllSum - SumSmall;
ProbabilitySmall = SumSmall / PixelNumberSmall;
ProbabilityBig = SumBig / PixelNumberBig;
Probability = PixelNumberSmall * ProbabilitySmall * ProbabilitySmall + PixelNumberBig * ProbabilityBig * ProbabilityBig;
if (Probability > MaxValue)
{
MaxValue = Probability;
threshold = (byte)i;
}
}
this.Threshoding(bitmap, threshold);
bitmap = twoBit(bitmap);
return bitmap; ;
}
#endregion
#region 固定阈值法二值化模块
public Bitmap Threshoding(Bitmap b, byte threshold)
{
int width = b.Width;
int height = b.Height;
BitmapData data = b.LockBits(new Rectangle(, , width, height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
unsafe
{
byte* p = (byte*)data.Scan0;
int offset = data.Stride - width * ;
byte R, G, B, gray;
for (int y = ; y < height; y++)
{
for (int x = ; x < width; x++)
{
R = p[];
G = p[];
B = p[];
gray = (byte)((R * + G * + B * ) >> );
if (gray >= threshold)
{
p[] = p[] = p[] = ;
}
else
{
p[] = p[] = p[] = ;
}
p += ;
}
p += offset;
}
b.UnlockBits(data);
return b;
}
}
#endregion
#region 创建1位图像
/// <summary>
/// 创建1位图像
/// </summary>
/// <param name="srcBitmap"></param>
/// <returns></returns>
public Bitmap twoBit(Bitmap srcBitmap)
{
int midrgb = Color.FromArgb(, , ).ToArgb();
int stride;//简单公式((width/8)+3)&(~3)
stride = (srcBitmap.Width % ) == ? (srcBitmap.Width / ) : (srcBitmap.Width / ) + ;
stride = (stride % ) == ? stride : ((stride / ) + ) * ;
int k = srcBitmap.Height * stride;
byte[] buf = new byte[k];
int x = , ab = ;
for (int j = ; j < srcBitmap.Height; j++)
{
k = j * stride;//因图像宽度不同、有的可能有填充字节需要跳越
x = ;
ab = ;
for (int i = ; i < srcBitmap.Width; i++)
{
//从灰度变单色(下法如果直接从彩色变单色效果不太好,不过反相也可以在这里控制)
if ((srcBitmap.GetPixel(i, j)).ToArgb() > midrgb)
{
ab = ab * + ;
}
else
{
ab = ab * ;
}
x++;
if (x == )
{
buf[k++] = (byte)ab;//每字节赋值一次,数组buf中存储的是十进制。
ab = ;
x = ;
}
}
if (x > )
{
//循环实现:剩余有效数据不满1字节的情况下须把它们移往字节的高位部分
for (int t = x; t < ; t++) ab = ab * ;
buf[k++] = (byte)ab;
}
}
int width = srcBitmap.Width;
int height = srcBitmap.Height;
Bitmap dstBitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
BitmapData dt = dstBitmap.LockBits(new Rectangle(, , dstBitmap.Width, dstBitmap.Height), ImageLockMode.ReadWrite, dstBitmap.PixelFormat);
Marshal.Copy(buf, , dt.Scan0, buf.Length);
dstBitmap.UnlockBits(dt);
return dstBitmap;
}
#endregion
#endregion
C#图片灰度处理(位深度24→位深度8)、C#图片二值化处理(位深度8→位深度1)的更多相关文章
- 深度学习实践-强化学习-bird游戏 1.np.stack(表示进行拼接操作) 2.cv2.resize(进行图像的压缩操作) 3.cv2.cvtColor(进行图片颜色的转换) 4.cv2.threshold(进行图片的二值化操作) 5.random.sample(样本的随机抽取)
1. np.stack((x_t, x_t, x_t, x_t), axis=2) 将图片进行串接的操作,使得图片的维度为[80, 80, 4] 参数说明: (x_t, x_t, x_t, x_t) ...
- python的N个小功能(图片预处理:打开图片,滤波器,增强,灰度图转换,去噪,二值化,切割,保存)
############################################################################################# ###### ...
- c#数字图像处理(二)彩色图像灰度化,灰度图像二值化
为加快处理速度,在图像处理算法中,往往需要把彩色图像转换为灰度图像,在灰度图像上得到验证的算法,很容易移植到彩色图像上.24位彩色图像每个像素用3个字节表示,每个字节对应着R.G.B分量的亮度(红.绿 ...
- 致敬学长!J20航模遥控器开源项目计划【开局篇】 | 先做一个开机界面 | MATLAB图像二值化 | Img2Lcd图片取模 | OLED显示图片
我们的开源宗旨:自由 协调 开放 合作 共享 拥抱开源,丰富国内开源生态,开展多人运动,欢迎加入我们哈~ 和一群志同道合的人,做自己所热爱的事! 项目开源地址:https://github.com/C ...
- c#实现图片二值化例子(黑白效果)
C#将图片2值化示例代码,原图及二值化后的图片如下: 原图: 二值化后的图像: 实现代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 ...
- [iOS OpenCV的使用,灰度和二值化]
看网上方法很多,但版本都不够新,我看了网上一些知识,总结了下,来个最新版Xcode6.1的. 最近主要想做iOS端的车牌识别,所以开始了解OpenCV.有兴趣的可以跟我交流下哈. 一.Opencv的使 ...
- java 图像灰度化与二值化
转载:http://www.chinasb.org/archives/2013/01/5053.shtml 1: package org.chinasb.client; 2: 3: import ja ...
- [置顶] c#验证码识别、图片二值化、分割、分类、识别
c# 验证码的识别主要分为预处理.分割.识别三个步骤 首先我从网站上下载验证码 处理结果如下: 1.图片预处理,即二值化图片 *就是将图像上的像素点的灰度值设置为0或255. 原理如下: 代码如下: ...
- Opencv实现图像的灰度处理,二值化,阀值选择
前几天接触了图像的处理,发现用OPencv处理确实比較方便.毕竟是非常多东西都封装好的.可是要研究里面的东西,还是比較麻烦的,首先,你得知道图片处理的一些知识,比方腐蚀,膨胀,仿射,透射等,还有非常多 ...
随机推荐
- SVM-支持向量机总结
一.SVM简介 (一)Support Vector Machine 支持向量机(SVM:Support Vector Machine)是机器学习中常见的一种分类算法. 线性分类器,也可以叫做感知机,其 ...
- nginx的proxy模块详解以及参数
文章来源 运维公会:nginx的proxy模块详解以及参数 使用nginx配置代理的时候,肯定是要用到http_proxy模块.这个模块也是在安装nginx的时候默认安装.它的作用就是将请求转发到相应 ...
- 安装配置nginx之后访问不了nginx的问题
我刚开通的服务器,没有设置安全组规则. 进入云服务控制台 配置规则 其他不要动,授权对象加0.0.0.0/0 就可以访问nginx了
- git pull 的时候 把本地的修改 覆盖远程端
首先,git pull 可以分成两步,git fetch 和git merge 使用git branch -a可以看出来 git merge 相当于当前分支 和 origin/master分支 ...
- 【OF框架】在Azure DevOps中配置项目持续集成CI服务,推送镜像到Azure容器注册表
准备工作 开通Azure账号,具有开通服务权限,关键是里面要有钱. 开通Azure DevOps,能够创建组织和项目. 具备一定的DevOps知识,了解CICD概念.Docker基本操作. 一.创建& ...
- rabbitmq rabbitmqadmin基本操作
一.下载管理命令 http://192.168.56.12:15672/cli/rabbitmqadmin 二.上传到mq对应服务器并添加权限 chmod +x /usr/locat/sbin/rab ...
- 【基础搜索】poj-2676-Sudoku(数独)--求补全九宫格的一种合理方案
数独 时限:2000 MS 内存限制:65536K 提交材料共计: 22682 接受: 10675 特别法官 描述 数独是一个非常简单的任务.一个9行9列的正方形表被分成9个较小的3x ...
- HTTP 状态码(常见及分析)
首先得明白状态码的几个大类: 状态码 响应类别 出现原因 1XX 信息性状态码(Informational) 服务器正在处理请求 2XX 成功状态码(Success) 请求已正常处理完毕 3XX 重定 ...
- JDK源码那些事儿之LinkedBlockingQueue
今天继续讲解阻塞队列,涉及到了常用线程池的其中一个队列LinkedBlockingQueue,从类命名部分我们就可以看出其用意,队列中很多方法名是通用的,只是每个队列内部实现不同,毕竟实现的都是同一个 ...
- el-input 只能输入数字并限制长度
在上一个博客中,有关于限制长度的使用,本文介绍限制只能输入数字的方法 el-input 代码如下: <el-form-item label="账号" required> ...