Ответ 1
Вот решение С#, используя OpenCvSharp (что должно быть легко преобразовать обратно в python/С++, потому что имена методов - это точно то же самое).
Он использует метод OpenCV inpainting, чтобы избежать слишком большого количества писем, прежде чем, возможно, запустил этап OCR. Мы можем видеть, что линии имеют другой цвет, чем остальные, поэтому мы будем использовать эту информацию очень рано, прежде чем любой оттенок серого/черный. Шаги следующие:
- создайте маску из линий, используя свой цвет (# 707070)
- расширение, которое маскирует немного, потому что линии, возможно, были нарисованы с помощью сглаживания
- перерисовать ( "inpaint" ) исходное изображение, используя эту маску, которая удалит строки, сохранив большую часть того, что было ниже строк (букв). Заметьте, что мы могли бы удалить небольшие точки до этого шага, я думаю, что было бы еще лучше
- примените некоторое расширение/размытие/порог для завершения
Вот маска:
Вот результат:
Вот результат на выборке:
Вот код С#:
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)));
}
}
}
}
}
}