x01.BitmapHelper:图像处理
“所有致我于死地的,也激发我胆魄”,姚贝娜的《心火》,是我近年来听过最好的歌,特此推荐一下。
图像处理,大概分三步:1.LockBits();2.进行处理;3.UnlockBits();这比起 C++ 来,不知清爽几许?
编程,是为了满足人的需求,所以进行灰度处理时,不是简单的 (r + g + b) / 3,而是分别乘以合适的比例值,r * 0.30 + g * 0.59 + b * 0.11。这是因为人眼对 green 最敏感,red 次之,blue 最低。
只实现了灰度处理,边缘提取,二值化,缩小,Rotate 等有限功能,代码不言自明,无需多说。
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text; namespace x01.Utilities
{
public static class BitmapHelper
{
/// <summary>
/// 对 bitmap 进行灰度处理。r,g,b 权重相加为 1。
/// </summary>
/// <param name="bmp">所要处理的 bitmap 对象。</param>
/// <param name="rWeight">red 权重。</param>
/// <param name="gWeight">green 权重。</param>
/// <param name="bWeight">blue 权重。</param>
public static void Gray(Bitmap bmp, float rWeight = 0.30f, float gWeight = 0.59f, float bWeight = 0.11f)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length);
for (int y = ; y < bmp.Height * data.Stride; y += data.Stride)
{
for (int x = ; x < bmp.Width * ; x += )
{
int i = y + x;
byte b = buf[i];
byte g = buf[i + ];
byte r = buf[i + ];
buf[i] = buf[i + ] = buf[i + ] = (byte)(b * bWeight + g * gWeight + r * rWeight);
}
}
Marshal.Copy(buf, , data.Scan0, buf.Length);
bmp.UnlockBits(data);
} /// <summary>
/// 对 bitmap 进行中值滤波处理。
/// </summary>
/// <param name="bmp">所要处理的 bitmap 对象。</param>
public static void MedianFilter(Bitmap bmp)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
unsafe
{
byte* pBuf = (byte*)data.Scan0.ToPointer();
for (int i = ; i < bmp.Height - ; i++)
{
for (int j = ; j < bmp.Width - ; j++)
{
List<byte>[] list = new List<byte>[];
for (int k = ; k < ; k++)
{
list[k] = new List<byte>();
} for (int y = -; y < ; y++)
{
for (int x = -; x < ; x++)
{
int index = (i + y) * data.Stride + (j + x) * ;
for (int k = ; k < ; k++)
{
list[k].Add(pBuf[index + k]);
}
}
} for (int k = ; k < ; k++)
{
list[k].Sort();
} int indexMedian = i * data.Stride + j * ; for (int k = ; k < ; k++)
{
pBuf[indexMedian + k] = list[k][]; // 4: median value after sort.
list[k].Clear();
} list = null;
}
}
} bmp.UnlockBits(data);
} /// <summary>
/// 获取 bitmap 所选的颜色分量直方图。
/// </summary>
/// <param name="bmp">所要处理的 bitmap 对象</param>
/// <param name="bgrOffset">所选的颜色: blue=0, green=1, red=2</param>
/// <returns>返回 256 * 256 大小的 Bitmap 直方图。</returns>
public static Bitmap Histogram(Bitmap bmp, int bgrOffset = )
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); int[] countColors = new int[];
for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ;
countColors[buf[index + bgrOffset]]++;
}
} bmp.UnlockBits(data); int maxIndex = ;
for (int i = ; i < ; i++)
{
if (countColors[maxIndex] < countColors[i])
{
maxIndex = i;
}
} Bitmap hist = new Bitmap(, );
Graphics g = Graphics.FromImage(hist);
g.Clear(Color.Wheat);
for (int i = ; i < ; i++)
{
int h = * countColors[i] / countColors[maxIndex];
g.DrawLine(new Pen(Color.FromArgb(i, i, i), 1f), i, , i, - h); // top bottom inverse
} return hist;
} public static void ExtractEdge(Bitmap bmp)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
byte[] edge = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); for (int y = ; y < bmp.Height - ; y++)
{
for (int x = ; x < bmp.Width - ; x++)
{
int index = y * data.Stride + x * ;
byte gray = (byte)((buf[index] + buf[index + ] + buf[index + ]) / ); int value = ;
for (int i = -; i < ; i++) // neareat eight point
{
for (int j = -; j < ; j++)
{
if (i == && j == )
{
continue;
} int index2 = (y + i) * data.Stride + (x + i) * ;
byte gray2 = (byte)((buf[index2] + buf[index2 + ] + buf[index2 + ]) / );
value += Math.Abs(gray - gray2);
}
} edge[index] = edge[index + ] = edge[index + ] = (byte)(value >> );
}
} Marshal.Copy(edge, , data.Scan0, edge.Length);
bmp.UnlockBits(data);
} /// <summary>
/// 对图像进行二值化处理。
/// </summary>
/// <param name="bmp">处理的图像。</param>
/// <param name="minValue">最小阀值。</param>
/// <param name="maxValue">最大阀值。</param>
public static void Binary(Bitmap bmp, int minValue, int maxValue)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ;
int gray = (buf[index] + buf[index+] +buf[index+])/;
if (gray >= minValue && gray <= maxValue)
{
buf[index] = buf[index + ] = buf[index + ] = ;
}
else
{
buf[index] = buf[index + ] = buf[index + ] = ;
}
}
} Marshal.Copy(buf, , data.Scan0, buf.Length);
bmp.UnlockBits(data);
} /// <summary>
/// 对灰度图像进行对比度增强。
/// </summary>
/// <param name="bmp">灰度图像</param>
/// <param name="srcMin">原灰度下界</param>
/// <param name="srcMax">原灰度上界</param>
/// <param name="destMin">目标灰度下界</param>
/// <param name="destMax">目标灰度上界</param>
public static void Enhance(Bitmap bmp, int srcMin, int srcMax, int destMin, int destMax)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ;
int gray = (buf[index] + buf[index + ] + buf[index + ]) / ;
float value = (float)(destMax - destMin) / (srcMax - srcMin) * (gray - srcMin) + destMin;
buf[index] = buf[index + ] = buf[index + ] =
value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
}
} Marshal.Copy(buf, , data.Scan0, buf.Length); bmp.UnlockBits(data);
} public static void Enhance(Bitmap bmp, float n)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ;
int gray = (buf[index] + buf[index + ] + buf[index + ]) / ;
float value = gray * n;
buf[index] = buf[index + ] = buf[index + ] =
value < byte.MinValue ? byte.MinValue : (value > byte.MaxValue ? byte.MaxValue : (byte)value);
}
} Marshal.Copy(buf, , data.Scan0, buf.Length);
bmp.UnlockBits(data);
} public static void ConnectRegion(Bitmap bmp)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); int sign = ;
for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ;
if (buf[index] == )
{
SignRegion(buf, x * , y * data.Stride, sign, data.Stride, bmp.Width, bmp.Height);
sign += ;
}
}
} Marshal.Copy(buf, , data.Scan0, buf.Length);
bmp.UnlockBits(data);
} public static void SignRegion(byte[] buf, int x, int y, int sign, int stride, int width, int height)
{
int index = x + y;
buf[index] = buf[index + ] = buf[index + ] = (byte)sign; if (x > && buf[index -] == ) // left
{
SignRegion(buf, x - , y, sign, stride, width, height);
} if (x < width * - && buf[index + ] == ) // right
{
SignRegion(buf, x + , y, sign, stride, width, height);
} if (y > && buf[index - stride] == ) // top
{
SignRegion(buf, x, y - stride, sign, stride, width, height);
} if (y < height * stride && buf[index + stride] == ) // bottom
{
SignRegion(buf, x, y + stride, sign, stride, width, height);
} } /// <summary>
/// 缩小图像。
/// </summary>
/// <param name="bmp">图像</param>
/// <param name="widthFactor">宽度缩小倍数</param>
/// <param name="heightFactor">高度缩小倍数</param>
public static void Dilation(Bitmap bmp, float widthFactor, float heightFactor)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); byte[] result = new byte[data.Stride * bmp.Height];
for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ; int rx = (int)(x * widthFactor);
int ry = (int)(y * heightFactor);
if (rx < || rx >= bmp.Width || ry < || ry >= bmp.Height)
{
continue;
}
int rindex = ry * data.Stride + rx * ; result[index] = buf[rindex];
result[index + ] = buf[rindex + ];
result[index + ] = buf[rindex + ];
}
} Marshal.Copy(result, , data.Scan0, result.Length);
bmp.UnlockBits(data);
} public static void Translate(Bitmap bmp, int xOffset, int yOffset)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); byte[] result = new byte[data.Stride * bmp.Height];
for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ; int rx = x - xOffset;
int ry = y - yOffset;
if (rx < || rx >= bmp.Width || ry < || ry >= bmp.Height)
{
continue;
}
int rindex = ry * data.Stride + rx * ; result[index] = buf[rindex];
result[index + ] = buf[rindex + ];
result[index + ] = buf[rindex + ];
}
} Marshal.Copy(result, , data.Scan0, result.Length);
bmp.UnlockBits(data);
} public static void Rotate(Bitmap bmp, float angle, Point center)
{
BitmapData data = bmp.LockBits(new Rectangle(new Point(), bmp.Size), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] buf = new byte[data.Stride * bmp.Height];
Marshal.Copy(data.Scan0, buf, , buf.Length); byte[] result = new byte[data.Stride * bmp.Height];
for (int y = ; y < bmp.Height; y++)
{
for (int x = ; x < bmp.Width; x++)
{
int index = y * data.Stride + x * ; int rx = (int)( (x - center.X) * Math.Cos(angle * Math.PI / )
- (y - center.Y) * Math.Sin(angle * Math.PI / ) + center.X );
int ry = (int)( (x - center.X) * Math.Sin(angle * Math.PI / )
+ (y - center.Y) * Math.Cos(angle * Math.PI / ) + center.Y ); if (rx < || rx >= bmp.Width || ry < || ry >= bmp.Height)
{
continue;
}
int rindex = ry * data.Stride + rx * ; result[index] = buf[rindex];
result[index + ] = buf[rindex + ];
result[index + ] = buf[rindex + ];
}
} Marshal.Copy(result, , data.Scan0, result.Length);
bmp.UnlockBits(data);
}
}
}
BitmapHelper
如果要处理图像,Paint.Net 是款不错的软件。
x01.BitmapHelper:图像处理的更多相关文章
- x01.os.12: 在 windows 中写 OS
在 windows 中写操作系统,需要一系列的辅助工具.在此,要感谢川谷秀实!所有工具,都在 z_tools 文件夹中.有了大师的帮助,不妨也来尝试在 windows 中写一把 OS. 源代码及工具可 ...
- Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉
Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉 1.1. 按照当前流行的分类方法,可以分为以下三部分:三部分 图像处理 图像分析 计算机视觉1 1.2. 图像处理需要 ...
- Atitit 图像处理的摩西五经attilax总结
Atitit 图像处理的摩西五经attilax总结 1. 数字图像处理(第三版)1 2. 图像处理基础(第2版)(世界著名计算机教材精选)1 3. 计算机视觉特征提取与图像处理(第三版)2 4. Op ...
- Atitit 图像处理的心得与疑惑 attilax总结
Atitit 图像处理的心得与疑惑 attilax总结 1.1. 使用类库好不好??还是自己实现算法1 1.2. 但是,如果遇到类库体积太大,后者没有合适的算法,那就只能自己开发算法了1 1.3. 如 ...
- Atitit 图像处理 调用opencv 通过java api attilax总结
Atitit 图像处理 调用opencv 通过java api attilax总结 1.1. Opencv java api的支持 opencv2.4.2 就有了对java api的支持1 1. ...
- Atitit MATLAB 图像处理 经典书籍attilax总结
Atitit MATLAB 图像处理 经典书籍attilax总结 1.1. MATLAB数字图像处理1 1.2. <MATLAB实用教程(第二版)>((美)穆尔 著)[简介_书评_在线阅读 ...
- Atitit 图像处理类库大总结attilax qc20
Atitit 图像处理类库大总结attilax qc20 1.1. 选择与组合不同的图像处理类库1 1.2. Halcon 貌似商业工具,功能强大.1 1.3. Openvc Openvc功能也是比 ...
- Atitit MATLAB 图像处理attilax总结
Atitit MATLAB 图像处理attilax总结 1.1. 下载 Matlab7.0官方下载_Matlab2012 v7.0 官方简体中文版-办公软件-系统大全.html1 1.2. Matla ...
- 使用MATLAB对图像处理的几种方法(下)
试验报告 一.试验原理: 图像点处理是图像处理系列的基础,主要用于让我们熟悉Matlab图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操作,直方图是对像素灰度值的统计,直方图均衡是对 ...
随机推荐
- 三层架构与MVC之间的区别
文章转发自:http://www.admin10000.com/document/535.html 我们平时总是将三层架构与MVC混为一谈,殊不知它俩并不是一个概念.下面我来为大家揭晓我所知道的一些真 ...
- PDF.NET SOD 开源框架红包派送活动 && 新手快速入门指引
一.框架的由来 快速入门 有关框架的更多信息,请看框架官方主页! 本套框架的思想是借鉴Java平台的Hibernate 和 iBatis 而来,兼有ORM和SQL-MAP的特性,同时还参考了后来.N ...
- C#微信公众平台开发者模式开启代码
using System;using System.IO;using System.Text;using System.Web.Security; namespace HPZJ.Web.sys.exc ...
- Spring4学习笔记 - 配置Bean - 自动装配 关系 作用域 引用外部属性文件
1 Autowire自动装配 1.1 使用:只需在<bean>中使用autowire元素 <bean id="student" class="com.k ...
- EasyDropDown – 很棒的下拉菜单,含精美主题
EasyDropDown 是一个 jQuery 插件,你可以毫不费力地将简陋的 Select 元素设置为可定制风格的下拉菜单,用于表单或者一般的导航.和著名的下拉插件 Chosen 很像,但是具有自己 ...
- 【CSS3】css3:box-sizing属性
本文介绍了css3中的box-sizing属性,在这之前读者需要预备知识width的范围. 浏览器的支持情况 Browser Suppored Notes Internet Explorer Yes ...
- react native 学习一(环境搭配和常见错误的解决)
react native 学习一(环境搭配) 首页,按照http://reactnative.cn/docs/0.30/getting-started.html#content上的介绍,下载安装pyt ...
- [deviceone开发]-百度地图do_BaiduMap的示例
一.简介 这个示例展示了百度地图的基本使用,并增加了一个自定义弹出的标示.这个标示是一个自定义的label,里面是地点的文字描述.因为这个组件需要根据应用app的包名去申请不同的key,所以提供一个可 ...
- User Profile Service Application 配置同步连接时,报 MOSS MA not found
最近在试着配置"我的网站",不知什么原因在配置同步连接时报:MOSS MA not found 搜索发现,需要启动Forefront Identity Manager Servic ...
- 如何查找SAP的事务代码清单
SAP系统中,为了省去输入程序名称等繁琐步骤,SAP提供一种命令,称作‘事务代码’,通过执行事务代码达到快速进入相应程序的目的.那么在系统中如何去查找事务代码,事务代码和程序的对应关系如何呢?我们可以 ...