清理验证码图片
Cleaning up captcha image
我正在尝试清理上面的图像我尝试了几种不同的方法使用 open cv,我要么将原始图像过度腐蚀到部分字母丢失的程度,如下所示:
我不太确定如何去掉最后一条对角线并修复 S,目前我的代码是:
import cv2
import matplotlib.pylab as plt
img = cv2.imread('/captcha_3blHDdS.png')
#make image gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#Blur
blur = cv2.GaussianBlur(gray,(5,5),0)
bilateral = cv2.bilateralFilter(gray,5,75,75)
#Thresholding
ret, thresh = cv2.threshold(bilateral,25,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#Kernal
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#other things
erosion = cv2.erode(thresh,kernel,iterations = 1)
closing = cv2.morphologyEx(erosion, cv2.MORPH_CLOSE, kernel, iterations = 1)
#Transform image
dist_transform = cv2.distanceTransform(closing,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.02*dist_transform.max(),255,cv2.THRESH_BINARY)#,255,0)
#kernel_1
kernel_1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 2))
dilation_1 = cv2.dilate(sure_fg,kernel_1,iterations = 2)
erosion_1 = cv2.erode(dilation_1,kernel_1,iterations = 3)
plt.imshow(erosion_1, 'gray')
如有任何帮助,我们将不胜感激,以下是从验证码生成的图像类型的更多示例;
也将 link 保存到包含 images
的文件夹
仔细查看您的验证码。该图像中的大部分灰尘具有与文本不同的灰度值。
正文在140
,尘埃在112
。
一个简单的灰度过滤在这里会有很大帮助。
from scipy.misc import imread, imsave
import numpy as np
infile = "A1nO4.png"
outfile = "A1nO4_out.png"
im = imread(infile, True)
out_im = np.ones(im.shape) * 255
out_im[im == 140] = 0
imsave(outfile, out_im)
现在使用 cv2.dilate
(cv2.erode
在黑底白字上)去除残留的灰尘。
这是一个使用 OpenCvSharp 的 C# 解决方案(应该很容易转换回 python/c++,因为方法名称完全相同)。
它使用 OpenCV 的 inpainting 技术来避免在可能 运行 OCR 阶段之前破坏过多的字母。我们可以看到线条的颜色与其他线条的颜色不同,因此我们将在任何 grayscaling/blackwhiting 之前尽早使用该信息。步骤如下:
- 使用线条的颜色构建遮罩 (#707070)
- 扩大掩码一点,因为线条可能是用抗锯齿绘制的
- 使用此蒙版重绘 ("inpaint") 原始图像,这将删除线条,同时保留线条下方的大部分内容(字母)。注意我们可以去掉before那一步的小点,我觉得会更好
- 应用一些 dilate/blur/threshold 来完成
这是面具:
结果如下:
这是样本集的结果:
这是 C# 代码:
static void Decaptcha(string filePath)
{
// load the file
using (var src = new Mat(filePath))
{
using (var binaryMask = new Mat())
{
// lines color is different than text
var linesColor = Scalar.FromRgb(0x70, 0x70, 0x70);
// build a mask of lines
Cv2.InRange(src, linesColor, linesColor, binaryMask);
using (var masked = new Mat())
{
// build the corresponding image
// dilate lines a bit because aliasing may have filtered borders too much during masking
src.CopyTo(masked, binaryMask);
int linesDilate = 3;
using (var element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(linesDilate, linesDilate)))
{
Cv2.Dilate(masked, masked, element);
}
// convert mask to grayscale
Cv2.CvtColor(masked, masked, ColorConversionCodes.BGR2GRAY);
using (var dst = src.EmptyClone())
{
// repaint big lines
Cv2.Inpaint(src, masked, dst, 3, InpaintMethod.NS);
// destroy small lines
linesDilate = 2;
using (var element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(linesDilate, linesDilate)))
{
Cv2.Dilate(dst, dst, element);
}
Cv2.GaussianBlur(dst, dst, new Size(5, 5), 0);
using (var dst2 = dst.BilateralFilter(5, 75, 75))
{
// basically make it B&W
Cv2.CvtColor(dst2, dst2, ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(dst2, dst2, 255, 255, ThresholdTypes.Otsu);
// save the file
dst2.SaveImage(Path.Combine(
Path.GetDirectoryName(filePath),
Path.GetFileNameWithoutExtension(filePath) + "_dst" + Path.GetExtension(filePath)));
}
}
}
}
}
}
这不是一个非常可靠的解决方案,但在大多数情况下可能会有所帮助:
通过查看上面发布的图像示例,我可以观察到对角线的一个共同特征,即它们在图像边缘开始或结束,而我们感兴趣的文本位于中间,因此我们可以通过这种方式通过在图像矩阵的第一行和最后几行和几列中搜索它们来确定这些对角线的像素值,并将它们作为噪声消除。
而且这种方法也可能花费更少的时间。
我正在尝试清理上面的图像我尝试了几种不同的方法使用 open cv,我要么将原始图像过度腐蚀到部分字母丢失的程度,如下所示:
我不太确定如何去掉最后一条对角线并修复 S,目前我的代码是:
import cv2
import matplotlib.pylab as plt
img = cv2.imread('/captcha_3blHDdS.png')
#make image gray
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
#Blur
blur = cv2.GaussianBlur(gray,(5,5),0)
bilateral = cv2.bilateralFilter(gray,5,75,75)
#Thresholding
ret, thresh = cv2.threshold(bilateral,25,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
#Kernal
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#other things
erosion = cv2.erode(thresh,kernel,iterations = 1)
closing = cv2.morphologyEx(erosion, cv2.MORPH_CLOSE, kernel, iterations = 1)
#Transform image
dist_transform = cv2.distanceTransform(closing,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform,0.02*dist_transform.max(),255,cv2.THRESH_BINARY)#,255,0)
#kernel_1
kernel_1 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1, 2))
dilation_1 = cv2.dilate(sure_fg,kernel_1,iterations = 2)
erosion_1 = cv2.erode(dilation_1,kernel_1,iterations = 3)
plt.imshow(erosion_1, 'gray')
如有任何帮助,我们将不胜感激,以下是从验证码生成的图像类型的更多示例;
也将 link 保存到包含 images
的文件夹仔细查看您的验证码。该图像中的大部分灰尘具有与文本不同的灰度值。
正文在140
,尘埃在112
。
一个简单的灰度过滤在这里会有很大帮助。
from scipy.misc import imread, imsave
import numpy as np
infile = "A1nO4.png"
outfile = "A1nO4_out.png"
im = imread(infile, True)
out_im = np.ones(im.shape) * 255
out_im[im == 140] = 0
imsave(outfile, out_im)
现在使用 cv2.dilate
(cv2.erode
在黑底白字上)去除残留的灰尘。
这是一个使用 OpenCvSharp 的 C# 解决方案(应该很容易转换回 python/c++,因为方法名称完全相同)。
它使用 OpenCV 的 inpainting 技术来避免在可能 运行 OCR 阶段之前破坏过多的字母。我们可以看到线条的颜色与其他线条的颜色不同,因此我们将在任何 grayscaling/blackwhiting 之前尽早使用该信息。步骤如下:
- 使用线条的颜色构建遮罩 (#707070)
- 扩大掩码一点,因为线条可能是用抗锯齿绘制的
- 使用此蒙版重绘 ("inpaint") 原始图像,这将删除线条,同时保留线条下方的大部分内容(字母)。注意我们可以去掉before那一步的小点,我觉得会更好
- 应用一些 dilate/blur/threshold 来完成
这是面具:
结果如下:
这是样本集的结果:
这是 C# 代码:
static void Decaptcha(string filePath)
{
// load the file
using (var src = new Mat(filePath))
{
using (var binaryMask = new Mat())
{
// lines color is different than text
var linesColor = Scalar.FromRgb(0x70, 0x70, 0x70);
// build a mask of lines
Cv2.InRange(src, linesColor, linesColor, binaryMask);
using (var masked = new Mat())
{
// build the corresponding image
// dilate lines a bit because aliasing may have filtered borders too much during masking
src.CopyTo(masked, binaryMask);
int linesDilate = 3;
using (var element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(linesDilate, linesDilate)))
{
Cv2.Dilate(masked, masked, element);
}
// convert mask to grayscale
Cv2.CvtColor(masked, masked, ColorConversionCodes.BGR2GRAY);
using (var dst = src.EmptyClone())
{
// repaint big lines
Cv2.Inpaint(src, masked, dst, 3, InpaintMethod.NS);
// destroy small lines
linesDilate = 2;
using (var element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new Size(linesDilate, linesDilate)))
{
Cv2.Dilate(dst, dst, element);
}
Cv2.GaussianBlur(dst, dst, new Size(5, 5), 0);
using (var dst2 = dst.BilateralFilter(5, 75, 75))
{
// basically make it B&W
Cv2.CvtColor(dst2, dst2, ColorConversionCodes.BGR2GRAY);
Cv2.Threshold(dst2, dst2, 255, 255, ThresholdTypes.Otsu);
// save the file
dst2.SaveImage(Path.Combine(
Path.GetDirectoryName(filePath),
Path.GetFileNameWithoutExtension(filePath) + "_dst" + Path.GetExtension(filePath)));
}
}
}
}
}
}
这不是一个非常可靠的解决方案,但在大多数情况下可能会有所帮助:
通过查看上面发布的图像示例,我可以观察到对角线的一个共同特征,即它们在图像边缘开始或结束,而我们感兴趣的文本位于中间,因此我们可以通过这种方式通过在图像矩阵的第一行和最后几行和几列中搜索它们来确定这些对角线的像素值,并将它们作为噪声消除。 而且这种方法也可能花费更少的时间。