I\'m trying to clean up the image above I\'ve tried several different methods using open cv, I either erode the original image too much to the point where parts of the
This is not a very robust solution but it might be help full in most of the cases:
By seeing the image sample posted above i can observe one common feature about the diagonal lines that they either start or end at the image edges while the text which we are interested in are in the middle so in this way we can determine the pixel values of those diagonal lines by searching them in the first and last few rows and columns of the image matrix and eliminate them as noise. And this approach also might be less time costly.
Take a closer look to your captcha. most of the dust in that image has a different grayscale value than the text.
The text is in 140
and the dust is in 112
.
A simple grayscale filtering will help a lot here.
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)
Now use cv2.dilate
(cv2.erode
on a white on black text) to get rid of the remaining dust.
Here is a C# solution using OpenCvSharp (which should be easy to convert back to python/c++ because the method names are exactly the same).
It uses OpenCV's inpainting technique to avoid destroying too much of the letters before possibly running an OCR phase. We can see that the lines have a different color than the rest, so we'll use that information very early, before any grayscaling/blackwhiting. Steps are as follow:
Here is the mask:
Here is the result:
Here is the result on sample set:
Here is the C# code:
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)));
}
}
}
}
}
}