机器学习系列之: 怎么样数鸡鸡? (2) 大津算法来计算阈值


拖延症又犯了, 上周第一篇: 机器学习系列之: 怎么样数鸡 ? (1) 说到了先把图片转成灰度 (Grey Scale), 接下来我们要做的就是 计算阈值 (Threshold)

当我们进行图片灰度化的时候, 我们把 RGBA 图片每个相素4个字节转成了 亮度 1个字节, 用了以下公式:

亮度 = R * 0.21 + G * 0.72 + B * 0.07

但是这对于后面要分类还是不太方便, 我们理想只需要 0 和1 , 1代表是鸡, 0代表是空气, 所以这一步计算阈值就是要计算出一个值, 然后之后根据这个 阈值 (Threshold) 来二分成 0 或 1. 比如 我们已经计算得到 threshold 然后可以遍历图片的每个相素, 依次按 RGB 三个值的平均计算得到当前的密度(Intensity) 和这个阀值判断二分成前景和背景(鸡和空气) :

本文的C#代码来自于 微软大神 Gary Short.

grayscale-to-bin 机器学习系列之: 怎么样数鸡鸡? (2) 大津算法来计算阈值 I.T. 数据结构与算法

灰度图像二值化

大津算法 Otsu’s Method

大津算法(Otsu’s Method)是计算机图形学上用来把一个灰度图片退化为黑白(二值)图像. 具体的算法可以看 WIKI, 这里就不多说明了.

假设以下方法用于得到这个阀值.

1
private static int GetThreshold(Bitmap image)
private static int GetThreshold(Bitmap image)

参数为图片(灰度), 首先我们得把图片变成字节数组(每个相素为1个字节8位)

1
byte[] imageBytes =  (byte[])new ImageConverter().ConvertTo(image, typeof(byte[]));
byte[] imageBytes =  (byte[])new ImageConverter().ConvertTo(image, typeof(byte[]));

然后这个大津算法需要图片的 Histogram (直方图), 横坐标是0到255个格子, 纵坐标是出现的次数.

1
2
3
4
5
6
7
int[] histogram = new int[256];
int ptr = 0;
while (ptr < imageBytes.Length)  {
    int h = 0xFF & imageBytes[ptr];
    histogram[h]++;
    ptr++;
}
int[] histogram = new int[256];
int ptr = 0;
while (ptr < imageBytes.Length)  {
    int h = 0xFF & imageBytes[ptr];
    histogram[h]++;
    ptr++;
}

把出现的次数计算成概率:

1
2
3
int totalPixels = imageBytes.Length;  // 相素点数
float sumOfIntensities = 0;
for (int t = 0; t < 256; t++) sumOfIntensities += t * histogram[t];
int totalPixels = imageBytes.Length;  // 相素点数
float sumOfIntensities = 0;
for (int t = 0; t < 256; t++) sumOfIntensities += t * histogram[t];

接下来就是大津算法得到这个阀值使得两类内方差(Variance)最小, 也就是类间(Intra Class)方差最大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 穷举阀值得到能使内间类别区别最大的值
float sumOfBackgroundIntensities = 0;
int backgroundWeight = 0;
int foregroundWeight = 0;
float maximumInterClassVariance = 0;
int threshold = 0;
for (int t = 0; t < 256; t++)
{
    backgroundWeight += histogram[t];
    if (backgroundWeight == 0) continue;
 
    foregroundWeight = totalPixels - backgroundWeight;
    if (foregroundWeight == 0) break;
 
    sumOfBackgroundIntensities += (float)(t * histogram[t]);
 
    float backgroundMean =
        sumOfBackgroundIntensities / backgroundWeight;
 
    float foregroundMean =
        (sumOfIntensities - sumOfBackgroundIntensities) / foregroundWeight;
 
    // 计算内间方差
    float intraClassVariance =
        (float)backgroundWeight * (float)foregroundWeight *
            (backgroundMean - foregroundMean) *
            (backgroundMean - foregroundMean);
 
    // 更新最大类间方差值
    if (intraClassVariance > maximumInterClassVariance)
    {
        maximumInterClassVariance = intraClassVariance;
        threshold = t;
    }
}
return threshold;
// 穷举阀值得到能使内间类别区别最大的值
float sumOfBackgroundIntensities = 0;
int backgroundWeight = 0;
int foregroundWeight = 0;
float maximumInterClassVariance = 0;
int threshold = 0;
for (int t = 0; t < 256; t++)
{
    backgroundWeight += histogram[t];
    if (backgroundWeight == 0) continue;

    foregroundWeight = totalPixels - backgroundWeight;
    if (foregroundWeight == 0) break;

    sumOfBackgroundIntensities += (float)(t * histogram[t]);

    float backgroundMean =
        sumOfBackgroundIntensities / backgroundWeight;

    float foregroundMean =
        (sumOfIntensities - sumOfBackgroundIntensities) / foregroundWeight;

    // 计算内间方差
    float intraClassVariance =
        (float)backgroundWeight * (float)foregroundWeight *
            (backgroundMean - foregroundMean) *
            (backgroundMean - foregroundMean);

    // 更新最大类间方差值
    if (intraClassVariance > maximumInterClassVariance)
    {
        maximumInterClassVariance = intraClassVariance;
        threshold = t;
    }
}
return threshold;

计得上周的这个鸡图么?

count-chicken 机器学习系列之: 怎么样数鸡鸡? (2) 大津算法来计算阈值 I.T. 数据结构与算法

count-chicken

来, 课后作业, 留言告诉我, 这张图的 阈值 是多少, 前三名答对的每人奖励 3 SBD.

未完待续……

GD Star Rating
loading...
本文一共 541 个汉字, 你数一下对不对.
机器学习系列之: 怎么样数鸡鸡? (2) 大津算法来计算阈值. (AMP 移动加速版本)
上一篇: Happy Mooncake Festival! 公司(英国)每年都会给员工发月饼(说说厦门中秋博饼)
下一篇: 隐藏STEEMIT钱包, 你能忍住不看么?

扫描二维码,分享本文到微信朋友圈
b2cd33abe9603d7470f97da11540b8ad 机器学习系列之: 怎么样数鸡鸡? (2) 大津算法来计算阈值 I.T. 数据结构与算法

一条回应

评论