Jump to content
Compvision.ru
VironZizu

Распознавание текста паспорта, OpenCV!

Recommended Posts

Ну, различать их просто, в интернете полно примеров, а также, как я уже писал, есть пример в стандартной поставке OpenCV - contours.c

На шарпе всё должноо быть очень похоже, но со своими особенностями.

Повторюсь ещё раз: замена CV_RETR_TREE на CV_RETR_EXTERNAL дала какие-нибудь результаты? В твоём коде же есть ContourRetrieval.Tree - замени же!

  • Like 1

Share this post


Link to post
Share on other sites

Поучаствую )

post-1-0-71943100-1408627906_thumb.png


#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include "opencv2/nonfree/nonfree.hpp"

int main(int argc, char* argv[])
{
cv::initModule_nonfree();
cv::namedWindow("result");
cv::Mat bgr_img = cv::imread("D:\\ImagesForTest\\passport.jpg");
imshow("src",bgr_img);
cv::GaussianBlur(bgr_img,bgr_img,cv::Size(3,3),1);

// int iLowH = 0;
// int iHighH = 179;
//
// int iLowS = 0;
// int iHighS = 255;
//
// int iLowV = 0;
// int iHighV = 255;
// cv::namedWindow("Control");
// Create trackbars in "Control" window
// cv::createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)
// cv::createTrackbar("HighH","Control", &iHighH, 179);
// cv::createTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255)
// cv::createTrackbar("HighS","Control", &iHighS, 255);
// cv::createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)
// cv::createTrackbar("HighV","Control", &iHighV, 255);
int k=0;
while(k!=27)
{
cv::Mat imgHSV;
cv::cvtColor(bgr_img, imgHSV, cv::COLOR_BGR2HSV);
//cv::Mat tmp_b,tmp_y;
//cv::inRange(imgHSV, cv::Scalar(iLowH, iLowS, iLowV), cv::Scalar(iHighH, iHighS, iHighV), tmp_B);
//cv::imshow("result",tmp_B);

cv::Mat tmp_1,tmp_2,tmp_3;
cv::inRange(imgHSV, cv::Scalar(155, 49, 180), cv::Scalar(179, 255, 255), tmp_1);
cv::inRange(imgHSV, cv::Scalar(100, 0, 92), cv::Scalar(179, 47, 142), tmp_2);
cv::inRange(imgHSV, cv::Scalar(168, 0, 0), cv::Scalar(179, 43, 202), tmp_3);

cv::dilate(tmp_1,tmp_1,cv::Mat::ones(15,15,CV_8UC1));
cv::erode(tmp_1,tmp_1,cv::Mat::ones(15,15,CV_8UC1));

cv::dilate(tmp_2,tmp_2,cv::Mat::ones(15,15,CV_8UC1));
cv::erode(tmp_2,tmp_2,cv::Mat::ones(15,15,CV_8UC1));

cv::dilate(tmp_3,tmp_3,cv::Mat::ones(1,31,CV_8UC1));
cv::erode(tmp_3,tmp_3,cv::Mat::ones(1,31,CV_8UC1));
cv::dilate(tmp_3,tmp_3,cv::Mat::ones(3,3,CV_8UC1));
cv::erode(tmp_3,tmp_3,cv::Mat::ones(3,3,CV_8UC1));
cv::erode(tmp_3,tmp_3,cv::Mat::ones(5,5,CV_8UC1));
cv::dilate(tmp_3,tmp_3,cv::Mat::ones(5,5,CV_8UC1));

std::vector<cv::Mat> ch(3);

ch[0]=tmp_1;
ch[1]=tmp_2;
ch[2]=tmp_3;


cv::Mat tmp;
cv::merge(ch,tmp);
cv::imshow("result",tmp);

k=cv::waitKey(5);
}

return 0;
}
[/code]

  • Like 1

Share this post


Link to post
Share on other sites


 if (openFileDialog1.ShowDialog() == DialogResult.OK)

            {

                using (var image = new IplImage(openFileDialog1.FileName))

                using (var hsv = new IplImage(image.Size, image.Depth, image.NChannels))

                {

                    Cv.CvtColor(image,hsv, ColorConversion.BgrToHsv);

                    var splits = hsv.Split();

                    Cv.Threshold(splits[0], splits[0], 160, 255, ThresholdType.BinaryInv);

                   using( var bin = new IplImage(image.Size, image.Depth, 1))

                    {

                        Cv.Threshold(splits[2], bin, 150,255, ThresholdType.BinaryInv);

                        Cv.And(bin, splits[0], bin);

                        Cv.Smooth(bin, bin, SmoothType.Median, 3, 3 );

                        Cv.ShowImage("2", bin);

                    }

                    foreach (var s in splits)

                        s.Dispose();

                }


            }

http://www.compvision.ru/forum/uploads/monthly_08_2014/post-5717-0-20011600-1408638089_thumb.jpg

post-5717-0-20011600-1408638089_thumb.jp

  • Like 1

Share this post


Link to post
Share on other sites

Ну, различать их просто, в интернете полно примеров, а также, как я уже писал, есть пример в стандартной поставке OpenCV - contours.c

На шарпе всё должноо быть очень похоже, но со своими особенностями.

Повторюсь ещё раз: замена CV_RETR_TREE на CV_RETR_EXTERNAL дала какие-нибудь результаты? В твоём коде же есть ContourRetrieval.Tree - замени же!

Перепробовал все варианты: ContourRetrieval.List, ContourRetrieval.CComp, ContourRetrieval.External, ContourRetrieval.FloodFill

Итого, поставил External и он вывел только один самый большой контур, остальные вывели все контуры, в чем их отличие я так и не понял, вроде как ContourRetrieval.CComp должен разделять, но тоже все выводит, хотя в описании написано "Retrieve all the contours and organizes them into two-level hierarchy: top level are external boundaries of the components, second level are boundaries of the holes [CV_RETR_CCOMP]"

Share this post


Link to post
Share on other sites

Поучаствую )

post-1-0-71943100-1408627906_thumb.png

Очень интересный вариант! Как раз на выходных опробую) самая большая для меня проблема этот код перевести в C#))

Share this post


Link to post
Share on other sites

Спасибо за вариант! примерно тоже самое у меня получалось, но тут буквы сильно видоизменяются, их потом tesseract не хочет нормально распозновать и CuneiFrom OCR, тоже не может)

Share this post


Link to post
Share on other sites

О, в ход пошла тяжёлая артиллерия форума. Но, господа, ваши варианты содержат слишком много магических констант и для изображений другого размера или снятые другой камерой могут не сработать.

Как ещё один универсальный вариант можно ещё применить k-means, на вход которому подать HSV изображение. Он достаточно точно отделит все элементы друг от друга. Но он будет сложнее, чем то, что сейчас делает автор.

Кстати, VironZizu: можно перед поиском контуров применить на изображение медианный фильтр размером 3х3.

  • Like 1

Share this post


Link to post
Share on other sites

Сам не люблю магию :), я за интеллект.

K-means хороший вариант.

Вот еще самообучающийся алгоритм (главный параметр, это количество цветов int NrGMMComponents = 8 ):


#include <opencv2/opencv.hpp>
#include "opencv2/ml/ml.hpp"
#include <vector>
#include <list>
#include <iostream>

using namespace cv;
using namespace std;

