2

范围

大家好,我正在尝试将此验证码转换为“黑白”(二值化)图像,其中字符为白色,其余部分(背景、线条、随机图片)为黑色。

可以在此处找到验证码的链接。刷新会给你另一个验证码。

原因:

我知道大多数人认为弄乱验证码是错误的,所以我在这里为自己辩护。这将仅用于知识/自我挑战。这些图像没有其他用途。

问题:

在研究了这些图像一段时间后,我发现一个好的方法是将颜色替换:“白色和黄色”到“Color.Black”,并且所有其他颜色都应该替换为“Color.White”。

在此之后,我将“反转”颜色,将我带到我想要的输出。

代码示例:

在这段代码中,我试图将每个图像的颜色“黑色”替换为 SkyBlue 像素。

        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 框架,我用它来减少颜色,但它根本不起作用,结果不是我期望的。

为了正确二值化此图像,我可以在这里做什么?

提前致谢,

马塞洛·林斯。

4

1 回答 1

1

您的算法不起作用的原因是您正在寻找精确匹配。但是由于 JPEG 压缩伪影,图像中的黑色并不是真正的黑色。在我加载的三个验证码中,甚至没有一个黑色 (0, 0, 0) 像素。最接近的值是 (0, 0, 4),它看起来是黑色的,但不是。

一个近似的方法是:

  • 用灰色去除通道平均值低于 220 的所有灰色(通道彼此差异小于 5%)。这会消除浅灰色细线以及灰色背景下的许多振铃 (JPEG) 伪影。
  • 用灰色替换红色、绿色或蓝色通道高于其他两个通道 25% 以上的所有像素。这会处理红色、绿色和蓝色以及它们的大部分振铃伪影。
  • 运行一个简单的去斑去除所有被五个灰色包围的非灰色像素,并且在 20% 范围内没有其他相同颜色的像素。

在这个过程结束时,背景全是灰色的,剩下的所有非灰色像素都是字符。

一些有用的功能:

// 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.
于 2012-09-17T21:11:46.177 回答