2. ostu自适应二值化

Otsu算法原理:
对于图像 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)
      g=ω0ω1(μ0-μ1)^2         (7) 

特别说明:

【1】实现过程中构造了三个容器,s[i] 表示像素值小于 i 的像素个数;m[i] 表示像素值小于 i 的平均像素;p[i] 表示像素值小于 i 的 m[i] *i 的所有值;

【2】我本想利用中值法来确定最佳的分割点,但没有很好的思路。当前使用的是遍历法来求值。

代码如下:

#include "opencv.h"

//大津展之算法
void otsu(cv::Mat& src, cv::Mat& dst)
{
    if (src.empty()) { cout << "Source image is empty ..." << endl; return; }
    cv::resize(src, dst, cv::Size(src.cols, src.rows));
    vector<int> s(256, 0);//积分 像素个数
    vector<int> m(256, 0);//存储前n个像素均值
    vector<long> p(256, 0);//积分 像素*个数

    for (int i = 0; i < src.rows; i++)
    {
        uchar* temp = src.ptr<uchar>(i);
        for (int j = 0; j < src.cols; j++)
            s[temp[j]]++;
    }

    for (int i = 1; i < 256; i++)
    {
        s[i] += s[i - 1];
        p[i] = p[i - 1] + s[i] * i;
        m[i] = p[i] / s[i];
    }

    int result = 0; int t;
    for (int i = 0; i < 256; i++)
    {
        float w0 = 1.0*s[i] / s[255];
        float w1 = 1 - w0;
        float u0 = m[i];
        float u1 = p[255] / s[i] - m[i];
        if (result < (int)(w0*w1*(u1 - u0)*(u1 - u0)))
        {
            result = (int)(w0*w1*(u1 - u0)*(u1 - u0));
            t = i;
        }
    }

    for (int i = 0; i < dst.rows; i++)
    {
        uchar* temp = dst.ptr<uchar>(i);
        for (int j = 0; j < dst.cols; j++)
            temp[j] = temp[j] < t ? 0 : 255;
    }
}

int main()
{
    string filename = "autum.jpg";
    cv::Mat src, dst;
    src = cv::imread(filename);
    cv::cvtColor(src, src, cv::COLOR_RGB2GRAY);
    otsu(src, dst);

    cv::namedWindow("img", 0);
    cv::imshow("img", src);
    cv::namedWindow("otsu", 0);
    cv::imshow("otsu", dst);

    cv::waitKey();
    return  0;
}
原文地址:https://www.cnblogs.com/2Bthebest1/p/11018135.html