多阈值otsu的opencv实现

 

 

 

#include <iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/photo.hpp>
using namespace cv;
using namespace std;
void inpaint_test()
{
    Mat img=imread("D:/Qt/MyImage/jingsai_1.jpg",0);
    imshow("original image",img);
    Mat mask=Mat::zeros(img.rows,img.cols,img.type());
    mask(Rect(377,228,(438-377),(269-228)))=1;
    Mat img_c;
    cv::inpaint(img,mask,img_c,3,INPAINT_TELEA);

    imshow("clear image",img_c);
    waitKey();
}
Mat getHist(const Mat &img)//img必须是单通道图像,img的概率直方图
{
    if(img.channels()!=1)
    {
        cout<<"channels of input image !=1"<<endl;
        exit(1) ;
    }
    int L=256;//灰度级数
     Mat hist(1,L,CV_64F,Scalar::all(0));
     int v=0;
    for(int i=0;i<img.rows;i++)
        for(int j=0;j<img.cols;j++)
        {
            v=img.ptr<uchar>(i)[j];
            hist.ptr<double>(0)[v]+=1;
        }
    return hist;
}
//计算累积概率分布函数,Mat &pi是概率分布,本函数可以指定某一灰度范围内(k1~k2)的累积概率
double getLocAccHist(const Mat&pi,int k1,int k2)
{
    double P=0;
    for(int k=k1;k<=k2;k++)
    {
        P +=pi.ptr<double>(0)[k];
    }
    return P;
}

Mat getMeanPerGrayLevel(const Mat& pi)//计算每个灰度级上的像素均值
{
    int L=256;
    Mat ipi(pi.size(),pi.type(),Scalar::all(0));
//    m1k.ptr<double>(0)[0]=pi.ptr<double>(0)[0]*0;
    for(int k=1;k<L;k++)
    {
        ipi.ptr<double>(0)[k]=ipi.ptr<double>(0)[(k-1)]+pi.ptr<double>(0)[k]*k;
    }
    return ipi;
}
/*计算某一灰度级范围内的所有像素灰度均值,下面是参数说明
k1:灰度级小端;k2:灰度级大端;
hist_img:原图像的直方图
*/
double getMeanvalueOfC(int k1,int k2,const Mat&hist_img)
{
    int pixTotalNum=0;
    double pixTotalValue=0;
    double mk1k2=0;
    for(int k=k1;k<=k2;k++)
    {
        pixTotalNum +=hist_img.ptr<double>(0)[k];//计算k1与k2之间所有像素的个数
        //计算k1与k2之间所有像素的灰度值之和
        pixTotalValue +=k*hist_img.ptr<double>(0)[k];
    }
    if(pixTotalNum!=0)
        mk1k2=pixTotalValue/pixTotalNum;
    return mk1k2;
}

void getOstu2Threshvalue(const Mat&img,int &k11,int &k22)
{
    Mat hist_img=getHist(img);
    Mat pi=hist_img/(img.rows*img.cols);//1.灰度级概率分布
    //3.全局均值、全局方差
    Scalar means,stddev;
    meanStdDev(img,means,stddev);
    double mG=means[0];
    //5.计算m1,第一类C1中的像素灰度均值
    int L=256;

    double SigmaB2=0;
    for(int k1=1;k1<L-2;k1++)
    {
        for(int k2=k1+1;k2<L-1;k2++)
        {
            //6.计算mk,第一类C2中的像素灰度均值
            double m1=getMeanvalueOfC(0,k1,hist_img);
            double m2=getMeanvalueOfC(k1+1,k2,hist_img);
            double m3=getMeanvalueOfC(k2+1,L-1,hist_img);
            //
            double P1=getLocAccHist(pi,0,k1);
            double P2=getLocAccHist(pi,k1+1,k2);
            double P3=getLocAccHist(pi,k2+1,L-1);
            //7.计算类间方差SigmaB2
            double temp=saturate_cast<double>(P1*(m1-mG)*(m1-mG)
                                              +P2*(m2-mG)*(m2-mG)
                                              +P3*(m3-mG)*(m3-mG));
            if(SigmaB2<temp)
            {
                SigmaB2=temp;
                k11=k1;
                k22=k2;
            }
        }
    }
}
Mat  myThreshHold(const Mat&img,int k1,int k2,int v1=0,int v2=90,int v3=255)
{
    Mat dst(img.size(),img.type(),Scalar::all(0));
    for(int i=0;i<img.rows;i++)
        for(int j=0;j<img.cols;j++)
        {
            int v=img.ptr<uchar>(i)[j];
            if(v<=k1)
                dst.ptr<uchar>(i)[j]=v1;
            else if(v<=k2)
                dst.ptr<uchar>(i)[j]=v2;
            else
                dst.ptr<uchar>(i)[j]=v3;
        }
    return dst;
}
int main()
{
    Mat img=imread("D:/Qt/MyImage/ch10/Fig1043(a)(yeast_USC).tif",0);
//    GaussianBlur(img,img,Size(7,7),0);
//    Mat kernel=(Mat_<int>(3,3)<<-1,-1,-1,
//                                -1,9,-1,
//                                -1,-1,-1);
//    filter2D(img,img,CV_8U,kernel);
    imshow("original image",img);
    int k11,k22;
    getOstu2Threshvalue(img,k11,k22);
    Mat dst=myThreshHold(img,k11,k22);

    imshow("binary image",dst);
    waitKey();

    return 0;
}

 

     下面左边是原图像,右边是双阈值ostu分割后的图像

              

 

posted @ 2025-07-21 13:40  凤凰_1  阅读(6)  评论(0)    收藏  举报