void main(void)
{
// Количество кластеров (сколько разных цветов будет на конечном изображении)
int NrGMMComponents = 8;
// Имя исходного файла
string fname="D:\\ImagesForTest\\passport.jpg";

cv::Mat SampleImg = imread(fname,1);

cv::GaussianBlur(SampleImg,SampleImg,Size(3,3),1);

int SampleImgHeight = SampleImg.rows;
int SampleImgWidth = SampleImg.cols;

// Набираем точки данных
vector<Vec3d> ListSamplePoints;

for (int y=0; y<SampleImgHeight; y++)
{
for (int x=0; x<SampleImgWidth; x++)
{
// Собираем точки с изображения
Vec3b bgrPixel = SampleImg.at<Vec3b>(y, x);

uchar b = bgrPixel.val[0];
uchar g = bgrPixel.val[1];
uchar r = bgrPixel.val[2];
if(rand()%25==0) // Берем не все точки подряд, а по равномерной выборке (примерно каждую 25-ую)
{
ListSamplePoints.push_back(Vec3d(b,g,r));
}
} // for (x)
} // for (y)


// Формируем матрицу обучающих данных
int NrSamples = ListSamplePoints.size();
Mat samples( NrSamples, 3, CV_64FC1 );

for (int s=0; s<NrSamples; s++)
{
Vec3d v = ListSamplePoints.at(s);
samples.at<double>(s,0) = (float) v[0];
samples.at<double>(s,1) = (float) v[1];
samples.at<double>(s,2) = (float) v[2];
}
// Напишем что нибудь по-английски.
cout << "Learning to represent the sample distributions with " << NrGMMComponents << " gaussians." << endl;
cout << "Started GMM training" << endl;

cv::EM em_model;

// Параметры алгоритма
em_model.setInt("covMatType",cv::EM::COV_MAT_GENERIC);
em_model.setInt("nclusters",NrGMMComponents);
em_model.setInt("maxIters",1500);
em_model.setDouble("epsilon",0.001);

Mat labels(NrSamples,1,CV_32SC1);
Mat logLikelihoods( NrSamples, 1, CV_64FC1 );

// Выполнение алгоритма обучения
em_model.train( samples,logLikelihoods,labels);

cout << "Finished GMM training" << endl;

// Изображение, на котором будет отображаться результат
Mat img = Mat::zeros( Size( SampleImgWidth, SampleImgHeight ), CV_8UC3 );

// Опрос классификатора для каждого пикселя
Mat sample( 1, 3, CV_64FC1 );

Mat means;
means=em_model.getMat("means");
for(int i = 0; i < img.rows; i++ )
{
for(int j = 0; j < img.cols; j++ )
{
Vec3b v=SampleImg.at<Vec3b>(i,j);
sample.at<double>(0,0) = (float) v[0];
sample.at<double>(0,1) = (float) v[1];
sample.at<double>(0,2) = (float) v[2];

int response = cvRound(em_model.predict( sample )[1]);

img.at<Vec3b>(i,j)[0]=means.at<double>(response,0);
img.at<Vec3b>(i,j)[1]=means.at<double>(response,1);
img.at<Vec3b>(i,j)[2]=means.at<double>(response,2);

}
}

img.convertTo(img,CV_8UC3);
imshow("result",img);
waitKey();
// Сохраним в файл результат
cv::imwrite("result.png", img);

}
[/code] Результат для 8 цветов: post-1-0-24232900-1408703583_thumb.png и для двух цветов: post-1-0-60787500-1408704014_thumb.png Дальше можно морфологию сделать (dilate, erode, см. выше) чтобы строчки слить в прямоугольные области. Затем найти контуры, габаритные прямоугольники и вынуть строки. Или сильно размываем (
[code]cv::GaussianBlur(SampleImg,SampleImg,Size(3,3),1);
заменяем на
cv::GaussianBlur(SampleImg,SampleImg,Size(15,15),5);

) затем кластеризуем (в примере 2 кластера), получим нечто в духе такого:

post-1-0-75490500-1408704786_thumb.png

И никакой магии :)

  • Like 2

Share this post


Link to post
Share on other sites

Ребят, хотел попробовать код на С++ с помощью VS12, но не могу либу OpenCV подрубить! Целая туча заморочек с ней. Может кто-нибудь залить проект с уже настроенными связями с OpenCV!? Я качал нагетом, в проекте либа с хедерами появляется, но сам проект эти хедеры не видит...

На C# как то все было проще))

Share this post


Link to post
Share on other sites

Блин, у меня винда 32))))

А можно ещё сами файлы проекта вложить, чтобы я смог с компилировать?) чтобы можно было с параметрами по играть ещё и другие примеры С++ кода опробовать! Был бы премного благодарен!

Share this post


Link to post
Share on other sites

я в полной растеренности, пробую распознать текст с помощью tesseract но распознавание просто ужастно, даже если я предварительно в ФШ удаляю все лишнее, перевожу в ч.б и тд! Может кто работал с этой библиотекой и может поделиться опытом распознавания русского языка?

