OpenCv 中Otsu 算法实现

来源:互联网 发布:mac自带快捷键怎么设置 编辑:程序博客网 时间:2024/06/10 04:08

一、Otsu算法原理

Otsu算法(大津法或最大类间方差法)使用的是聚类的思想,把图像的灰度数按灰度级分成2个部分,使得两个部分之间的灰度值差异最大,每个部分之间的灰度差异最小,通过方差的计算来寻找一个合适的灰度级别来划分。 所以可以在二值化的时候采用otsu算法来自动选取阈值进行二值化。otsu算法被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮度和对比度的影响。因此,使类间方差最大的分割意味着错分概率最小。

设t为设定的阈值。

w0分开后前景像素点数占图像的比例u0分开后前景像素点的平均灰度w1分开后背景像素点数占图像的比例u1分开后背景像素点的平均灰度

 

 

 

 

图像总平均灰度为: u = w0∗u0 + w1∗u1 

 

从L个灰度级遍历 t,使得 t 为某个值的时候,前景和背景的方差最大,则 这个 t 值便是我们要求得的阈值。其中,方差的计算公式如下:

 g = wo∗(u0−u)∗(u0−u) + w1∗(u1−u)∗(u1−u) 

此公式计算量较大,可以采用:

 g = w0∗w1∗(u0−u1)∗(u0−u1) 

由于Otsu算法是对图像的灰度级进行聚类,因此在执行Otsu算法之前,需要计算该图像的灰度直方图。

二. 代码

  #include <opencv2/photo.hpp>  
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>
#include<fstream>
#include<Windows.h>
using namespace cv;
using namespace std;

Mat src,dst;

int Otsu(Mat &src);
int main(int argc, char ** argv)
{
    
    //Mat f,g;
 
    src = imread("D:\\Test_picture\\guit5.jpeg", IMREAD_GRAYSCALE);
    dst = src.clone();
    int threadshold = Otsu(src);
    threshold(src, dst, threadshold, 255, CV_THRESH_BINARY);
    namedWindow(window_name, WINDOW_AUTOSIZE);
    imshow(window_name, dst);

   waitKey(0);

}

int Otsu(Mat &src)
{
    long size = src.cols*src.rows;
    float histogram[256] = { 0 };
    for (int m = 0; m < src.rows; m++)
    {
        unsigned char *p = src.ptr<uchar>(m);
        for (int n = 0; n < src.cols; n++)
        {
            histogram[p[n]]++;
        }
    }
    int threshold;
    long sum0 = 0, sum1 = 0;
    long cnt0, cnt1 = 0;
    double w0 = 0, w1 = 0;
    double u0 = 0, u1 = 0;
    double variance = 0;
    int i, j;
    double u = 0;
    double maxVariance = 0;
    for (i = 0; i < 256; i++)
    {
        sum0 = 0;
        sum1 = 0;
        cnt0 = 0;
        cnt1 = 0;
        w0 = 0;
        w1 = 0;
        for (j = 0; j < i; j++)
        {
            cnt0 += histogram[j];
            sum0 += j*histogram[j];

        }
        u0 = (double)sum0 / cnt0;
        w0 = (double)cnt0 / size;
        for (j = i; j <= 255; j++)
        {
            cnt1 += histogram[j];
            sum1 += j*histogram[j];
        }
        u1 = (double)sum1 / cnt1;
        w1 = 1 - w0;
        u = u0 * w0 + u1 * w1;
        variance = w0 * w1 *  (u0 - u1) * (u0 - u1);
        if (variance > maxVariance)
        {
            maxVariance = variance;
            threshold = i;
        }
    }
    return threshold;

}


原创粉丝点击