OTSU算法(大津法—最大类间方差法)原理及实现
背景
大津法(OTSU)是一种确定图像二值化分割阈值的算法,由日本学者大津于1979年提出。从大津法的原理上来讲,该方法又称作最大类间方差法,因为按照大津法求得的阈值进行图像二值化分割后,前景与背景图像的类间方差最大。
方差:
它是按图像的灰度特性,将图像分成背景和前景两部分。因方差是灰度分布均匀性的一种度量,背景和前景之间的类间方差越大,说明构成图像的两部分的差别越大,当部分前景错分为背景或部分背景错分为前景都会导致两部分差别变小。
优点:
计算简单,方便,不受图像的亮度的影响,在简单双峰场景中能进行快速分割
缺点:
噪声的干扰大,当图像没有典型的双峰时,不能够精确分割,对于多峰图像则失去效果。
应用:
医学影像分割,目标识别等,常和其它算法结合使用
基本原理:
OPENCV实现:
#include<opencv2/opencv.hpp>
#include<vector>
#include<iostream>
using namespace std;
using namespace cv;
void otsu(Mat input,Mat&output,int&thres)
{
const int Grayscale = 256;
int width = input.cols;
int height = input.rows;
double Graystatistics[Grayscale] = { 0 };
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width;j++)
{
int Grayvalue = input.at<uchar>(i, j);
Graystatistics[Grayvalue]++;//直方图统计
}
}
double allnum = width * height;
double Pi[Grayscale] = { 0 };//单个个灰度的概率
double P[Grayscale] = { 0 };//累计灰度概率
double Mi[Grayscale] = { 0 };//累计灰度平均和
double Psum = 0;
double cumgray = 0;
for (int i = 0; i < Grayscale; i++)
{
Pi[i] = Graystatistics[i] / allnum;
P[i] = Pi[i] + Psum;
Psum = P[i];
Mi[i] = cumgray + (double)i * Pi[i];
cumgray = Mi[i];
}
//计算类间方差
double var = 0;
thres = 0;
for (int i = 0; i < Grayscale; i++)
{
double fenzi = (Mi[Grayscale - 1] * P[i] - Mi[i]) * (Mi[Grayscale - 1] * P[i] - Mi[i]);
double fenmu = P[i] * (1 - P[i]);
double vau = fenzi / fenmu;
if (vau > var)
{
var = vau;
thres = i;
}
}
cout << thres << endl;
input.copyTo(output);
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
int value = output.at<uchar>(i, j);
if (value >thres)
{
output.at<uchar>(i, j) = 255;
}
else
{
output.at<uchar>(i, j) = 0;
}
}
}
}
int main()
{
Mat a = imread("1.bmp");
cvtColor(a, a, COLOR_RGB2GRAY);
Mat b;
int th = 0;
otsu(a, b, th);
int Otsu1 = cv::threshold(a, b, 0, 255, THRESH_OTSU +THRESH_BINARY);
cout << Otsu1 << endl;
imshow("1", b);
return 0;
}
opencv接口:
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)