拖延症又犯了, 上周第一篇: 机器学习系列之: 怎么样数鸡 ? (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, 这里就不多说明了.
假设以下方法用于得到这个阀值.
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;
计得上周的这个鸡图么?
来, 课后作业, 留言告诉我, 这张图的 阈值 是多少, 前三名答对的每人奖励 3 SBD.
未完待续……
- 机器学习系列之: 怎么样数鸡?
- 机器学习系列之: 怎么样数鸡鸡? 大津算法来计算阈值
- 机器学习系列之: 怎么样数鸡鸡? 分类 Clustering
GD Star Rating
loading...
本文一共 541 个汉字, 你数一下对不对.loading...
上一篇: Happy Mooncake Festival! 公司(英国)每年都会给员工发月饼(说说厦门中秋博饼)
下一篇: 隐藏STEEMIT钱包, 你能忍住不看么?
扫描二维码,分享本文到微信朋友圈

貌似5只母鸡, 没用公鸡, 阀不出值!