otsu算法实现(基于opecv2.0版本)

出处:http://www.cnblogs.com/xy-kidult/p/3397553.html

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,取每个数作为一个阈值,计算此时的前景和背景概率总和以及它们的期望,计算公式见下图:

otsu算法实现(基于opecv2.0版本)_第1张图片
4 最后,根据上述几个值获得一个类间方差和类内方差,公式就不放上来了,直接看代码。
 
复制代码
#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;
}

你可能感兴趣的:(opencv,otsu算法)