OSTU(大津算法选自适应阈值)

OTSU算法是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法。**重点内容**
    1. OTSU算法原理简介
      对于一幅图像,设当前景与背景的分割阈值为t时,前景点占图像比例为w0,均值为u0,背景点占图像比例为w1,均值为u1。则整个图像的均值为u = w0*u0+w1*u1。建立目标函数g(t)=w0*(u0-u)^2+w1*(u1-u)^2,g(t)就是当分割阈值为t时的类间方差表达式。OTSU算法使得g(t)取得全局最大值,当g(t)为最大时所对应的t称为最佳阈值。OTSU算法又称为最大类间方差法。
      最大类间方差法是由日本学者大津于1979年提出的,是一种自适应的阈值确定的方法,又叫大津法,简称OTSU。它是按图像的灰度特性,将图像分成背景和目标2部分。背景和目标之间的类间方差越大,说明构成图像的2部分的差别越大,当部分目标错分为背景或部分背景错分为目标都会导致2部分差别变小。因此,使类间方差最大的分割意味着错分概率最小 对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均灰度记为μ,类间方差记为g。假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有:
            ω0=N0/ M×N (1)
            ω1=N1/ M×N (2)
            N0+N1=M×N (3)
            ω0+ω1=1 (4)
            μ=ω0*μ0+ω1*μ1 (5)
            g=ω0(μ0-μ)^2+ω1(μ1-μ)^2 (6)
      将式(5)代入式(6),得到等价公式: g=ω0ω1(μ0-μ1)^2 (7)
      采用遍历的方法得到使类间方差最大的阈值T,即为所求。
  • 2.OTSU算法例程
 //-----------------------------------OpenCV学习------------------------------------- 
//  程序名称:OSTU算法选自适应阈值
//  2016年10月 Created by孙立波(Visual Studio 2013+OpenCV2.4.9)
#include  
#include 
#include  
#include 
using namespace cv;
using namespace std;
隐藏控制台窗口
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
int otsu(IplImage *image)
{
    assert(NULL != image);//若执行该函数,则终止程序运行

    int width = image->width;
    int height = image->height;
    int x = 0, y = 0;
    int pixelCount[256];
    float pixelPro[256];
    int i, j, pixelSum = width * height, threshold = 0;

    uchar* data = (uchar*)image->imageData;

    //初始化  
    for (i = 0; i < 256; i++)
    {
        pixelCount[i] = 0;
        pixelPro[i] = 0;
    }

    //统计灰度级中每个像素在整幅图像中的个数  
    for (i = y; i < height; i++)
    {
        for (j = x; jwidthStep + j]]++;
    }


    //计算每个像素在整幅图像中的比例  
    for (i = 0; i < 256; i++)
    {
        pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
    }

    //经典ostu算法,得到前景和背景的分割  
    //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值  
    float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;
    for (i = 0; i < 256; i++)//i为阈值
    {
        w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

        for (j = 0; j < 256; j++)//遍历阈值数组当i=0,1,2,3...255
        {
            if (j <= i) //背景部分  
            {
                //以i为阈值分类,第一类总的概率  
                w0 += pixelPro[j];
                u0tmp += j * pixelPro[j];
            }
            else       //前景部分  
            {
                //以i为阈值分类,第二类总的概率  
                w1 += pixelPro[j];
                u1tmp += j * pixelPro[j];
            }
        }

        u0 = u0tmp / w0;        //第一类的平均灰度  
        u1 = u1tmp / w1;        //第二类的平均灰度  
        u = u0tmp + u1tmp;      //整幅图像的平均灰度  
        //计算类间方差  
        deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
        //找出最大类间方差以及对应的阈值  
        if (deltaTmp > deltaMax)
        {
            deltaMax = deltaTmp;
            threshold = i;
        }
    }
    //返回最佳阈值;  
    return threshold;
}

int main(int argc, char* argv[])
{
    IplImage* srcImage = cvLoadImage("F:\\workplace\\opencv_training\\test2.png", 0);
    assert(NULL != srcImage);

    cvNamedWindow("src");
    cvShowImage("src", srcImage);

    IplImage* biImage = cvCreateImage(cvGetSize(srcImage), 8, 1);

    //计算最佳阈值  
    int threshold = otsu(srcImage);
    //对图像二值化  
    cvThreshold(srcImage, biImage, threshold, 255, CV_THRESH_BINARY);

    cvNamedWindow("binary");
    cvShowImage("binary", biImage);

    cvWaitKey(0);

    cvReleaseImage(&srcImage);
    cvReleaseImage(&biImage);
    cvDestroyWindow("src");
    cvDestroyWindow("binary");

    return 0;
}

OSTU(大津算法选自适应阈值)_第1张图片

你可能感兴趣的:(OSTU(大津算法选自适应阈值))