图像处理之大津法OTSU(C++)
前言
大津法,又称最大类间方差法(OTSU)是一种常用的阈值处理方法。
该方法假设图像包含两类像素(前景和背景),通过计算使得两类像素间方差最大的灰度值。
应用场景:直方图为双峰直方图、单个目标物体的分割。
一、大津法原理
参数解释:
- mG:全局平均灰度值
- P1(k):灰度值从0到k的概率和
- m(k):灰度值从0到k的灰度值的平均
- σ*σB:灰度值为k时的类间方差,我们的目标就是求得最大类间方差时的灰度值K。
二、代码实现
1.C++手动实现
/*
* @param cv::Mat src 输入图像(CV_8U)
* @param cv::Mat dst 输出图像
* @param int thresh OTSU最大类间方差的灰度值
* @brief 计算OTSU的灰度值并返回
*/
int OtsuThreshold(const cv::Mat& src, cv::Mat& dst,int& thresh)
{
int h = src.rows;
int w = src.cols;
//利用查表法计算各个灰度级的概率
double grayTable[256] = { 0 };
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
grayTable[src.at<uchar>(i, j)]++;
for (int i = 0; i < 256; i++)
grayTable[i] /= (h * w);
//计算全局灰度平均值
double mg = 0;
for (int i = 0; i < 256; i++)
mg += (i * grayTable[i]);
//计算各个灰度级的方差
double sigmmaTable[256] = { 0 };
double m = 0;
double p1= 0;
for (int k = 0; k < 256; k++)
{
m += (k * grayTable[k]); // 灰度级为k的累加均值m
p1 += grayTable[k]; // 灰度级为k的累加概率p1
sigmmaTable[k] = pow((mg * p1 - m), 2) / (p1 * (1 - p1));
}
//查找方差最大的灰度值k
double max = sigmmaTable[0];
thresh = 0;
for (int i = 1; i < 256; i++)
{
if (max < sigmmaTable[i])
{
max = sigmmaTable[i];
thresh = i;
}
}
dst = src.clone();
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++) {
if (src.at<uchar>(i, j) > thresh)
dst.at<uchar>(i, j) = 255;
else
dst.at<uchar>(i, j) = 0;
}
return thresh;
}
int main()
{
//读取图片
string filepath = "F://work_study//algorithm_demo//baby.jpg";
cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
if (src.empty())
{
std::cout << "imread error" << std::endl;
return -1;
}
cv::Mat dst(src.size(), src.type());
// 调用自己实现的OTSU函数
OtsuThreshold(src,dst,thresh2);
//显示图片
cv::imshow("dst.bmp", dst);
cv::waitKey(0);
return 0;
}
2.调用OpenCV的API
int main()
{
//读取图片
string filepath = "F://work_study//algorithm_demo//baby.jpg";
cv::Mat src = cv::imread(filepath, cv::IMREAD_GRAYSCALE);
if (src.empty())
{
std::cout << "imread error" << std::endl;
return -1;
}
cv::Mat dst(src.size(), src.type());
// 调用OpenCV的API
cv::threshold(src, dst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
//显示图片
cv::imshow("dst.bmp", dst);
cv::waitKey(0);
return 0;
}
三、结果展示
总结
本文介绍了大津法的原理和C++代码实现,和opencv API进行对比,自己实现的算法处理速度是2ms,OpenCV的是5ms,计算得到的最大类间对应的灰度值一致,欢迎大家阅读。
因为笔者水平有限,有错误欢迎指出,代码本人均在本地运行实验正确,大家放心使用。