Share this post


Link to post
Share on other sites

Я работал. Всё печально.

Но можно немного подтюнить алгоритмы. С какиими параметрами ты запускаешь tesseract?

  • Like 1

Share this post


Link to post
Share on other sites

Блин, у меня винда 32))))

А можно ещё сами файлы проекта вложить, чтобы я смог с компилировать?) чтобы можно было с параметрами по играть ещё и другие примеры С++ кода опробовать! Был бы премного благодарен!

Я CMAKE-ом заготовки для проектов делаю, ибо ленив :).

Вот файл:

CMakeLists.txt

вот видео как создать проект:

CreatingOpenCV_Project_CMAKE.rar

  • Like 1

Share this post


Link to post
Share on other sites

Я работал. Всё печально.

Но можно немного подтюнить алгоритмы. С какиими параметрами ты запускаешь tesseract?

Nuzhny

Я тоже убедился что все печально))

Запускаю пока так


Bitmap pictureInfoArea = src.ToBitmap();

TesseractEngine engine = new TesseractEngine("tessdata/", "rus", EngineMode.Default);                            

var page = engine.Process(pictureInfoArea, PageSegMode.Auto);

string s = page.GetText();

Собственно никаких наворотов не делал, задаем путь к словарю (3.02), EngineMode по дефолту, ну собственно практически ничего не делал с настройками, просто из настроек ещё есть разделение по блокам, по считать буквы\слова\предложения, а само распознавание при это остается в печале)

Smorodov

Спасибо!) сейчас опробую) не знал про такую штуку интересную)

Share this post


Link to post
Share on other sites

Для Engine надо подобрать аналог tesseract::OEM_TESSERACT_CUBE_COMBINED, оно распознаёт лучше всех.

Далее, если ты подаёшь на распознавание только по одной строке, а не изображение целиком (а так лучше), то указывай опцию SetPageSegMode(tesseract::PSM_SINGLE_LINE) - я не знаю, как это звучит на Шарпе, но должно быть похоже.

  • Like 1

Share this post


Link to post
Share on other sites

Для Engine надо подобрать аналог tesseract::OEM_TESSERACT_CUBE_COMBINED, оно распознаёт лучше всех.

Далее, если ты подаёшь на распознавание только по одной строке, а не изображение целиком (а так лучше), то указывай опцию SetPageSegMode(tesseract::PSM_SINGLE_LINE) - я не знаю, как это звучит на Шарпе, но должно быть похоже.

Cube есть такое! попробую его или имеете ввиду cube&tesseract? эта опция с русскими словарем вроде как не пашет...

Single line тоже есть! Не знал что по одной строчке он распознает удачней чем весь абзац!

p/s/оказалось опция OEM_TESSERACT_CUBE_COMBINED не работает с русским словарем, только инглиш...

  • Like 1

Share this post


Link to post
Share on other sites

Нашел интересный проект по нахождению текста на картинке, ребята писали под телефон Н900, но потом переписали и под PC

У меня скомпилировать не получилось, проект снова на плюсах :\

Может у кого получится с компилировать и попробовать результат с моей картинкой?

ссылка на github

Share this post


Link to post
Share on other sites

О, как интересно!

Я как раз этим занимался, прочитай самый первый мой ответ на твоё сообщение, там есть ссылка и на код, и на страничку с кодом для телефона.

А несколькими постами далее есть и результат с твоей картинкой.

  • Like 1

Share this post


Link to post
Share on other sites

оу, сорри за невнимательность!

Просто решил немного систематизировать подход, нашел сайт , где ребята уже реализовывали подобное, они немного расписывают процесс создания, думаю нужно идти по их пути, рас у них уже получился готовый продукт по этим технологиям. OpenCV+tesseract

Весь секрет успешного результата в подавании на распознание в tesseract одной буквы, т.е. нахождение строк, разбивка строк на слова, затем на буквы - это задача реализуемая OpenCV как я понял

Что думаете по этому поводу?

Share this post


Link to post
Share on other sites

Скорее всего так и надо делать, но я всё равно не уверен на счёт качества tesseract.

