原文地址: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;
運行效果: