原文地址:http://www.cnblogs.com/CoverCat/p/5043833.htmlhtml
转载,备查数组
Visual Studio Community 2015 工程和代码:http://pan.baidu.com/s/1o7lxYSM函数
内容学习
在这篇文章中将提到如下内容:spa
在图像处理中,会但愿忽略掉一些灰度细节,只保留主体的轮廓,对灰度图像进行阈值化处理能达到这个目的。3d
“其基本的思想是,给定一个数组和一个阈值,而后根据数组中的每一个元素的值是低于仍是高于阈值而进行一些处理”——《学习OpenCV(中文版)》,这里说的“数组”即为图像数据,code
而“进行一些处理”说的是进行分类,只有两类,根据值不一样分到不一样的类中。orm
准备工做htm
using Emgu.CV; using Emgu.CV.Structure; using Emgu.CV.CvEnum;
全局阈值blog
全局阈值指的是整个图像数据使用一个阈值进行筛选分类,OpenCV提供cvThreshold()方法进行阈值化操做,在Emgu中对应的方法名称为Threshold。
Threshold方法接受一个类型为ThresholdType的参数,ThresholdType是一个枚举类型,其枚举值为:
Binary = 0,
BinaryInv = 1, Trunc = 2, ToZero = 3, ToZeroInv = 4, Mask = 7,//这里不作介绍 Otsu = 8 //后面会作介绍
value = value > threshold ? max_value : 0
value = value > threshold ? 0 : max_value
value = value > threshold ? threshold : value
value = value > threshold ? value : 0
value = value > threshold ? 0 : value
从上边描述咱们能够看出二进制阈值化/反二进制阈值化须要一个max_value(最大值)的参数,同时,二进制阈值化/反二进制阈值化处理后图像数据中只存在两种
可能的值:0和max_value,这种图像称为二值化图像。
“在数字图像处理中,二值图像占有很是重要的地位,首先,图像的二值化有利于图像的进一步处理,使图像变得简单,并且数据量减少,能凸显出感兴趣的目标的轮
廓。其次,要进行二值图像的处理与分析,首先要把灰度图像二值化,获得二值化图像。全部灰度大于或等于阈值的像素被断定为属于特定物体,其灰度值为255表示,
不然这些像素点被排除在物体区域之外,灰度值为0,表示背景或者例外的物体区域。”——百度百科
下面的代码显示了如何使用二进制阈值化处理,若是你要使用不是二进制阈值化处理,那么max_value能够不用在乎设什么值。
{ using (var image = new Image<Bgr, Byte>(Properties.Resources.chess3)) { var grayImage = image.Convert<Gray, Byte>();//转为灰度图 var threshImage = grayImage.CopyBlank(); CvInvoke.Threshold( grayImage, threshImage, 150, //阀值 255, //最大值 ThresholdType.Binary);//二进制阈值化 imageBox1.Image = grayImage; imageBox2.Image = threshImage; } }
效果以下: Binary -> BinaryInv -> Trunc -> ToZero -> ToZeroInv
自适应阈值
全局阈值是整幅图像使用一个阀值,这并不能适应全部的状况。自适应阈值是图像的不一样的区域使用不一样的阀值,而阀值是对这个区域计算得来的,OpenCV提供cvAdaptiveThreshold()
函数进行自适应阈值化处理,这个函数提供两种计算阀值的方法,分别为CV_ADAPTIVE_THRESH_MEAN_C和CV_ADAPTIVE_THRESH_GAUSSIAN_C。
“在这两种状况下,自适应阈值T(x,y)在每一个像素点都不一样。经过计算像素点周围的b x b区域的加权平均,而后减去一个常数来获得自适应阈值, b有参数block_size指定,常数有param1
指定。若是使用CV_ADAPTIVE_THRESH_MEAN_C方法,那么对区域的全部像素平均加权。若是使用了CV_ADAPTIVE_THRESH_GAUSSIAN_C放,那么区域中的(x,y)周围的像素
根据高斯函数按照它们离中心点的距离进行加权计算。”——《学习OpenCV(中文版)》
Emgu中CVInvoke类提供了AdaptiveThreshold静态方法进行自适应阈值处理,这个方法的原型为:
public static void AdaptiveThreshold( IInputArray src, //原图像 IOutputArray dst, //结果图像 double maxValue, //二进制阈值化/反二进制阈值化处理使用到的最大值 CvEnum.AdaptiveThresholdType adaptiveType, // 自适应阈值计算方式:MeanC或GaussianC CvEnum.ThresholdType thresholdType, //阈值化方式,必须为二进制阈值化和反二进制阈值化之一(Binary / BinaryInv) int blockSize, //计算使用的区域矩阵大小:3,5,7,9... double param1) //常数
同时,Image类也提供了一个封装了AdaptiveThreshold方法的ThresholdAdaptive方法,下面的代码中使用的几位Image类的ThresholdAdaptive方法:
private void Form1_Load(object sender, EventArgs e) { var grayImage = new Image<Gray, Byte>(Properties.Resources.chess3); //CvInvoke.AdaptiveThreshold(grayImage, threshImage, 255, AdaptiveThresholdType.GaussianC, ThresholdType.BinaryInv, 12, 5); var threshImage = grayImage.ThresholdAdaptive( new Gray(255), AdaptiveThresholdType.MeanC, ThresholdType.Binary, 9, new Gray(5)); imageBox1.Image = grayImage; imageBox2.Image = threshImage; }
执行效果为:MeanC -> GaussianC
Otsu二值化
在全局阈值的代码中,咱们使用150做为二进制阈值化的阀值,可是这个阀值是我随意选择的,我并不肯定这个阀值是不是合适的阈值。而若是使用Otsu二值化方法,它能够根据
图像的直方图计算出一个阀值。使用Otsu方法用到的是全局阈值提到过的Threshold方法,只是在传入的ThresholdType值为Otsu,代码以下:
var grayImage = new Image<Gray, Byte>(Properties.Resources.chess3); var threshImage = grayImage.CopyBlank(); CvInvoke.Threshold( grayImage, threshImage, 0, 255, ThresholdType.Otsu); imageBox1.Image = grayImage; imageBox2.Image = threshImage;
运行效果: