Otsu是图像处理中最常用的二值化算法,原理如下:
下面是用ostu算法对灰度图进行二值化处理的代码,用opencv写的
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main()
{
Mat src = imread("D:\\picture\\1.jpg");
if(!src.data)
return -1;
imshow("original",src);
Mat gray ;
cv::cvtColor(src,gray,CV_BGR2GRAY);
imshow("gray",gray);
int rows = gray.rows;
int cols = gray.cols;
float count[256] = {0};//每个灰度值[0,255]的计数
for(int i = 0;i<rows;i++)
for(int j = 0;j<cols;j++)
{
int index = (int)gray.at<uchar>(i,j);
count[index]++;
}
float P[256]; //每个灰度值[0,255]的概率密度
for(int i = 0;i<256;i++)
P[i] = count[i]/(rows*cols);
int threshold= 0;
float deltaMax = 0;
float w0,w1,u0tmp,u1tmp,u0,u1,ut,deltaTmp;
for(int i = 1;i<256;i++)
{
w0 = w1 = u0tmp = u1tmp = u0 = u1 = ut = deltaTmp = 0;
for(int j = 0;j<256;j++)
{
if(j<i)//背景
{
w0 = w0+P[j];//背景像素占整幅图的比例
u0tmp = u0tmp + j*P[j];
}
else //前景
{
w1 = w1+P[j];//前景占整幅图的比例
u1tmp = u1tmp + j*P[j];
}
}
u0 = u0tmp/w0;//背景像素点的平均灰度
u1 = u1tmp/w1;//前景像素点的平均灰度
ut = w0*u0 + w1*u1; //整幅图像的平均灰度
for(int k = 0;k<256;k++)
deltaTmp = deltaTmp + (k-ut)*(k-ut)*P[k];//全局方差
deltaTmp = w0*w1*(u1-u0)*(u1-u0)/deltaTmp;//类间方差除以全局方差
if (deltaTmp>deltaMax)
{
deltaMax = deltaTmp;
threshold = i;
}
}
Mat binary_gray = gray.clone();
for(int i = 0;i<rows;i++)
for(int j = 0;j<cols;j++)
if((int)gray.at<uchar>(i,j)<threshold)
binary_gray.at<uchar>(i,j) = (uchar)0;
else
binary_gray.at<uchar>(i,j) = (uchar)255;
imshow("binary_gray",binary_gray);
waitKey(0);
return 0;
}
接下来是运行的结果