如何替换C#位图中相同颜色的色调变化



范围

大家好,我正在尝试将这个captcha转换为"黑白"(二进制)图像,其中字符是白色的,其余部分(背景、线条、随机图片)是黑色的。

captcha的链接可以在这里找到。清爽会给你带来另一个captcha。

原因:

我知道大多数人都认为惹上队长是错误的,所以我在这里为自己辩护。这将仅用于知识/自我挑战。这些图像没有其他用途的计划。

问题:

在研究了这些图像一段时间后,我发现一个好的方法是将颜色替换为:"白色和黄色"为"彩色黑色",其他所有颜色都应该替换为"彩色白色"。

在这之后,我只是"反转"颜色,引导我到我想要的输出。

代码示例:

在这个代码中,我试图将每个图像的颜色"黑色"替换为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框架,我正在使用它来减少颜色,但它根本不起作用,结果不是我预期的。

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

提前感谢

林。

您的算法不起作用的原因是您正在寻找精确的匹配。但是由于JPEG压缩伪影,图像中的黑色并不是真正的黑色;在我加载的三个CAPTCHA中,甚至没有一个黑色(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.

最新更新