OTSU閾值分割演算法原理與原始碼
阿新 • • 發佈:2018-12-14
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; }