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图像处理的编程环境.灰度线性变换和灰度拉伸是对像素灰度值的变换操作,直方图是对像素灰度值的统计,直方图均衡是对 ...
随机推荐
- 项目总结笔记系列 Maven Session1
主题:Maven 参考地址: 1.http://www.yiibai.com/maven/ 2.http://www.icoolxue.com/ 目录 1.环境搭建 2.pom.xml文件解析 3.m ...
- 通俗易懂地讲解TCP建立连接的三次握手和释放连接的四次挥手
TCP建立连接时,为什么要进行三次挥手? 每一次TCP连接都需要三个阶段:连接建立.数据传送和连接释放.三次握手就发生在连接建立阶段. 在谢希仁著<计算机网络>第四版中讲三次握手的目的是为 ...
- MySQL max_allowed_packet设置及问题
MySQL根据配置文件会限制server接受的数据包大小. 有时候大的插入和更新会被max_allowed_packet 参数限制掉,导致失败. 查看目前配置 show VARIABLES like ...
- Atom + activate-power-mode震屏插件Windows7下安装
Atom是Github推出的一个文本编辑器,搜索一下大概是给Web前端用的,最近比较火的是他的一个插件activate-power-mode,可以实现打字屏振效果. 用来装装逼还是挺适合的,本来想试试 ...
- 闭包和this
一.闭包 最开始理解闭包是在一个函数内部定义一个函数,可以在外面的环境里进行调用.现在对于闭包的理解是利用函数来保存作用域内的对象. 理解闭包首先要理解执行上下文,变量对象,活动对象,作用域链.因为执 ...
- 【zepto学习笔记03】事件机制
前言 我们今天直接进入事件相关的学习,因为近期可能会改到里面的代码就zepto来说,我认为最重要的就是选择器与事件相关了,随着浏览器升级,选择器简单了,而事件相关仍然是核心,今天我们就来学习学习 ze ...
- go语言条件语句 if else
示例: if a < 5 { return 0 } else { return 1 } 关于条件语句,需要注意以下几点: 条件语句不需要使用括号将条件包含起来(): 无论语句体内有几条语 ...
- [deviceone开发]-do_Viewshower的动画效果示例
一.简介 do_Viewshower组件也支持View之间的过场动画,支持大概12种,这个示例随机的切换12种动画中的一种,而且每次切换的动画时间不一样.直观的展示12种动画的效果.适合初学者. 二. ...
- 设置css通用字体
font-family: "Helvetica Neue","Arial","PingFang SC","Hiragino San ...
- Eclipse Plug-in Hello world
这一篇就简单说下一个hello world插件工程创建过程. 1.创建一个Plug-in Project 2.填写project name 3.第二个确认框勾上,然后直接下一步 ...