单阈值大津法

大津法属于全局阈值办法中的一种,即是最大类间方差法
大津法次要原理在于会主动找出一个阈值 使得宰割后的两部分类间方差最大 实用于有双波峰的图像,大津法作为图像宰割中阈值选取的罕用算法,计算简略,不受图像亮度和对比度的影响,次要原理如下:
影像的大小为M×N,将前景区域和背景区域的宰割阈值记作T,影像中像素值小于阈值T的像素个数记为N0,像素值大于阈值T的像素个数记为N1,则有:

w0=N0/(M×N)    w1=N1/(M×N)    =w0×0+w1×1    g=w0×(0-)^2+w1×(1-)^2    

其中w0为前景区域像素个数占整幅影像的比例,其像素均值为0;w1是背景区域像素个数占整幅影像的比例,其像素均值为1;为影像的总像素均值,g为类间方差,当计算出的类间方差g最大时,对应的阈值T即为最佳宰割成果的阈值。

其实比照 方差的求解公式

很容易了解 最大类间方差
类间方差就是把图像分成两团 两个整体 别离计算 每个整体的方差
方差1 xi就是 前景的均值u0 x均匀 就是整幅影像均值u n=1
方差2 同样
而后再乘以这两局部的权重 相加即可

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>#include <opencv2/imgproc.hpp>#include <opencv2\imgproc\types_c.h>#include <opencv2/highgui/highgui_c.h>#include <opencv2/opencv.hpp>#include <iostream>using namespace std;using namespace cv;double Otsu(Mat& image){    int threshold = 0;    double maxVariance = 0;    double w0 = 0, w1 = 0;//前景与背景像素点所占比例    double u0 = 0, u1 = 0;//前景与背景像素值均匀灰度    int histogram[256] = { 0 }; //定义一个数组 长度为256  0-255    int Num = image.cols * image.rows;  //总像素个数    //统计256个bin,每个bin像素的个数    for (int i = 0; i < image.rows; i++)    {        const uchar* p = image.ptr<uchar>(i);        for (int j = 0; j < image.cols; j++)        {            histogram[int(*p++)]++; //cout<<"Histogram[data[i*image.step+j]]++:;"<<histogram[int(*p++)]++<<endl;         }        //*p++,  *和++优先级是雷同的 先解援用取出指针指向的值,        //而后再将指针地址加1,指向下一个地位。也就是取值为 *p   然而这时候指针曾经指向下一个地位    }    //前景像素统计    for (int i = 1; i < 256; i++)    {        w0 = 0;    //前景像素所占比例        w1 = 0;    //背景像素所占比例        u0 = 0;    //前景像素灰度均值        u1 = 0;    //背景像素灰度均值           for (int j = 1; j <= i; j++)        {            w0 = w0 + histogram[j];//以i为阈值,统计前景像素比例            u0 = u0 + j * histogram[j];//以i为阈值,统计前景像素灰度总和        }        u0 = u0 / w0; w0 = w0 / Num;    //Num是总像素个数        //背景像素统计        for (int j = i + 1; j <= 255; j++)        {            w1 = w1 + histogram[j];//以i为阈值,统计前景像素个数            u1 = u1 + j * histogram[j];//以i为阈值,统计前景像素灰度总和  histogram[j]是像素值为j的像素个数         }        u1 = u1 / w1; w1 = w1 / Num;        // 后面的u1是总灰度和  除以w1总个数是前景的灰度均值// 后面的w1是总个数 除以Num当前才是比例         double variance = w0 * w1 * (u1 - u0) * (u1 - u0); //以后类间方差计算        if (variance > maxVariance)        {            maxVariance = variance;            threshold = i;        }    }    cout << "threshold:" << threshold << endl;    return threshold;}int main(){    Mat img = imread("C://Users//马亚飞//Pictures//Saved Pictures//湖人.jpg");    imshow("原图", img);    Mat img1;    img.copyTo(img1);    cvtColor(img, img, CV_BGR2GRAY);   // 把img转为灰度图    cvtColor(img1, img1, CV_BGR2GRAY); //把img1转为灰度图    double th = Otsu(img);   //调用Otsu函数 失去阈值th    cout << "The return value of getOstu is: " << th << endl;   //输入阈值th    cout << "The return value of opencv threshold is: " << threshold(img1, img1, th, 255, CV_THRESH_OTSU);//opencv已实现的大津法      for (int i = 0; i < img.rows; i++)  //行循环    {        uchar* data = img.ptr<uchar>(i);  //获取第i行的首地址        for (int j = 0; j < img.cols; j++)   //列循环        {            if (data[j] <= th)                data[j] = 0;            else                data[j] = 255;        }  //行解决完结    }    imshow("Ostu_img", img);    //cv::namedWindow("Opencv_img", CV_WINDOW_NORMAL);    cv::imshow("Opencv_img", img1);    //对一次大津法 的彩色或者红色局部进行掩膜    //bitwise_not(img1, img1); //这里先变反转色彩    /*Mat src = imread("D://opencvdata//0//0.png");    src.setTo(0,img1);    imshow("掩膜", src);*/    waitKey(0);    return 0;}


(威少的黑白图还有点像利拉德)
都差不多