我正试图将图片二值化,首先当然是准备好了(灰度) 我的方法是找到灰度的最大值和最小值,然后找到中间值(这是我的阈值),然后迭代所有像素,我将当前值与阈值进行比较,如果灰度大于阈值,我把0放在一个矩阵中,或者放在其他放的1中。 但现在我正面临这个问题。通常我是用白色背景二值化图像,所以我的算法进一步基于这个特征。但是当我遇到黑色背景的图像时,一切都会崩溃,但我仍然可以清楚地看到数字(现在是0和1的开关位置) 我怎样才能解决这个问题,让我的程序更常见? 也许我最好找另一种二值化方式/
P.S。我找了一个可以理解的Otsu阈值方法的解释,但是我似乎没有为这种困难做好准备,或者我每次都找到非常复杂的解释,但是我不能用C写出来。如果有人能在这里找到,这太棒了。
很抱歉没有回答问题,只是没有看到他们 首先 - 代码
for (int y=1;y<Source->Picture->Height;y++)
for (int x=1;x<Source->Picture->Width;x++)
{
unsigned green = GetGValue(Source->Canvas->Pixels[x][y]);
unsigned red = GetRValue(Source->Canvas->Pixels[x][y]);
unsigned blue = GetBValue(Source->Canvas->Pixels[x][y]);
threshold = (0.2125*red+0.7154*green+0.0721*blue);
if (min>threshold)
min=threshold;
if (max<threshold)
max = threshold;
}
middle = (max+min)/2;
然后遍历图像
if (threshold<middle)
{
picture[x][y]=1;
fprintf( fo,"1");
} else {
picture[x][y]=0;
fprintf( fo,"0");
}
}
fprintf( fo,"\n");
}
fclose(fo);
所以我得到一个像这样的文件
000000000
000001000
000001000
000011000
000101000
000001000
000001000
000001000
000000000
在这里你可以看到一个例子。
然后我可以插入它,或者做其他事情(识别),这取决于零和一个。 但是,如果我切换颜色,数字将不相同。所以这种认可是行不通的。我想知道是否有一个可以帮助我的算法。
答案 0 :(得分:1)
我会用另一种方法解决这个问题:
算法如下:
int bin [256];
foreach pixel in image
bin[pixelvalue]++;
endfor // this computes the histogram of the image
int thresholdCount = ImageWidth * ImageSize / 2;
int count = 0;
for int i = 0 to 255
count = count + bin[i];
if( count > thresholdCount)
threshold = i;
break; // we are done
endif
endfor
此算法不会计算累积直方图本身,而是使用图像直方图来执行我之前所说的。
答案 1 :(得分:1)
如果您的算法适用于白色背景但黑色背景无效,您只需要检测何时有黑色背景并反转值。如果假设背景值更常见,则可以简单地计算结果中的1和0的数量;如果0更大,则反转结果。
答案 2 :(得分:1)
我从来没有听说过Otsu的方法,但是我理解了一些维基百科页面,所以我会尝试简化它。
1 Count how many pixels are at each level of darkness.
2 "Guess" a threshold.
3 Calculate the variance of the counts of darkness less than the threshold
4 Calculate the variance of the counts of darkness greater than the threshold
5 If the variance of the darker side is greater, guess a darker threshold,
else guess a higher threshold.
Do this like a binary search so that it ends.
6 Turn all pixels darker than threshold black, the rest white.
Otsu的方法实际上是“最大化类间方差”,但我不理解那部分数学。
方差的概念是“相互之间的价值相差多远”。低差异意味着一切都很相似。高差异意味着价值相差很大。彩虹的变化非常高,颜色很多。 stackoverflow背景的方差为0,因为它都是完全白色的,没有其他颜色。差异计算或多或少像这样计算
double variance(unsigned int* counts, int size, int threshold, bool above) {
//this is a quick trick to turn the "upper" into lower, save myself code
if (above) return variance(counts, size-threshold, size-threshold, false);
//first we calculate the average value
unsigned long long atotal=0;
unsigned long long acount=0;
for(int i=0; i<threshold; ++i) {
atotal += counts[i]*i //number of px times value
acount += counts[i];
}
//finish calculating average
double average = double(atotal)/count;
//next we calculate the variance
double vtotal=0;
for(int i=0; i<threshold; ++i) {
//to do so we get each values's difference from the average
double t = std::abs(i-average);
//and square it (I hate mathmaticians)
vtotal += counts[i]*t*t;
}
//and return the average of those squared values.
return vtotal/count;
}
答案 3 :(得分:1)
您应该使用所有点的中位数作为阈值,而不是使用min和max的均值。一般来说,第k个百分位数(k =你想要的黑色点的百分比)更合适。
另一种解决方案是将数据集中到两个集群中。