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

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版本)
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;

}

 

 

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