复制TesserCap的斩波滤波器去除captcha图像的背景噪声

2024-04-26 10:05:30 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一张这样的验证码图片:

使用McAfee中名为TesserCap的实用程序,我可以对图像应用“斩波”过滤器。(在运行它之前,我确保图像中只有两种颜色,白色和黑色。)在文本框中使用值为2的过滤器的结果给我留下了深刻的印象。它准确地消除了大部分噪音,但保留了正文,结果是:

我想在自己的一个脚本上实现类似的东西,所以我试图找出TesserCap使用的图像处理库。我什么也找不到,结果发现它用自己的代码来处理图像。然后我阅读了this whitepaper,它准确地解释了程序的工作原理。它向我描述了这个斩波滤波器的功能:

If the contiguous number of pixels for given grayscale values are less than the number provided in the numeric box, the chopping filter replaces these sequences with 0 (black) or 255 (white) as per user choice. The CAPTCHA is analyzed in both horizontal and vertical directions and corresponding changes are made.

我不确定我是否明白它在做什么。我的脚本是用Python编写的,所以我尝试使用PIL来操作像素,就像上面提到的那样。听起来有点简单,但我失败了,可能是因为我不知道过滤器到底在做什么:

(这是由稍微不同的使用圆形图案的验证码制成的。)

我还试着看看是否可以用ImageMagick的convert.exe轻松完成。他们的选择是完全不同的。使用-中值和一些-形态学命令有助于减少一些噪音,但讨厌的点出现,字母变得非常扭曲。这并不像用泰瑟卡普做斩波滤波器那么简单。

所以,我的问题是:如何在Python中实现TesserCap的斩波过滤器,是使用PIL还是ImageMagick?斩波滤波器比我尝试过的任何一种方法都好得多,但我似乎无法复制它。我已经研究了好几个小时了,还没发现什么。


Tags: andthein图像脚本过滤器numberpil
2条回答

算法基本上检查一行中是否有多个目标像素(在本例中是非白色像素),如果像素数小于或等于chop因子,则更改这些像素。

例如,在像素的样本行中,其中#为黑色,-为白色,应用2的chop因子将--#--###-##---#####---#-#转换为------###-------#####-------。这是因为存在小于或等于2像素的黑色像素序列,并且这些序列被替换为白色。大于2像素的连续序列保持不变。

这是在我的Python代码(如下)中实现的chop算法在您文章的原始图像上的结果:

'Chopped' image

为了将此应用于整个图像,只需对每一行和每一列执行此算法。下面是实现这一点的Python代码:

import PIL.Image
import sys

# python chop.py [chop-factor] [in-file] [out-file]

chop = int(sys.argv[1])
image = PIL.Image.open(sys.argv[2]).convert('1')
width, height = image.size
data = image.load()

# Iterate through the rows.
for y in range(height):
    for x in range(width):

        # Make sure we're on a dark pixel.
        if data[x, y] > 128:
            continue

        # Keep a total of non-white contiguous pixels.
        total = 0

        # Check a sequence ranging from x to image.width.
        for c in range(x, width):

            # If the pixel is dark, add it to the total.
            if data[c, y] < 128:
                total += 1

            # If the pixel is light, stop the sequence.
            else:
                break

        # If the total is less than the chop, replace everything with white.
        if total <= chop:
            for c in range(total):
                data[x + c, y] = 255

        # Skip this sequence we just altered.
        x += total


# Iterate through the columns.
for x in range(width):
    for y in range(height):

        # Make sure we're on a dark pixel.
        if data[x, y] > 128:
            continue

        # Keep a total of non-white contiguous pixels.
        total = 0

        # Check a sequence ranging from y to image.height.
        for c in range(y, height):

            # If the pixel is dark, add it to the total.
            if data[x, c] < 128:
                total += 1

            # If the pixel is light, stop the sequence.
            else:
                break

        # If the total is less than the chop, replace everything with white.
        if total <= chop:
            for c in range(total):
                data[x, y + c] = 255

        # Skip this sequence we just altered.
        y += total

image.save(sys.argv[3])

尝试以下操作(伪代码):

for each row of pixels:
    if there is a group of about 3 or more pixels in a row, leave them
    else remove the pixels

然后对列重复同样的操作。看起来至少有点管用。这样水平和垂直移动也会删除水平/垂直线。

相关问题 更多 >