大津法二值化的应用与实现

一、大津法二值化算法

大津法是一种自适应阈值法,该算法是由日本学者大津展之于1979年提出的,也被称为OTSU算法。

该算法是对灰度图像进行二值化的一种方法,它通过计算图像的阈值,将图像分成前景和背景两部分。阈值能够根据图像的直方图分布情况自适应的调整。

该算法的主要思路如下:

1、对图像的每一个灰度值进行统计,得到灰度直方图。

2、遍历灰度直方图,计算每一个灰度值的“类内方差”。类内方差度量了同一区域内像素灰度分布的聚集程度,方差越小,表示像素值分布越聚集,对应的区域越容易被划分为背景或者前景。

3、选取类内方差最小的灰度阈值作为二值化的阈值。

二、大津法二值化的代码实现

接下来是一个C语言中实现大津法二值化的示例代码:

// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度

int threshold = 0;
int pixelCount[256] = {0};
float pixelProb[256] = {0.0f};
float cumProb[256] = {0.0f};
float cumMean[256] = {0.0f};
float sigma[256] = {0.0f};

// 计算像素值出现的频率
for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
        int pixel = img[i*w + j];
        pixelCount[pixel]++;
    }
}

// 计算像素值出现的概率
for (int i = 0; i < 256; i++) {
    pixelProb[i] = (float)pixelCount[i] / (float)(w * h);
}

// 计算累积概率和累积分布均值
for (int i = 0; i < 256; i++) {
    if (i == 0) {
        cumProb[i] = pixelProb[i];
        cumMean[i] = i * pixelProb[i];
    } else {
        cumProb[i] = cumProb[i-1] + pixelProb[i];
        cumMean[i] = cumMean[i-1] + i * pixelProb[i];
    }
}

// 计算全局平均值
float globalMean = cumMean[255];

// 计算类内方差
for (int i = 0; i < 256; i++) {
    if (i == 0 || cumProb[i] == 1.0f) {
        sigma[i] = 0.0f;
    } else {
        float weight = cumProb[i];
        float mean = cumMean[i] / cumProb[i];
        sigma[i] = (globalMean * weight - mean) * (globalMean * weight - mean) / (weight * (1.0f - weight));
    }
}

// 选取类内方差最小的像素值作为阈值
float maxSigma = 0.0f;
for (int i = 0; i  maxSigma) {
        maxSigma = sigma[i];
        threshold = i;
    }
}

// 对图像进行二值化
for (int i = 0; i < h; i++) {
    for (int j = 0; j  threshold) {
            img[i*w + j] = 255;
        } else {
            img[i*w + j] = 0;
        }
    }
}

三、大津法二值化的程序实现

除了使用C语言实现大津法二值化之外,我们还可以使用其他的编程语言实现。下面是使用MATLAB实现大津法二值化的示例代码:

% img -- 图像数据

histogram = imhist(img);
pixelProb = histogram / sum(histogram);

cumProb = cumsum(pixelProb);
cumMean = cumsum((0:255)'.*pixelProb);

globalMean = cumMean(end);

sigma = (globalMean*cumProb - cumMean).^2 ./ (cumProb.*(1-cumProb));

[~, threshold] = max(sigma);

bwImg = imbinarize(img, threshold/255); 

使用MATLAB时,可以使用imhist函数计算图像的直方图,使用imbinarize函数进行二值化。

四、大津法二值化后如何知道具体阈值

大津法二值化得到的阈值可以用于对图像进行二值化处理。

我们可以在处理图像的时候,将得到的阈值作为参数传入二值化函数。在C语言中,可以使用以下代码进行二值化:

int threshold = 128;
// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度

for (int i = 0; i < h; i++) {
    for (int j = 0; j  threshold) {
            img[i*w + j] = 255;
        } else {
            img[i*w + j] = 0;
        }
    }
}

在MATLAB中,可以使用以下代码进行二值化:

bwImg = imbinarize(img, threshold/255); 

五、大津算法求二值化阈值选取

大津算法求二值化阈值选取是对大津法二值化的改进,该算法通过迭代的方式求出最优的阈值,从而使得阈值更加准确。

该算法主要思路如下:

1、初始化阈值T为图像的平均值。

2、将像素分为两类:小于等于阈值T和大于阈值T。

3、计算两个类的平均值:μ1和μ2。

4、计算两个类对应的类内方差:var1和var2。

5、计算全局类内方差:intraVariance。

6、将阈值T更新为使得全局类内方差最小的值。

7、重复步骤2~6,直到阈值T的变化小于给定的阈值。

下面是使用C语言实现大津算法求二值化阈值选取的示例代码:

// img -- 图像数据
// w -- 图像宽度
// h -- 图像高度

#define THRESHOLD_DELTA 0.5f

float threshold = 0.0f;

while (true) {

    int pixelCount1 = 0;
    int pixelCount2 = 0;
    float pixelProb1 = 0.0f;
    float pixelProb2 = 0.0f;
    float cumProb1 = 0.0f;
    float cumProb2 = 0.0f;
    float cumMean1 = 0.0f;
    float cumMean2 = 0.0f;
    float intraVariance = 0.0f;

    // 遍历图像,计算各种参数
    for (int i = 0; i < h; i++) {
        for (int j = 0; j  threshold) {
                pixelCount1++;
                cumMean1 += pixel;
            } else {
                pixelCount2++;
                cumMean2 += pixel;
            }
        }
    }

    pixelProb1 = (float)pixelCount1 / (float)(w * h);
    pixelProb2 = (float)pixelCount2 / (float)(w * h);
    cumProb1 = pixelProb1;
    cumProb2 = pixelProb2;
    cumMean1 /= pixelCount1;
    cumMean2 /= pixelCount2;

    // 计算类内方差和全局方差
    for (int i = 0; i < h; i++) {
        for (int j = 0; j  threshold) {
                intraVariance += (pixel-cumMean1)*(pixel-cumMean1);
            } else {
                intraVariance += (pixel-cumMean2)*(pixel-cumMean2);
            }
        }
    }

    intraVariance /= (float)(w*h);

    // 更新阈值
    float newThreshold = (cumMean1+cumMean2) / 2.0f;
    if (fabs(newThreshold-threshold) < THRESHOLD_DELTA) {
        threshold = newThreshold;
        break;
    }
    threshold = newThreshold;
}

// 对图像进行二值化
for (int i = 0; i < h; i++) {
    for (int j = 0; j  threshold) {
            img[i*w + j] = 255;
        } else {
            img[i*w + j] = 0;
        }
    }
}

上述代码首先定义了一个阈值的变化阈值,当两次迭代之间的阈值变化小于该值时,算法停止。接下来进行迭代,直到达到停止条件。在每一次迭代过程中,首先将图像分为两类,统计每一类的像素值频率和像素值分布情况等参数,然后计算全局类内方差,更新阈值。最后,使用更新后的阈值对图像进行二值化处理。

原创文章,作者:EPXP,如若转载,请注明出处:https://www.506064.com/n/142125.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
EPXPEPXP
上一篇 2024-10-10 08:47
下一篇 2024-10-10 08:47

发表回复

登录后才能评论