1. 程式人生 > >OTSU閾值分割演算法原理與原始碼

OTSU閾值分割演算法原理與原始碼

OTSU閾值分割

OTSU閾值處理(最大類間方差),演算法步驟如下: 【1】統計灰度級中每個畫素在整幅影象中的個數。 【2】計算每個畫素在整幅影象的概率分佈。 【3】對灰度級進行遍歷搜尋,計算當前灰度值下前景背景類間概率。 【4】通過目標函式計算出類內與類間方差下對應的閾值。

對於影象I(x,y),前景(即目標)和背景的分割閾值記作T,屬於前景的畫素點數佔整幅影象的比 例記為ω0,其平均灰度μ0;背景畫素點數佔整幅影象的比例為ω1,其平均灰度為μ1。影象的總平均 灰度記為μ,類間方差記為g。 假設影象的背景較暗,並且影象的大小為M×N, 影象中畫素的灰度值小於閾值T的畫素個數記作N0,畫素灰度大於閾值T的畫素個數記作N1,則有:       ω0=N0/ M×N                                            (1)       ω1=N1/ M×N                                            (2)       N0+N1=M×N                                            (3)       ω0+ω1=1                                                 (4)       μ=ω0*μ0+ω1*μ1                                     (5)       g=ω0(μ0-μ)^2+ω1(μ1-μ)^2                    (6) 將式(5)代入式(6),得到等價公式: g=ω0ω1(μ0-μ1)^2  (7)

#include <stdio.h>
#include <string>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

// 大均法函式實現
int OTSU(cv::Mat srcImage)
{
    int nCols = srcImage.cols;
    int nRows = srcImage.rows;
    int threshold = 0;

    // 初始化統計引數
    int nSumPix[256];
    float nProDis[256];
    for (int i = 0; i < 256; i++)
    {
        nSumPix[i] = 0;
        nProDis[i] = 0;
    }

    // 統計灰度級中每個畫素在整幅影象中的個數 
    for (int i = 0; i < nCols; i++)
    {
        for (int j = 0; j < nRows; j++)
        {
            nSumPix[(int)srcImage.at<uchar>(i, j)]++;
        }
    }

    // 計算每個灰度級佔影象中的概率分佈
    for (int i = 0; i < 256; i++)
    {
        nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
    }

    // 遍歷灰度級[0,255],計算出最大類間方差下的閾值  
    float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
    double delta_max = 0.0;
    for (int i = 0; i < 256; i++)
    {
        // 初始化相關引數
        w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
        for (int j = 0; j < 256; j++)
        {
            //背景部分 
            if (j <= i)
            {
                // 當前i為分割閾值,第一類總的概率  
                w0 += nProDis[j];
                u0_temp += j * nProDis[j];
            }
            //前景部分   
            else
            {
                // 當前i為分割閾值,第一類總的概率
                w1 += nProDis[j];
                u1_temp += j * nProDis[j];
            }
        }

        // 分別計算各類的平均灰度 
        u0 = u0_temp / w0;
        u1 = u1_temp / w1;
        delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));

        // 依次找到最大類間方差下的閾值    
        if (delta_temp > delta_max)
        {
            delta_max = delta_temp;
            threshold = i;
        }
    }

    return threshold;
}