Если бы ты дружил со связкой (Linux + C++), то можно было бы несколькими консольными командами собрать приложение по поиску и распознаванию текста на картинке от создателей OpenCV.

На всякий случай:

1. не так давно вышел OpenCV 3.0 alpha;

2. надо сделать git clone основного репозитория OpenCV;

3. сделать git clone для репозитория opencv_contrib (есть в ссылке пункта 1);

4. запустить cmake & make, но перед этим не забыть установить tesseract, например sudo apt-get install tesseract-ocr;

5. запустить сначала ./example_text_textdetection passport.jpg, убедиться, что твой текст находится (а он находится);

6. запустить ./example_text_end_to_end_recognition passport.jpg

P.S. Ну или как вариант просто посмотреть в исходники. Вообще, выбор C# в качестве языка для разработки алгоритмов компьютерного зрения кажется странным. На него можно переписывать уже готовый алгоритм, разработанный на С/С++ или даже на Питоне (он во много раз превосходит по удобству C#, а также по доступности математических и других библиотек).

  • Like 1

Share this post


Link to post
Share on other sites

Nuzhny

Спасибо за инструкцию, ноутбук с линуксом должен на днях подвернуться, на нем и опробую!

Я так понимаю нахождение текста появилось только в 3.0 версии OpenCV? Тот пример, что на первой странице выложен, там как раз и есть этот поиск или вы какой то свой метод реализовали с помощью OpenCV? У вас случайно нету примера реализации стандартного метода OpenCV3.0 поиска текста? просто интересно глянуть как он отрабатывает!

з.ы. Если честно, в голове уже всё перемешалось, tesseract, open cv и тд) Уже не знаешь за какой конкретно метод хвататься первым ))

Share this post


Link to post
Share on other sites

Я так понимаю нахождение текста появилось только в 3.0 версии OpenCV? Тот пример, что на первой странице выложен, там как раз и есть этот поиск или вы какой то свой метод реализовали с помощью OpenCV? У вас случайно нету примера реализации стандартного метода OpenCV3.0 поиска текста? просто интересно глянуть как он отрабатывает!

Случайно есть, иначе как бы я инструкцию написал. См. аттач, это результирующая картинка по поиску текста. Распознавалка, кстати, там есть и своя (на основе HMM), и дёргается API tesseract'a (для этого не забыть его поставить и прописать параметры в CMake).

з.ы. Если честно, в голове уже всё перемешалось, tesseract, open cv и тд) Уже не знаешь за какой конкретно метод хвататься первым ))

Тут надо действовать примерно так:

1. позапускать каждый метод на своих данных, причём данных должно быть достаточно много;

2. выбрать метод, кажущийся наиболее подходящим, основательно изучить его математику и принципы работы в тонкости, посмотреть как и почему он не срабатывает (тако бывается практически наверняка) на некоторых примерах;

3. подкрутить параметры метода, добавить некоторые свои улучшалки, фильтры, предобработку, опять посмотреть на всех примерах;

4. если метод подогнался точно, то оставлять его, а иначе смотреть: возможно ли вообще его применять ко всему спектру входных данных;

5. если метод подошёл - отлично или... опять несколько вариантов:

5.1. надо брать другой метод и повторять для него шаги 2-4;

5.2. если на каждом примере распознавание требует выставления индивидуальных параметров, то попрробовать их автоматически подогнать;

5.3. можно попробовать автоматически отделить примеры, на которых работает первый алгоритм, а другой уже подгонять и тестировать только на тех данных, на которых первый принципиально не работает.

post-391-0-64224900-1409469898_thumb.png

  • Like 1

Share this post


Link to post
Share on other sites

Вроде как дело продвигается, слова нахожу с помощью tesseract, пробую делить буквы с помощью tesseract, для раздельных вариантов все нормально, но для слипшихся печально, вот думаю как можно преобразовать? или уже писать свой алгоритм разделения слова на буквы, у OpenCV нет такой возможности?

p/s блин не могу полый прямоугольни нарисовать!))) т.е. чтобы у него белый фон был, а то он дает только кромку окрасить!

Share this post


Link to post
Share on other sites

Толщину линии надо установить в -1, тогда будет заливать цветом внутренности прямоугольника.

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×