“所有致我于死地的,也激发我胆魄”,姚贝娜的《心火》,是我近年来听过最好的歌,特此推荐一下。

图像处理,大概分三步: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:图像处理的更多相关文章

  1. x01.os.12: 在 windows 中写 OS

    在 windows 中写操作系统,需要一系列的辅助工具.在此,要感谢川谷秀实!所有工具,都在 z_tools 文件夹中.有了大师的帮助,不妨也来尝试在 windows 中写一把 OS. 源代码及工具可 ...

  2. Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉

    Atitit 图像处理和计算机视觉的分类 三部分 图像处理 图像分析 计算机视觉 1.1. 按照当前流行的分类方法,可以分为以下三部分:三部分 图像处理 图像分析 计算机视觉1 1.2. 图像处理需要 ...

  3. Atitit 图像处理的摩西五经attilax总结

    Atitit 图像处理的摩西五经attilax总结 1. 数字图像处理(第三版)1 2. 图像处理基础(第2版)(世界著名计算机教材精选)1 3. 计算机视觉特征提取与图像处理(第三版)2 4. Op ...

  4. Atitit 图像处理的心得与疑惑 attilax总结

    Atitit 图像处理的心得与疑惑 attilax总结 1.1. 使用类库好不好??还是自己实现算法1 1.2. 但是,如果遇到类库体积太大,后者没有合适的算法,那就只能自己开发算法了1 1.3. 如 ...

  5. Atitit 图像处理 调用opencv 通过java  api   attilax总结

    Atitit 图像处理 调用opencv 通过java  api   attilax总结 1.1. Opencv java api的支持 opencv2.4.2 就有了对java api的支持1 1. ...

  6. Atitit MATLAB 图像处理 经典书籍attilax总结

    Atitit MATLAB 图像处理 经典书籍attilax总结 1.1. MATLAB数字图像处理1 1.2. <MATLAB实用教程(第二版)>((美)穆尔 著)[简介_书评_在线阅读 ...

  7. Atitit 图像处理类库大总结attilax qc20

    Atitit 图像处理类库大总结attilax qc20 1.1. 选择与组合不同的图像处理类库1 1.2. Halcon 貌似商业工具,功能强大.1 1.3. Openvc  Openvc功能也是比 ...

  8. Atitit MATLAB 图像处理attilax总结

    Atitit MATLAB 图像处理attilax总结 1.1. 下载 Matlab7.0官方下载_Matlab2012 v7.0 官方简体中文版-办公软件-系统大全.html1 1.2. Matla ...

  9. 使用MATLAB对图像处理的几种方法(下)

     试验报告 一.试验原理: 图像点处理是图像处理系列的基础,主要用于让我们熟悉Matlab图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操作,直方图是对像素灰度值的统计,直方图均衡是对 ...

随机推荐

  1. Hibernate原生SQL查询

    最近在做一个较为复杂的查询,hibernate基本的查询不能满足,只好使用其提供的原生sql查询.参考网上的一些资料,做一些总结. 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行 ...

  2. CnBlogs自定义博客样式

    弄了半个晚上的时间,总算马马虎虎搞好了博客的样式. 整个博客是蓝色的基调,比较激情,我喜欢. 比较郁闷的是,rightmenu 和 main都是position:absolute 布局的.要添加一个f ...

  3. CentOS 6.5下Redis安装详细步骤

    Redis简介: Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工 ...

  4. Microsoft SQL Server Compact 4.0&&ADO.NET Entity Framework 4.1&&MVC3

    最近重新查看微软MvcMusicStore-v3.0的源代码,发现忽略了很多重要的东西,特别是数据访问那一部分. 首先Microsoft SQL Server Compact 4.0 详细的介绍和下载 ...

  5. bootstrap深入理解之格子布局

    一.源码文件: _grid.scss:格子系统类文件 Mixins/_grid.scss:支持格子系统实现的mixin集合 Mixins/_grid-framework.scss:格子系统实现的核心m ...

  6. 15款帮助你实现响应式导航的 jQuery 插件

    对于我们大多数人来说,建立一个负责任的布局中最困难的方面是规划和导航的实现.由于没有真正经得起考验的通用解决方案,您可以使用的菜单设计风格将取决于正在建设的网站类型. 无论你正在建设什么类型的网站,在 ...

  7. css居中完全指南(翻译)

    最近参加了百度的前端技术学院,任务4是要求一个元素在父元素中水平和垂直居中,提供的一篇文章对各种情况都进行了分析,很不错,英文也不是那么难懂,毕竟代码还是主体,翻译过来分享出来,翻译内容带有自己的理解 ...

  8. React入门--------顶层API

    React.createClass 参数:config(object) 创建一个ReactClass(组件类),参数是一个对象且必须带有render属性方法,该方法必须返回一个封闭的容器(容器内可以由 ...

  9. [deviceone开发]-echart的简单报表示例

    一.简介 echart是一个常用的基于h5的报表库.这个例子简单展示了实现折线图,柱状图,圆环图和圆饼图的使用. 并实现和do的非html部分的数据交互. 二.效果图 三.相关下载 https://g ...

  10. AloneJs —— 简洁高效的JavaScript UI库

    以前做项目时用了一些第三方的JS UI库,项目比较low的时候用还行,一旦项目要求比较高,特别是交互比较复杂时,某些第三方UI库就显得无能为力,用起来也不顺手,改也不好改,所以我就自己基于jQuery ...