OpenCV C++(六)----閾值分割

6.1徊哑、方法概述

閾值分割的核心就是如何選取閾值随闽, 選取正確的閾值是分割成功的關(guān)鍵过牙。

1社牲、全局閾值分割

全局閾值分割指的是將灰度值大于thresh(閾值)的像素設(shè)為白色粪薛,小于或者等于 thresh的像素設(shè)為黑色; 或者反過來搏恤, 將大于thresh的像素設(shè)為黑色违寿, 小于或者等于thresh 的像素設(shè)為白色湃交, 兩者的區(qū)別只是呈現(xiàn)形式不同。

image.png
double threshold( InputArray src, OutputArray dst,double thresh, double maxval, int type );
image.png

需要注意的是藤巢,當(dāng)類型為THRESH_OTSUTHRESH_TRIANGLE時搞莺,輸入?yún)?shù)src只支持uchar類型, 這時thresh也是作為輸出參數(shù)的掂咒, 即通過OtsuTRIANGLE算法自動計算出來才沧。

2、局部閾值分割

局部閾值分割的核心也是計算閾值矩陣绍刮,比較常用的是后面提到的自適應(yīng)閾值算法(又稱移動平均值算法) 温圆, 是一種簡單但是高效的局部閾值算法,其核心思想就是把每一個像素的鄰域的“平均值”作為該位置的閾值孩革。

6.2岁歉、直方圖技術(shù)法

一幅含有一個與背景呈現(xiàn)明顯對比的物體的圖像具有包含雙峰的直方圖,兩個峰值對應(yīng)于物體內(nèi)部和外部較多數(shù)目的點膝蜈,兩個峰值之間的波谷對應(yīng)于物體邊緣附近相對較少數(shù)目的點锅移。

直方圖技術(shù)法就是首先找到這兩個峰值,然后取兩個峰值之 間的波谷位置對應(yīng)的灰度值彬檀,就是所要的閾值帆啃。

一 種常用的方式是先對直方圖進行高斯平滑處理,逐漸增大高斯濾波器的標(biāo)準差窍帝,直到能從平滑后的直方圖中得到兩個唯一的波峰和它們之間唯一的最小值努潘。但這種方式需要手動調(diào)節(jié),下面介紹一種規(guī)則自動選取波峰和波谷的方式坤学。

假設(shè)輸入圖像為I疯坤, 高為H、 寬為W深浮,histogramI代表其對應(yīng)的灰度直方圖压怠, histogramI (k) 代表灰度值等于k的像素點個數(shù), 其中0≤k≤255飞苇。

  • 第一步: 找到灰度直方圖的第一個峰值菌瘫,并找到其對應(yīng)的灰度值。顯然布卡,灰度直方圖的最大值就是第一個峰值且對應(yīng)的灰度值用firstPeak表示雨让。

  • 第二步: 找到直方圖的第二個峰值,并找到其對應(yīng)的灰度值忿等。第二個峰值不一定是直方圖的第二大值栖忠,因為它很有可能出現(xiàn)在第一個峰值的附近。

image.png
  • 第三步: 找到這兩個峰值之間的波谷,如果出現(xiàn)兩個或者多個波谷庵寞,則取左側(cè)的波 谷即可狸相,其對應(yīng)的灰度值即為閾值。
int threshTwoPeaks(const Mat &image, Mat &thresh_out)
{
    //計算灰度直方圖
    Mat histogram = calGrayHist(image);
    //找到灰度直方圖最大峰值對應(yīng)的灰度值
    Point firstPeakLoc;
    minMaxLoc(histogram, NULL, NULL, NULL, &firstPeakLoc);
    int firstPeak = firstPeakLoc.x;
    //尋找灰度直方圖第二個峰值對應(yīng)的灰度值
    Mat measureDists = Mat::zeros(Size(256, 1), CV_32FC1);
    for (int k = 0; k < 256; k++)
    {
        int hist_k = histogram.at<int>(0, k);
        measureDists.at<float>(0, k) = pow(float(k - firstPeak), 2)*hist_k;
    }
    Point secondPeakLoc;
    minMaxLoc(measureDists, NULL, NULL, NULL, &secondPeakLoc);
    int secondPeak = secondPeakLoc.x;

    //找到兩個之間的最小值對應(yīng)的灰度值捐川,作為閾值
    Point threshLoc;
    int thresh = 0;
    if (firstPeak < secondPeak)//第一個峰值在第二個峰值的左側(cè)
    {
        minMaxLoc(histogram.colRange(firstPeak, secondPeak), NULL, NULL, NULL, &threshLoc);
        thresh = firstPeak + threshLoc.x + 1;
    }
    else//第一個峰值在第二個峰值的右側(cè)
    {
        minMaxLoc(histogram.colRange(secondPeak, firstPeak), NULL, NULL, NULL, &threshLoc);
        thresh = secondPeak + threshLoc.x + 1;
    }
    //閾值分割
    threshold(image, thresh_out, thresh, 255, THRESH_BINARY);
    return thresh;
}

6.3脓鹃、熵方法

image.png

利用熵計算閾值的步驟如下:

  • 第一步: 計算I 的累加概率直方圖,又稱零階累積矩属拾,記為
image.png
  • 第二步: 計算各個灰度級的熵将谊,記為
image.png
  • 第三步: 計算使f (t) =f1(t) +f2(t) 最大化的t值, 該值即為得到的閾值渐白, 即thresh=argtmax(f (t) )尊浓, 其中
image.png

6.4、Otsu閾值處理

在對圖像進行閾值分割時纯衍,所選取的分割閾值應(yīng)使前景區(qū)域的平均灰度栋齿、背景區(qū)域 的平均灰度與整幅圖像的平均灰度之間的差異最大, 這種差異用區(qū)域的方差來表示襟诸。 Otsu[2]提出了最大方差法瓦堵, 該算法是在判別分析最小二乘法原理的基礎(chǔ)上推導(dǎo)得出的, 計算過程簡單歌亲, 是一種常用的閾值分割的穩(wěn)定算法菇用。

  • 第一步: 計算灰度直方圖的零階累積矩(或稱累加直方圖) 。
image.png
  • 第二步: 計算灰度直方圖的一階累積矩陷揪。
image.png
  • 第三步: 計算圖像I 總體的灰度平均值mean惋鸥, 其實就是k=255時的一階累積距, 即
image.png
  • 第四步: 計算每一個灰度級作為閾值時悍缠, 前景區(qū)域的平均灰度卦绣、 背景區(qū)域的平均灰 度與整幅圖像的平均灰度的方差。 對方差的衡量采用以下度量:
image.png
  • 第五步: 找到上述最大的σ2(k)飞蚓, 然后對應(yīng)的k即為Otsu自動選取的閾值滤港, 即
image.png
int otsu(const Mat &image, Mat &OtsuThreshImage)
{
    //計算灰度直方圖
    Mat histogram = calGrayHist(image);
    //歸一化灰度直方圖
    Mat normHist;
    histogram.convertTo(normHist, CV_32FC1, 1.0 / (image.rows*image.cols), 0.0);
    //計算累加直方圖(零階累積距)和一階累積距
    Mat zeroCumuMoment = Mat::zeros(Size(256, 1), CV_32FC1);
    Mat oneCumuMoment = Mat::zeros(Size(256, 1), CV_32FC1);
    for (int i = 0; i < 256; i++)
    {
        if (i == 0)
        {
            zeroCumuMoment.at<float>(0, i) = normHist.at<float>(0, i);
            oneCumuMoment.at<float>(0, i) = normHist.at<float>(0, i);
        }
        else
        {
            zeroCumuMoment.at<float>(0, i) = normHist.at<float>(0, i) + zeroCumuMoment.at<float>(0, i - 1);
            oneCumuMoment.at<float>(0,i)= normHist.at<float>(0, i) + oneCumuMoment.at<float>(0, i - 1);
        }
    }
    //計算類間方差
    Mat variance = Mat::zeros(Size(256, 1), CV_32FC1);
    //總平均值
    float mean = oneCumuMoment.at<float>(0, 255);
    for (int j = 0; j < 256; j++)
    {
        if (zeroCumuMoment.at<float>(0, j) == 0 || zeroCumuMoment.at<float>(0, j) == 1)
        {//分母不能為零
            variance.at<float>(0, j) = 0;
        }
        else
        {
            variance.at < float>(0, j) = pow(mean*zeroCumuMoment.at<float>(0, j) - oneCumuMoment.at<float>(0, j), 2) / zeroCumuMoment.at<float>(0, j)*(1.0 - zeroCumuMoment.at<float>(0, j));
        }
    }
    //找到最值作為閾值
    Point maxLoc;
    minMaxLoc(variance, NULL, NULL, NULL, &maxLoc);
    int thresh = maxLoc.x;
    //閾值處理
    threshold(image, OtsuThreshImage, thresh, 255, THRESH_BINARY);
    return thresh;
}

6.5、自適應(yīng)閾值

在不均勻照明或者灰度值分布不均的情況下趴拧,如果使用全局閾值分割溅漾, 那么得到的分割效果往往會很不理想。那么想到的策略是針對每一個位置的灰度值 設(shè)置一個對應(yīng)的閾值著榴, 而該位置閾值的設(shè)置也和其鄰域有必然的關(guān)系樟凄。

在對圖像進行平滑處理時,均值平滑兄渺、高斯平滑、中值平滑用不同規(guī)則計算出以當(dāng)前像素為中心的鄰域內(nèi)的灰度“平均值”, 所以可以使用平滑處理后的輸出結(jié)果作為每個 像素設(shè)置閾值的參考值挂谍,如用均值濾波后的結(jié)果乘以某個比例系數(shù)作為最后的閾值矩陣叔壤。

平滑算子的寬度必須大于被識別物體的寬度,平滑算子的尺寸越大口叙,平滑后的結(jié)果越能更好地作為每個像素的閾值的參考炼绘,當(dāng)然也不能無限大。

  • 第一步: 對圖像進行平滑處理妄田, 平滑結(jié)果記為fsmooth(I) 俺亮,其中fsmooth可以代表 均值平滑、高斯平滑疟呐、中值平滑脚曾。
  • 第二步: 自適應(yīng)閾值矩陣Thresh=(1-ratio) *fsmooth(I) ,一般令ratio=0.15启具。
  • 第三步: 利用局部閾值分割的規(guī)則進行閾值分割本讥。
Mat adaptiveThresh(Mat I, int radius, float radio, METHOD method)
{
    //step1:對圖像矩陣進行平滑處理
    Mat smooth;
    switch (method)
    {
    case MEAN:
        boxFilter(I, smooth, CV_32FC1, Size(2 * radius + 1, 2 * radius + 1));
        break;
    case GAUSS:
        GaussianBlur(I, smooth, Size(2 * radius + 1, 2 * radius + 1), 0, 0);
        break;
    case MEDIAN:
        medianBlur(I, smooth, 2 * radius + 1);
        break;
    default:
        break;
    }
    //step2:平滑結(jié)果乘于比例系數(shù),然后圖像矩陣與其做差
    I.convertTo(I, CV_32FC1);
    smooth.convertTo(smooth, CV_32FC1);
    Mat diff = I - (1.0 - radio)*smooth;
    //step3:閾值處理鲁冯,當(dāng)≥0拷沸,輸出值為255,反之薯演,輸出值為0
    Mat out = Mat::zeros(diff.size(), CV_8UC1);
    for (int r = 0; r < I.rows; r++)
    {
        for (int c = 0; c < I.cols; c++)
        {
            if (diff.at<float>(r, c) > 0)
            {
                out.at<uchar>(r, c) = 255;
            }
        }
    }
    return out;
}

就可以理解OpenCV提供的自適應(yīng)閾值函數(shù):

void adaptiveThreshold( InputArray src, OutputArray dst,
                                     double maxValue, int adaptiveMethod,
                                     int thresholdType, int blockSize, double C );

6.6撞芍、二值圖的邏輯運算

OpenCV提供的兩個函數(shù)bitwise_andbitwise_or分別實現(xiàn)了兩 個矩陣之間的與運算和或運算,它們本質(zhì)上完成的是兩個矩陣對應(yīng)位置數(shù)值的邏輯運算跨扮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末序无,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子好港,更是在濱河造成了極大的恐慌愉镰,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钧汹,死亡現(xiàn)場離奇詭異丈探,居然都是意外死亡,警方通過查閱死者的電腦和手機拔莱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進店門碗降,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人塘秦,你說我怎么就攤上這事讼渊。” “怎么了尊剔?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵爪幻,是天一觀的道長。 經(jīng)常有香客問我,道長挨稿,這世上最難降的妖魔是什么仇轻? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮奶甘,結(jié)果婚禮上篷店,老公的妹妹穿的比我還像新娘。我一直安慰自己臭家,他們只是感情好疲陕,可當(dāng)我...
    茶點故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钉赁,像睡著了一般蹄殃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上橄霉,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天窃爷,我揣著相機與錄音,去河邊找鬼姓蜂。 笑死按厘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钱慢。 我是一名探鬼主播逮京,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼束莫!你這毒婦竟也來了懒棉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤览绿,失蹤者是張志新(化名)和其女友劉穎策严,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饿敲,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡妻导,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了怀各。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倔韭。...
    茶點故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瓢对,靈堂內(nèi)的尸體忽然破棺而出寿酌,到底是詐尸還是另有隱情,我是刑警寧澤硕蛹,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布醇疼,位于F島的核電站硕并,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏僵腺。R本人自食惡果不足惜鲤孵,卻給世界環(huán)境...
    茶點故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望辰如。 院中可真熱鬧,春花似錦贵试、人聲如沸琉兜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豌蟋。三九已至,卻和暖如春桑滩,著一層夾襖步出監(jiān)牢的瞬間梧疲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工运准, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幌氮,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓胁澳,卻偏偏與公主長得像该互,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子韭畸,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容