【问题标题】:multi-level (4) Otsu thresholding多级 (4) Otsu 阈值
【发布时间】:2016-01-28 08:52:18
【问题描述】:

我正在尝试实现多级 Otsu 的阈值,更具体地说,我需要 3 个阈值/4 个类。

我知道关于它的 2 个类似问题:#34856019 和 #22706742。 问题是我没有得到好的结果:我已经阅读了几篇文章,其中包含示例图像,并且该代码发现的阈值与这些论文中的不同。

假设我有一张黑色背景上有 3 个圆圈的图片,圆圈的亮度从非常亮到暗不等:

Sample Image

我是否正确假设得到 4 个类别:黑色背景和 3 个根据圆圈强度的类别?

我的程序给了我这些阈值:226、178、68

因此,第三个圆圈完全不可见 - 它与背景属于同一类。

有人可以检查这些值和/或源代码吗?也许可以使用 Matlab 或其他方式检查此图像... 顺便说一句,处理除以零的最佳方法是什么,这通常发生在直方图中的零值? 源代码:

void MultilevelThresholding(cv::Mat& src)
{
    int histogram[256] = { 0 };
    int pixelsCount = src.cols * src.rows;

    for (int y = 0; y < src.rows; y++)
    {
        for (int x = 0; x < src.cols; x++)
        {
            uchar value = src.at<uchar>(y, x);
            histogram[value]++;
        }
    }

    double c = 0;
    double Mt = 0;

    double p[256] = { 0 };
    for (int i = 0; i < 256; i++)
    {
        p[i] = (double) histogram[i] / (double) pixelsCount;
        Mt += i * p[i];
    }

    int optimalTreshold1 = 0;
    int optimalTreshold2 = 0;
    int optimalTreshold3 = 0;

    double maxBetweenVar = 0;

    double w0 = 0;
    double m0 = 0;
    double c0 = 0;
    double p0 = 0;

    double w1 = 0;
    double m1 = 0;
    double c1 = 0;
    double p1 = 0;

    double w2 = 0;
    double m2 = 0;
    double c2 = 0;
    double p2 = 0;
    for (int tr1 = 0; tr1 < 256; tr1++)
    {
        p0 += p[tr1];
        w0 += (tr1 * p[tr1]);
        if (p0 != 0)
        {
            m0 = w0 / p0;
        }

        c0 = p0 * (m0 - Mt) * (m0 - Mt);

        c1 = 0;
        w1 = 0;
        m1 = 0;
        p1 = 0;
        for (int tr2 = tr1 + 1; tr2 < 256; tr2++)
        {

            p1 += p[tr2];
            w1 += (tr2 * p[tr2]);
            if (p1 != 0)
            {
                m1 = w1 / p1;
            }

            c1 = p1 * (m1 - Mt) * (m1 - Mt);


            c2 = 0;
            w2 = 0;
            m2 = 0;
            p2 = 0;
            for (int tr3 = tr2 + 1; tr3 < 256; tr3++)
            {

                p2 += p[tr3];
                w2 += (tr3 * p[tr3]);
                if (p2 != 0)
                {
                    m2 = w2 / p2;
                }

                c2 = p2 * (m2 - Mt) * (m2 - Mt);

                c = c0 + c1 + c2;

                if (maxBetweenVar < c)
                {
                    maxBetweenVar = c;
                    optimalTreshold1 = tr1;
                    optimalTreshold2 = tr2;
                    optimalTreshold3 = tr3;
                }
            }
        }
    }

【问题讨论】:

  • 你可以尝试添加一个大的中值滤波器来消除边缘的褪色效果吗?您是否尝试过 k-means 聚类(4 个聚类)而不是 otsu?
  • 是的,我可以添加任何我想要的过滤器,但这只是一个示例 - 问题是关于 Otsu 及其阈值。你认为他们做对了吗?
  • 我不知道,但您的代码似乎只假设 3 个阈值 (optimalThreshold1-3) 而不是 4 个?
  • 是的,3 个阈值给我们 4 个类别,就像二进制阈值中的 1 个阈值给我们 (n+1) = 2 个类别 - 黑色和白色一样。
  • 如果您确定您的问题已得到解答,请记住接受(即使是您自己的)答案!

标签: opencv image-processing computer-vision


【解决方案1】:

所以,我想通了。 4类(3个阈值)Otsu阈值的最终源代码:

// cv::Mat& src - source image's matrix
    int histogram[256] = { 0 };
    int pixelsCount = src.cols * src.rows;

    for (int y = 0; y < src.rows; y++)
    {
        for (int x = 0; x < src.cols; x++)
        {
            uchar value = src.at<uchar>(y, x);
            histogram[value]++;
        }
    }

    double c = 0;
    double Mt = 0;

    double p[256] = { 0 };
    for (int i = 0; i < 256; i++)
    {
        p[i] = (double) histogram[i] / (double) pixelsCount;
        Mt += i * p[i];
    }

    int optimalTreshold1 = 0;
    int optimalTreshold2 = 0;
    int optimalTreshold3 = 0;

    double maxBetweenVar = 0;

    double w0 = 0;
    double m0 = 0;
    double c0 = 0;
    double p0 = 0;

    double w1 = 0;
    double m1 = 0;
    double c1 = 0;
    double p1 = 0;

    double w2 = 0;
    double m2 = 0;
    double c2 = 0;
    double p2 = 0;
    for (int tr1 = 0; tr1 < 256; tr1++)
    {
        p0 += p[tr1];
        w0 += (tr1 * p[tr1]);
        if (p0 != 0)
        {
            m0 = w0 / p0;
        }

        c0 = p0 * (m0 - Mt) * (m0 - Mt);

        c1 = 0;
        w1 = 0;
        m1 = 0;
        p1 = 0;
        for (int tr2 = tr1 + 1; tr2 < 256; tr2++)
        {

            p1 += p[tr2];
            w1 += (tr2 * p[tr2]);
            if (p1 != 0)
            {
                m1 = w1 / p1;
            }

            c1 = p1 * (m1 - Mt) * (m1 - Mt);


            c2 = 0;
            w2 = 0;
            m2 = 0;
            p2 = 0;
            for (int tr3 = tr2 + 1; tr3 < 256; tr3++)
            {

                p2 += p[tr3];
                w2 += (tr3 * p[tr3]);
                if (p2 != 0)
                {
                    m2 = w2 / p2;
                }

                c2 = p2 * (m2 - Mt) * (m2 - Mt);

                double p3 = 1 - (p0 + p1 + p2);
                double w3 = Mt - (w0 + w1 + w2);
                double m3 = w3 / p3;
                double c3 = p3 * (m3 - Mt) * (m3 - Mt);

                double c = c0 + c1 + c2 + c3;

                if (maxBetweenVar < c)
                {
                    maxBetweenVar = c;
                    optimalTreshold1 = tr1;
                    optimalTreshold2 = tr2;
                    optimalTreshold3 = tr3;
                }
            }
        }
    }

Source image

Result: 3 thresholds / 4 classes

阈值:179、92、25

【讨论】:

  • 穿了什么?你能详细说明一下吗?
猜你喜欢
  • 2014-05-07
  • 2019-10-25
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 2022-06-22
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多