OTSU阈值分割算法原理与源码

OTSU阈值分割

OTSU阈值处理(最大类间方差),算法步骤如下:
【1】统计灰度级中每个像素在整幅图像中的个数。
【2】计算每个像素在整幅图像的概率分布。
【3】对灰度级进行遍历搜索,计算当前灰度值下前景背景类间概率。
【4】通过目标函数计算出类内与类间方差下对应的阈值。

对于图像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)

#include 
#include 
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;

// 大均法函数实现
int OTSU(cv::Mat srcImage)
{
    int nCols = srcImage.cols;
    int nRows = srcImage.rows;
    int threshold = 0;

    // 初始化统计参数
    int nSumPix[256];
    float nProDis[256];
    for (int i = 0; i < 256; i++)
    {
        nSumPix[i] = 0;
        nProDis[i] = 0;
    }

    // 统计灰度级中每个像素在整幅图像中的个数 
    for (int i = 0; i < nCols; i++)
    {
        for (int j = 0; j < nRows; j++)
        {
            nSumPix[(int)srcImage.at(i, j)]++;
        }
    }

    // 计算每个灰度级占图像中的概率分布
    for (int i = 0; i < 256; i++)
    {
        nProDis[i] = (float)nSumPix[i] / (nCols * nRows);
    }

    // 遍历灰度级[0,255],计算出最大类间方差下的阈值  
    float w0, w1, u0_temp, u1_temp, u0, u1, delta_temp;
    double delta_max = 0.0;
    for (int i = 0; i < 256; i++)
    {
        // 初始化相关参数
        w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
        for (int j = 0; j < 256; j++)
        {
            //背景部分 
            if (j <= i)
            {
                // 当前i为分割阈值,第一类总的概率  
                w0 += nProDis[j];
                u0_temp += j * nProDis[j];
            }
            //前景部分   
            else
            {
                // 当前i为分割阈值,第一类总的概率
                w1 += nProDis[j];
                u1_temp += j * nProDis[j];
            }
        }

        // 分别计算各类的平均灰度 
        u0 = u0_temp / w0;
        u1 = u1_temp / w1;
        delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));

        // 依次找到最大类间方差下的阈值    
        if (delta_temp > delta_max)
        {
            delta_max = delta_temp;
            threshold = i;
        }
    }

    return threshold;
}



 

你可能感兴趣的:(OpenCV)