OTSU 获取最佳阈值,及opencv二值化
Posted BigProgrambug
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OTSU 获取最佳阈值,及opencv二值化相关的知识,希望对你有一定的参考价值。
OTSU 算法求最佳阈值,及opencv 二值化
前言
OTSU算法,也就是大津算法,属于自适应的阈值确定方法,用该阈值进行的图像固定阈值二值化,类间方差最大,它是按图像的灰度特性,将图像分成背景和前景两部分,使类间方差最大的分割意味着错分概率最小。其核心思路是寻找一个阈值T,把图像的所有像素点分成两类,一类的像素值均小于等于T(背景区域),另一类的像素值均大于T(前景区域),当这两类的类间方差取得最大值时,则认为该T值为最合适的阈值。假设所有像素点的总和是Sum,背景区域所有像素点数为N1,其占图像总像素数的比例为w1,平均像素值为μ1;前景区域所有像素点数为N2,其占图像总像素数的比例为w2,平均像素值为μ2;μ 为0-255 的平均像素,那么有以下关系式:
提示:以下是本篇文章正文内容,下面案例可供参考
一、OTSU 算法求最佳阈值
有着上面的算法公式我们就可以很容易的把代码写出来了,下面是代码,如果不需要用QImage的话可以直接使用Mat,选哟 转换代码的可以去转换代码
int ImageHandle::GetOptimalThreshold(QImage &image)//OTSU (大津法)
{
//首先先把QImage 转为三通道并转换为Mat
image = image.convertToFormat(QImage::Format_RGB888);
cv::Mat src = this->QImage2Mat(image);
//灰度处理,转成单通道
cv::cvtColor(src,src,cv::COLOR_BGR2GRAY);
//图片的宽,高
int nRows = src.rows;
int nCols = src.cols;
int threshold = 0; //最佳阈值
double temp = 0.0; //获取
double AvePix[256];
int TotalPix[256];
double nProDis[256];
double nSumProDis[256];
//变量初始化
for (int i = 0; i < 256; i++)
{
AvePix[i] = 0.0;
TotalPix[i] = 0;
nProDis[i] = 0.0;
nSumProDis[i] = 0.0;
}
//计算0-255 每个像素值的像素点
for (int i = 0; i < nRows; i++)
{
for (int j = 0; j < nCols; j++)
{
TotalPix[(int)src.at<uchar>(i, j)]++;
}
}
//计算每个像素值的像素点 占 总像素点的比例
for (int i = 0; i < 256; i++)
{
nProDis[i] = (double)TotalPix[i] / (nRows*nCols);
}
AvePix[0] = 0;
nSumProDis[0] = nProDis[0];
//计算背景区域的像素比例 与 像素平均值
for (int i = 1; i < 256; i++)
{
nSumProDis[i] = nSumProDis[i - 1] + nProDis[i];
AvePix[i] = AvePix[i - 1] + i*nProDis[i];
}
double mean = AvePix[255];
//遍历像素值 找到类间方差最大的像数值即为最佳阈值
for (int i = 1; i < 256; i++)
{
double Pback = nSumProDis[i];
double Pfront = 1 - nSumProDis[i];
double g= 0.0;
if (fabs(Pback ) > 0.000001 && fabs(Pfront ) > 0.000001)
{
double Mback = AvePix[i];
double Mfront = (mean - Pback *Mback)/Pfront ;
g= (double)(Pback * Pfront * pow((Mback - Mfront), 2)); //大津算法 即(背景像素占总像素的比例 * 前景像素占总像素的比例 * (背景平均像素 - 前景平均像素)的平方)
if (g> temp)
{
temp = g;
threshold = i;
}
}
}
return threshold;
}
二、使用获取的最佳阈值进行二值化
QImage ImageHandle::Binarization(QImage &image,int threshold)
{
image = image.convertToFormat(QImage::Format_RGB888);
cv::Mat src = this->QImage2Mat(image);
cv::cvtColor(src,src,cv::COLOR_BGR2GRAY);
cv::Mat dst;
cv::threshold(src,dst,threshold,255,CV_THRESH_BINARY);
return this->Mat2QImage(dst);
}
int main()
{
QApplication a(argc, argv);
QImage temp;
temp = QImage("temp.png");
ImageHandle f;
int i = f.GetOptimalThreshold(temp);
temp = f.Binarization(temp,i);
QLabel *m_label = new QLabel();
m_label->resize(1280,1024);
QPixmap I_map = QPixmap::fromImage(temp);
I_map = I_map.scaled(m_label->width(),m_label->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
m_label->setPixmap(I_map);
m_label->show();
return a.exec();
}
三、效果
1、二值化前
2、二值化后
以上是关于OTSU 获取最佳阈值,及opencv二值化的主要内容,如果未能解决你的问题,请参考以下文章