Nuzhny 243 Report post Posted August 21, 2014 Ну, различать их просто, в интернете полно примеров, а также, как я уже писал, есть пример в стандартной поставке OpenCV - contours.c На шарпе всё должноо быть очень похоже, но со своими особенностями. Повторюсь ещё раз: замена CV_RETR_TREE на CV_RETR_EXTERNAL дала какие-нибудь результаты? В твоём коде же есть ContourRetrieval.Tree - замени же! 1 Share this post Link to post Share on other sites
Smorodov 578 Report post Posted August 21, 2014 Поучаствую ) #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_; //cv::imshow("result",tmp_; 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] 1 Share this post Link to post Share on other sites
iskees 32 Report post Posted August 21, 2014 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 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 21, 2014 Ну, различать их просто, в интернете полно примеров, а также, как я уже писал, есть пример в стандартной поставке 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
VironZizu 2 Report post Posted August 21, 2014 Поучаствую ) Очень интересный вариант! Как раз на выходных опробую) самая большая для меня проблема этот код перевести в C#)) Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 21, 2014 http://www.compvision.ru/forum/uploads/monthly_08_2014/post-5717-0-20011600-1408638089_thumb.jpg Спасибо за вариант! примерно тоже самое у меня получалось, но тут буквы сильно видоизменяются, их потом tesseract не хочет нормально распозновать и CuneiFrom OCR, тоже не может) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted August 22, 2014 О, в ход пошла тяжёлая артиллерия форума. Но, господа, ваши варианты содержат слишком много магических констант и для изображений другого размера или снятые другой камерой могут не сработать. Как ещё один универсальный вариант можно ещё применить k-means, на вход которому подать HSV изображение. Он достаточно точно отделит все элементы друг от друга. Но он будет сложнее, чем то, что сейчас делает автор. Кстати, VironZizu: можно перед поиском контуров применить на изображение медианный фильтр размером 3х3. 1 Share this post Link to post Share on other sites
Smorodov 578 Report post Posted August 22, 2014 Сам не люблю магию , я за интеллект. 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 цветов: и для двух цветов: Дальше можно морфологию сделать (dilate, erode, см. выше) чтобы строчки слить в прямоугольные области. Затем найти контуры, габаритные прямоугольники и вынуть строки. Или сильно размываем ([code]cv::GaussianBlur(SampleImg,SampleImg,Size(3,3),1); заменяем на cv::GaussianBlur(SampleImg,SampleImg,Size(15,15),5);) затем кластеризуем (в примере 2 кластера), получим нечто в духе такого: И никакой магии 2 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 25, 2014 Ребят, хотел попробовать код на С++ с помощью VS12, но не могу либу OpenCV подрубить! Целая туча заморочек с ней. Может кто-нибудь залить проект с уже настроенными связями с OpenCV!? Я качал нагетом, в проекте либа с хедерами появляется, но сам проект эти хедеры не видит... На C# как то все было проще)) Share this post Link to post Share on other sites
Smorodov 578 Report post Posted August 25, 2014 Exe-шник с DLL'ками. https://drive.google.com/file/d/0Bxk3hR536PxSWkVBdXQ3alB6dWc/edit?usp=sharing 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 25, 2014 Блин, у меня винда 32)))) А можно ещё сами файлы проекта вложить, чтобы я смог с компилировать?) чтобы можно было с параметрами по играть ещё и другие примеры С++ кода опробовать! Был бы премного благодарен! Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 26, 2014 я в полной растеренности, пробую распознать текст с помощью tesseract но распознавание просто ужастно, даже если я предварительно в ФШ удаляю все лишнее, перевожу в ч.б и тд! Может кто работал с этой библиотекой и может поделиться опытом распознавания русского языка? Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted August 26, 2014 Я работал. Всё печально. Но можно немного подтюнить алгоритмы. С какиими параметрами ты запускаешь tesseract? 1 Share this post Link to post Share on other sites
Smorodov 578 Report post Posted August 26, 2014 Блин, у меня винда 32)))) А можно ещё сами файлы проекта вложить, чтобы я смог с компилировать?) чтобы можно было с параметрами по играть ещё и другие примеры С++ кода опробовать! Был бы премного благодарен! Я CMAKE-ом заготовки для проектов делаю, ибо ленив . Вот файл: CMakeLists.txt вот видео как создать проект: CreatingOpenCV_Project_CMAKE.rar 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 27, 2014 Я работал. Всё печально. Но можно немного подтюнить алгоритмы. С какиими параметрами ты запускаешь 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
Nuzhny 243 Report post Posted August 27, 2014 Для Engine надо подобрать аналог tesseract::OEM_TESSERACT_CUBE_COMBINED, оно распознаёт лучше всех. Далее, если ты подаёшь на распознавание только по одной строке, а не изображение целиком (а так лучше), то указывай опцию SetPageSegMode(tesseract::PSM_SINGLE_LINE) - я не знаю, как это звучит на Шарпе, но должно быть похоже. 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 27, 2014 Для Engine надо подобрать аналог tesseract::OEM_TESSERACT_CUBE_COMBINED, оно распознаёт лучше всех. Далее, если ты подаёшь на распознавание только по одной строке, а не изображение целиком (а так лучше), то указывай опцию SetPageSegMode(tesseract::PSM_SINGLE_LINE) - я не знаю, как это звучит на Шарпе, но должно быть похоже. Cube есть такое! попробую его или имеете ввиду cube&tesseract? эта опция с русскими словарем вроде как не пашет... Single line тоже есть! Не знал что по одной строчке он распознает удачней чем весь абзац! p/s/оказалось опция OEM_TESSERACT_CUBE_COMBINED не работает с русским словарем, только инглиш... 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 28, 2014 Нашел интересный проект по нахождению текста на картинке, ребята писали под телефон Н900, но потом переписали и под PC У меня скомпилировать не получилось, проект снова на плюсах :\ Может у кого получится с компилировать и попробовать результат с моей картинкой? ссылка на github Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted August 28, 2014 О, как интересно! Я как раз этим занимался, прочитай самый первый мой ответ на твоё сообщение, там есть ссылка и на код, и на страничку с кодом для телефона. А несколькими постами далее есть и результат с твоей картинкой. 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 29, 2014 оу, сорри за невнимательность! Просто решил немного систематизировать подход, нашел сайт , где ребята уже реализовывали подобное, они немного расписывают процесс создания, думаю нужно идти по их пути, рас у них уже получился готовый продукт по этим технологиям. OpenCV+tesseract Весь секрет успешного результата в подавании на распознание в tesseract одной буквы, т.е. нахождение строк, разбивка строк на слова, затем на буквы - это задача реализуемая OpenCV как я понял Что думаете по этому поводу? Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted August 29, 2014 Скорее всего так и надо делать, но я всё равно не уверен на счёт качества 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#, а также по доступности математических и других библиотек). 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted August 31, 2014 Nuzhny Спасибо за инструкцию, ноутбук с линуксом должен на днях подвернуться, на нем и опробую! Я так понимаю нахождение текста появилось только в 3.0 версии OpenCV? Тот пример, что на первой странице выложен, там как раз и есть этот поиск или вы какой то свой метод реализовали с помощью OpenCV? У вас случайно нету примера реализации стандартного метода OpenCV3.0 поиска текста? просто интересно глянуть как он отрабатывает! з.ы. Если честно, в голове уже всё перемешалось, tesseract, open cv и тд) Уже не знаешь за какой конкретно метод хвататься первым )) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted August 31, 2014 Я так понимаю нахождение текста появилось только в 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. можно попробовать автоматически отделить примеры, на которых работает первый алгоритм, а другой уже подгонять и тестировать только на тех данных, на которых первый принципиально не работает. 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted September 2, 2014 Вроде как дело продвигается, слова нахожу с помощью tesseract, пробую делить буквы с помощью tesseract, для раздельных вариантов все нормально, но для слипшихся печально, вот думаю как можно преобразовать? или уже писать свой алгоритм разделения слова на буквы, у OpenCV нет такой возможности? p/s блин не могу полый прямоугольни нарисовать!))) т.е. чтобы у него белый фон был, а то он дает только кромку окрасить! Share this post Link to post Share on other sites
Smorodov 578 Report post Posted September 2, 2014 Толщину линии надо установить в -1, тогда будет заливать цветом внутренности прямоугольника. 1 Share this post Link to post Share on other sites