拖延症又犯了,上周第一篇: 机器学习系列之:怎么样数鸡 ?(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
大津算法 Otsu's Method
大津算法(Otsu's Method)是计算机图形学上用来把一个灰度图片退化为黑白(二值)图像。具体的算法可以看 WIKI,这里就不多说明了。
假设以下方法用于得到这个阀值。
private static int GetThreshold(Bitmap image)
参数为图片(灰度),首先我们得把图片变成字节数组(每个相素为1个字节8位)
byte[] imageBytes = (byte[])new ImageConverter().ConvertTo(image, typeof(byte[]));
然后这个大津算法需要图片的 Histogram (直方图),横坐标是0到255个格子,纵坐标是出现的次数。
int[] histogram = new int[256];
int ptr = 0;
while (ptr < imageBytes.Length) {
int h = 0xFF & imageBytes[ptr];
histogram[h]++;
ptr++;
}
把出现的次数计算成概率:
int totalPixels = imageBytes.Length; // 相素点数
float sumOfIntensities = 0;
for (int t = 0; t < 256; t++) sumOfIntensities += t * histogram[t];
接下来就是大津算法得到这个阀值使得两类内方差(Variance)最小,也就是类间(Intra Class)方差最大
// 穷举阀值得到能使内间类别区别最大的值
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;
计得上周的这个鸡图么?
来,课后作业,留言告诉我,这张图的 阈值 是多少,前三名答对的每人奖励 3 SBD。
未完待续……
@justyy 是CN 区的点赞机器人,对优质内容进行点赞,只要代理给 @justyy 每天收利息(100 SP 每天0.04 SBD)并且能获得一次相应至少2倍的点赞,可以认为是VP 200%+ ,详细请看:
中文区的大鱼 @htliao 都加入了这个计划(530 SP)表示支持,您还不来试试么?
@justyy 是 https://justyy.com 的博主 - 西半球知名的“土豪”博主。在大哥 @tumutanzi 的带领下加入了 STEEMIT。感谢您阅读 @justyy 的帖子 希望得到您的follow、upvote 或者是 reply 。
欢迎您发表高见,我会赞赏(Upvote)高质量的评论。