Как стать автором
Обновить

Знакомство с OCR библиотекой tessnet2 (язык C#)

Время на прочтение 5 мин
Количество просмотров 59K
example
Буквально на днях у меня появилась необходимость распознать простой текст на картинке и совсем не было желания реализовывать свой алгоритм, т.к. знаком с теорией и знаю, что это не такое простое дело, поэтому сразу решил изучить сначала рынок готовых библиотек. Буквально несколько запросов в гугл и я понял, что ничего более подходящего мне как библиотека tessnet2 невозможно найти. Постоянно читаю хабр и знаю, что тут есть уйма статей посвященных теории OCR и очень удивился, что нет ничего о библиотеке tessnet2.

tessnet2 основана на Tesseract OCR


Движок Tesseract OCR был одним из 3-х лучших движков представленных в 1995 году на UNLV Accuracy test. В период между 1995 годом и 2006 годом он был немного доработан, но, вероятно, это один из наиболее точных OCR движков, который доступен с открытым исходным кодом. Код, который доступен будет читать бинарные, серые или цветное изображение и выводить текст. Чтение TIFF построено так, что будут читаться несжатые TIFF изображения или могут быть добавлены Libtiff для чтения сжатых изображений.

Как использовать Tessnet2:
1. Загружаем библиотеку, добавляем ссылку (reference) на Tessnet2.dll в .NET проекте.
2. Загружаем нужный нам язык (лично мне необходим английский) (tesseract-2.00.eng.tar.gz) и складываем в папку tessdata. Папка tessdata обязательно должна быть рядом с исполняемым файлом нашего приложения.

Для того, чтобы прочитать текст с картинки достаточно такого текста:
Bitmap image = new Bitmap("eurotext.tif");
tessnet2.Tesseract ocr = new tessnet2.Tesseract();
ocr.SetVariable("tessedit_char_whitelist", "0123456789"); // If digit only
ocr.Init(@"c:\temp", " eng ", false); // To use correct tessdata
List<tessnet2.Word> result = ocr.DoOCR(image, Rectangle.Empty);
foreach (tessnet2.Word word in result)
  Console.WriteLine("{0} : {1}", word.Confidence, word.Text);


* This source code was highlighted with Source Code Highlighter.

Я был очень рад результату, поэтому сразу вспомнил о том, что несколько месяцев назад прикручивал сервис для разгадывания каптч для одного проекта, сразу скажу, что ничего хорошего из этого не вышло, там нужна была скорость, но её не удалось там получить, т.к. подобные сервисы не способны её обеспечить, да и результат как правило плачевный, оно и понятно, т.к. платят там от 1 доллара за 1000 правильно введённых каптч, что мягко сказать ужасно. Поэтому эксперимента ради я решил поиграть с данной библиотекой на том примере.
Исходными данными для нас будет являться каптча, на которой нужно произвести простейшие действия над двумя числами и получить ответ. Звучит довольно просто, но вот проблема ещё в том, что все символы разных цветов и имеется динамический фон, порой даже мне (человеку) сложно понять сходу, что там написано.

Сразу привожу результаты работы программы, после чего я расскажу как это всё работает:

screenshot1

screenshot2

screenshot3

screenshot4

screenshot5

На скриншотах чётко видно, что библиотека не может ничего разгадать из-за кучи линий, порой мешает и фон, который был убран не целиком. Поэтому я разработал свой небольшой алгоритм для чистки картинки, ничего в нём грандиозного нет, я просто отступаю несколько пикселей от края и пробегаю по прямоугольнику и собираю там цвета, также собираю цвета после первой цифры и перед знаком равно (последнее это больше хак, но т.к. статья посвящена другому, то оставил так). Всё что мне надо сделать потом – это закрасить все цвета, которые попали ко мне в коллекцию и не являются белым цветом.

Из всех алгоритмов наиболее полезным может быть только алгоритм закрашивания области на Bitmap`е:
void FloodFill(Bitmap bitmap, int x, int y, Color color)
    {
      BitmapData data = bitmap.LockBits(
        new Rectangle(0, 0, bitmap.Width, bitmap.Height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
      int[] bits = new int[data.Stride / 4 * data.Height];
      Marshal.Copy(data.Scan0, bits, 0, bits.Length);

      LinkedList<Point> check = new LinkedList<Point>();
      int floodTo = color.ToArgb();
      int floodFrom = bits[x + y * data.Stride / 4];
      bits[x + y * data.Stride / 4] = floodTo;

      if (floodFrom != floodTo)
      {
        check.AddLast(new Point(x, y));
        while (check.Count > 0)
        {
          Point cur = check.First.Value;
          check.RemoveFirst();

          foreach (Point off in new Point[] {
        new Point(0, -1), new Point(0, 1),
        new Point(-1, 0), new Point(1, 0)})
          {
            Point next = new Point(cur.X + off.X, cur.Y + off.Y);
            if (next.X >= 0 && next.Y >= 0 &&
              next.X < data.Width &&
              next.Y < data.Height)
            {
              if (bits[next.X + next.Y * data.Stride / 4] == floodFrom)
              {
                check.AddLast(next);
                bits[next.X + next.Y * data.Stride / 4] = floodTo;
              }
            }
          }
        }
      }

      Marshal.Copy(bits, 0, data.Scan0, bits.Length);
      bitmap.UnlockBits(data);
    }
  }


* This source code was highlighted with Source Code Highlighter.

Для тех кому интересно самому поэкспериментировать прикрепляю исходный код.

Итог


Мы познакомились с довольно интересной библиотекой tessnet2, проверили её работу в реальных условиях, добились довольно неплохих результатов разгадывания для сложных картинок (каптч), конечно ошибки есть, но их количество ничтожно мало, тем более для данного вида каптч можно добавить проверку с помощью регулярного выражения и Вы точно будете знать, что разгаданный текст соответствует нужному формату.
Теги:
Хабы:
+63
Комментарии 21
Комментарии Комментарии 21

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн