其实OpenCV中内置了这个二值化算法,在Threshold方法中
double threshold( InputArray src, OutputArray dst, double thresh, double maxval, int type );
/*
阈值类型有如下几种:
0:二进制阈值化--THRESH_BINARY
1:反二进制阈值化--THRESH_BINARY_INV
2:截断阈值化:大于该阈值的像素点被设定为该阈值--THRESH_TRUNC
3:阈值化为0:低于阈值被设置为0--THRESH_TOZERO
4:反阈值化为0:超过阈值被设置为0--THRESH_TOZERO_INV
8:OTSU阈值化--CV_THRESH_OTSU
*/
参数说明:
第一个参数:InputArray类型的src,输入数组,填单通道,8位或32位浮点类型Mat即可。即为输入图像。
第二个参数:函数运算后的结果存放在这。即为输出图像(与输入图像同样的尺寸和类型)。
第三个参数:double类型的thresh,阈值的具体值。根据需要自行设置。
第四个参数:表示预设最大值,使用THRESH_BINARY或THRESH_BINARY_INV类型。
第五个参数:int类型的type,表示阈值化处理的类型。
otsu的c++实现,需要参考公式 :https://blog.csdn.net/liuzhuomei0911/article/details/51440305
效果如下:
#include "pch.h"
#include <iostream>
#include <opencv2\opencv.hpp>
int OTSU(cv::Mat& img);
int main()
{
cv::Mat src = cv::imread("lena.png", 0);
cv::imshow("src", src);
int threshold = OTSU(src);
cv::Mat dst(src.size(), CV_8UC1);
for (int i = 0; i < dst.rows; i++)
{
for (int j = 0; j < dst.cols; j++)
{
//阈值判断。 若该点值大于阈值,则设为255,否则设为0。
if (src.at<uchar>(i, j) > threshold)
dst.at<uchar>(i, j) = 255;
else
dst.at<uchar>(i, j) = 0;
}
}
cv::imshow("otsu", dst);
cv::waitKey(0);
}
int OTSU(cv::Mat& img)
{
int nRows = img.rows;
int nCols = img.cols;
int threshold = 0;
int nSumPix[256];
float nProDis[256];
for (int i = 0; i < nRows; i++)
{
for (int j = 0; j < nCols; j++)
{
nSumPix[(int)img.at<uchar>(i, j)]++;
}
}
for (int i = 0; i < 256; i++)
{
nProDis[i] = (float)nSumPix[i] / (nCols*nRows);
}
float wb, wf; //比重. wb-背景部分; wf-前景部分
float u0_temp, u1_temp, u0, u1; //平均值
float delta_temp; //存放临时方差
double delta_max = 0.0; //初始化最大类间方差
for (int i = 0; i < 256; i++)
{
wb = wf = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;//初始化相关参数
for (int j = 0; j < 256; j++)
{
//背景部分
if (j <= i)
{
//当前i为分割阈值,第一类总的概率
wb += nProDis[j]; //比重
u0_temp += j * nProDis[j];
}
//前景部分
else
{
//当前i为分割阈值,第一类总的概率
wf += nProDis[i]; //比重
u1_temp += j * nProDis[j];
}
}
//------------分别计算各类的平均值------------
u0 = u0_temp / wb;
u1 = u1_temp / wf;
//-----------计算最大类间方差------------
delta_temp = (float)(wb*wf*pow((u0 - u1), 2));//形如pow(x,y);其作用是计算x的y次方。
//------------依次找到最大类间方差下的阈值------------
if (delta_temp > delta_max)
{
delta_max = delta_temp;
threshold = i;
}
}//计算结束
return threshold; //返回OTUS计算出的阈值
}