Перейти к содержимому
Compvision.ru
VironZizu

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

Recommended Posts

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

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поучаствую )

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах


 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну, различать их просто, в интернете полно примеров, а также, как я уже писал, есть пример в стандартной поставке 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]"

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поучаствую )

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Вот файл:

CMakeLists.txt

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

CreatingOpenCV_Project_CMAKE.rar

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Но можно немного подтюнить алгоритмы. С какиими параметрами ты запускаешь 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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

ссылка на github

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Скорее всего так и надо делать, но я всё равно не уверен на счёт качества 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Nuzhny

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я так понимаю нахождение текста появилось только в 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

  • Like 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×