范围:
大家好,我正在尝试将此验证码转换为“黑白”(二值化)图像,其中字符为白色,其余部分(背景,线条,随机图片)为黑色。
可以找到验证码的链接here。刷新会给你另一个验证码。
原因:
我知道大多数人认为乱用验证码是错误的所以我在这里为自己辩护。这将仅用于知识/自我挑战。这些图像没有计划用于其他用途。
问题:
在对这些图像进行了一段时间的研究之后,我发现一个好的方法是将颜色替换为“白色和黄色”到“Color.Black”,其他每种颜色都应该替换为“Color.White。 “
在此之后,我只是“反转”颜色,将我引导到我想要的输出。
代码示例:
在此代码中,我尝试将SkyBlue Pixel的每个图像的颜色替换为“黑色”。
WebRequests wr = new WebRequests(); // My class to handle WebRequests
Bitmap bmp;
string url = "http://www.fazenda.rj.gov.br/projetoCPS/codigoImagem";
bmp = wr.GetBitmap (url);
for (int i = 1; i < bmp.Height ; i++)
{
for (int j = 1 ; j < bmp.Width ; j++)
{
if (bmp.GetPixel(j,i).Equals(Color.Black))
{
bmp.SetPixel(j,i, Color.SkyBlue);
}
}
}
这段代码根本不起作用,我不知道为什么,但在这个例子中没有像素被替换。
问题:
我怎样才能做到这一点?我在这里失踪了什么?
此外,对我来说理想的情况是将此图像的颜色“减少”为“基本”颜色,这将使我在这里的工作变得更加容易。
我已经尝试了AForge Framework,我正在使用它来减少颜色,但它根本不起作用,结果不是我预期的结果。
我可以在这做什么才能正确地将这个图像二值化?
提前致谢,
Marcello Lins。
答案 0 :(得分:1)
您的算法不起作用的原因是您正在寻找完全匹配。但是由于JPEG压缩伪像,图像中的黑色并不是真正的黑色;在我加载的三个CAPTCHAS中,甚至没有一个黑色(0,0,0)像素。最接近的值是(0,0,4),看起来是黑色,但不是。
近似方法是:
在此过程结束时,背景全部为灰色,剩下的所有非数字像素都是字符。
一些有用的功能:
// Very basic (and CIE-incorrect) check
public static int isGray(Color c)
{
if (Math.Abs(c.R - c.G) > 5 * 2.55) return 0; // Not gray. R and G too different
if (Math.Abs(c.R - c.B) > 5 * 2.55) return 0;
if (Math.Abs(c.G - c.B) > 5 * 2.55) return 0;
return 1;
}
// the blind man's test for shading :-)
public static int isShadeOfRed(Color c)
{
if (4*c.R < 5*c.G) return 0; // Red not strong enough in respect to green
if (4*c.R < 5*c.B) return 0; // Red not strong enough in respect to blue
return 1; // Red is stronger enough than green and blue to be called "shade of red"
}
// (shades of green and blue left as an exercise)
// Very basic (and CIE-incorrect) check
public static int areSameColor(Color a, Color b)
{
if (Math.Abs(a.R - b.R) > 5 * 2.55) return 0;
if (Math.Abs(a.G - b.G) > 5 * 2.55) return 0;
if (Math.Abs(a.B - b.B) > 5 * 2.55) return 0;
return 1; // "more or less" the same color
}
// This is more or less pseudo code...
public static int isNoise(int x, int y)
{
if ((x < 1) || (y < 1)) return 0; // or maybe "return 1"
if ((x+1 >= bmp.Width)||(y+1 >= bmp.Height)) return 0;
pix = bmp.GetPixel(x,y);
for (i = -1; i <= 1; i++)
for (j = -1; j <= 1; j++)
{
if ((i == 0) && (j == 0)) continue;
test = bmp.GetPixel(x+i, y+j);
if (isGray(test)) grays++;
if (isSameColor(pix, test)) same++;
}
// Pixel surrounded by grays, and has no neighbours of the same colour
// (who knows, maybe we could skip gray calculation and check altogether?)
// is noise.
if ((grays == 5) && (same == 0))
return 1;
return 0;
}
// NOTE: do not immediately set to gray pixels found to be noise, for their neighbours
// will be calculated using the new gray pixel. Damage to image might result.
// Use a copy of bmp instead.