otsu是nobuyuki otsu于1979年提出的一种寻找灰度图像的最佳阈值的算法。
其论文名字是《A Threshold Selection Method from Gray-Level Histograms》,用google可以找到pdf版,建议大致看一下论文,再编程实现,这样容易把握重点。我刚开始是看别人对otsu的介绍,然后编程实现,但每次求出的阈值都无法达到理想效果。被逼无奈,终于还是决定看看原作者的论文。
算法简要步骤:
1 计算每个灰度值在整个图像的数量n[i];i取值从0~255;
2 计算每个灰度值出现在图像中的概率p[i],p[i]=n[i]/N,N是图像总体像素个数,为图像的宽*高;
3 从0~255,取每个数作为一个阈值,计算此时的前景和背景概率总和以及它们的期望,计算公式见下图:
#include <stdio.h> #include <string> #include "opencv2/highgui/highgui.hpp" #include "opencv2/opencv.hpp" #define MAX_GRAY_VALUE 256 #define MIN_GRAY_VALUE 0 int otsu(cv::Mat dst){ int i,j; int tmp; double u0,u1,w0,w1,u, uk; double cov; double maxcov=0.0; int maxthread=0; int hst[MAX_GRAY_VALUE]={0}; double pro_hst[MAX_GRAY_VALUE]={0.0}; int height=dst.cols; int width=dst.rows; //统计每个灰度的数量 for( i =0 ; i<width; i++ ){ for( j=0; j<height; j++){ tmp=dst.at<uchar>(i,j); hst[tmp]++; } } //计算每个灰度级占图像中的概率 for( i=MIN_GRAY_VALUE ; i<MAX_GRAY_VALUE; i++) pro_hst[i]=(double)hst[i]/(double)(width*height); //计算平均灰度值 u=0.0; for( i=MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++) u += i*pro_hst[i]; double det=0.0; for( i= MIN_GRAY_VALUE; i< MAX_GRAY_VALUE; i++) det += (i-u)*(i-u)*pro_hst[i]; //统计前景和背景的平均灰度值,并计算类间方差 for( i=MIN_GRAY_VALUE; i<MAX_GRAY_VALUE; i++){ w0=0.0; w1=0.0; u0=0.0; u1=0.0; uk=0.0; for( j=MIN_GRAY_VALUE; j < i; j++){ uk += j*pro_hst[j]; w0 += pro_hst[j]; } u0=uk/w0; w1=1-w0; u1= (u - uk )/(1-w0); //计算类间方差 cov=w0*w1*(u1-u0)*(u1-u0); if ( cov > maxcov ) { maxcov=cov; maxthread=i; } } std::cout<<maxthread<<std::endl; return maxthread; } int main(){ int width,height; int i,j; cv::Mat obj=cv::imread("Image16.jpg"); cv::Mat dst; cv::cvtColor(obj,dst,CV_RGB2GRAY); height=dst.cols; width=dst.rows; int thd=otsu(dst); cv::imshow("origin img",dst); for( i=0; i < width; i++) for( j=0; j< height; j++) if( dst.at<uchar>(i,j) > thd) dst.at<uchar>(i,j)=MAX_GRAY_VALUE-1; else dst.at<uchar>(i,j)=MIN_GRAY_VALUE; cv::imshow("img after ostu",dst); cv::waitKey(0); return 0; }原作网址:http://www.cnblogs.com/xy-kidult/p/3397553.html