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处理确实比較方便.毕竟是非常多东西都封装好的.可是要研究里面的东西,还是比較麻烦的,首先,你得知道图片处理的一些知识,比方腐蚀,膨胀,仿射,透射等,还有非常多 ...
随机推荐
- webdispatch配置
PRDPISP01:/sapmnt/WIP/profile # su - wipadm PRDPISP01:wipadm 23> cdpro PRDPISP01:wipadm 24> ls ...
- UICollectionViewLayout详解,文档翻译
实现一个UICollectionView,和UITableView类似,不过初始化的时候要传入一个UICollectionViewLayout. 苹果给UIcollectionview中的所有视图都来 ...
- sql将查询结果的某个字段赋值给另一个字段
Update a set a.NickName=b.name FROM AccountsInfo a, TT b where a.UserID=b.userId 必须要有关联的两个表
- sql 四舍五入 保留两位小数
一.问题描述 数据库里的 float momey 类型,都会精确到多位小数.但有时候 我们不需要那么精确,例如,只精确到两位有效数字. 二.sqlserver解决方案: 1. 使用 Round() 函 ...
- nginx: [emerg] directive "upstream" has no opening "{" in /application/nginx-1.6.3/conf/nginx.conf:13 ...
修改nginx.conf配置文件时,报以下错误: [root@bqh-lb- nginx]# vim conf/nginx.conf [root@bqh-lb- nginx]# sbin/nginx ...
- py-2 python介绍与安装
一.python介绍 1.python背景 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Py ...
- HTML的BODY内标签介绍
一.基本标签 <body> <b>加粗</b> <i>斜体</i> <u>下划线</u> <s>删除线& ...
- OpenStack环境搭建
实验环境 CentOS-7-x86_64-Minimal-1708.iso openstack_N.tar.gz 创建虚拟机 controller部署 computer网络配置 OpenStack环境 ...
- TCP的三次握手和四次挥手与路由器(三层)转发原理
传输层是国际标准化组织提出的开放系统互连(OSI)参考模型中的第四层.该层协议为网络端点主机上的进程之间提供了可靠.有效的报文传送服务.其功能紧密地依赖于网络层的虚拟电路或数据报服务.传输层定义了主机 ...
- k8s的监控
监控 1.资源指标和资源监控 一个集群系统管理离不开监控,同样的Kubernetes也需要根据数据指标来采集相关数据,从而完成对集群系统的监控状况进行监测.这些指标总体上分为两个组成:监控集群本身和监 ...