Nuzhny 243 Report post Posted September 30, 2014 В твоём случае - да. Каскады есть смысл применять, когда, например, ты подносишь паспорт к веб-камере, он каскадами обнаруживается и только потом в области обнаружения ищутся стороны и распознаётся текст. Share this post Link to post Share on other sites
VironZizu 2 Report post Posted September 30, 2014 Ребят, а есть еще идеи по удалению мусора с картинки, кроме как по цвету и по размеру отсортировывать? А то этот алгоритм срабатывает только конкретно с моим паспортом, стоит взять что-нибудь другое и все!) начинаются косяки! Как то все таки нужно мух от котлет отделять, а именно буквы... Пока у меня плохо сортируются контуры которые по размеру совпадают с контурами букв и я вот не знаю как к ним еще подлезть!?)) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted September 30, 2014 Ты не пробовал перед началом поиска контуров делать медианную фильтрацию? Вообще, тяжело что-то конкретное посоветовать, когда не видно проблемы. Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 1, 2014 Да, наверное я не так спрашиваю, медианную фильтрация делаю и так, в частности размытие Гаусса. Получается я нахожу позиции паспорта, и потом нарезаю примерно ту область где находится нужный мне текст, естественно для разных паспортов эта область не получается пиксель в пиксель, и получается что в кадр попадают не нужные предметы, а тессеракт при распозновании очень болезненно на них реагирует. Лучше для примера я выложу сами картинки, допустим с полями Фамилия, Имя, Отчество: Так вот, в область попала верхняя кромка, она на паспорте идет чуть ниже сердцевины, по свойствам она похожа на буквы, как удалять её, вообще не понятно мне) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted October 1, 2014 А, вот оно как. Обычно такие штуки убирают с помощью мат. морфологии: пару раз делают эрозию, смотрят, что осталось и распознают на исходном изображении (до эрозии!) только эти области. Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 1, 2014 Взял для тестов несколько паспортов, результат жутко расстроил, положил паспорт с обложкой, мой алгоритм с ним не отработал, кароче из 5 штук, 2 нормально отработали... В связи с этим вопрос обнаружения границ паспорта снова актуален) ибо я уже без сил, как его границы еще находить вообще не понимаю, там столько ньюансов получается, что очуметь Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted October 1, 2014 [off] Ну, я точно уверен, что Smorodov сможет сделать это с помощью ASM, например. [/off] А я бы нашёл отрезки (например с помощью алгоритма LSD), а по ним с помощью RANSAC построил уравнения прямых - сторон паспорта. Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 1, 2014 По поводу ASM, думаю должен хорошо работать, но это крайний случай Еще можно попробовать идеологию фильтра частиц, где частица это прямоугольник и координаты частицы (X,Y,W,H,поворот), а в качестве функции правдоподобия взять сумму градиентов вдоль границ этого прямоугольника. Для пущей крутости можно еще учитывать направление градиента, и считать сумму проекций на перпендикуляр к стороне. Но это тоже "из пушки по воробьям". Может будет чуток времени, попробую что-нибудь набросать, есть одна мысль, хочу проверить. Мысль: метод на основе максимизации отношения количества "правильных" пикселей к площади повернутого прямоугольника. Если прямоугольник "правильно" закрывает область, то это отношение максимально. Как то пытался объяснить иностранцам, не получилось ), наверное мой английский хромает ). Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 2, 2014 Nuzhny пробовал загуглить lsd) как и ожидалось вылезла целая туча статей про наркоту))) можно по подробней по нему? тяжело реализовывается? средставами OpenCV? Smorodov Я прочитал и общей картины не получил)) Видимо это действительно пушка, которую я с трудом осилю)) Сейчас попробую контуры по моментам по сравнивать, хотя затея глупая конечно, потому что для каждого паспорта он всегда рандомно эту прямоугольную область находит(с половинкой паспорта), то верхнюю половинку, то нижнюю. Думал искать область, потом переворачивать изображение на 180 и заново пробовать искать, но логику пока додумать не могу, что с этими двумя областями делать... Опять же, при тестах он мог так одну и ту же половинку паспорта находить при переворотах, а мог разные... Оказалось я немного подтупил, мой метод находит все таки нужную мне страничку, оказалось я неправильно отсортировываю! Но остается маленький ньюанс, как отличить верхнуюю страничку от нижней?)) размеры и площади то у них одинаковые!))) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted October 2, 2014 Nuzhny пробовал загуглить lsd) как и ожидалось вылезла целая туча статей про наркоту))) можно по подробней по нему? тяжело реализовывается? средставами OpenCV? LSD же! Там есть статья, исходники и demo, куда ты можешь загрузить свою картинку и посмотреть на результат работы онлайн. Реализация там без OpenCV. Но такой хороший алгоритм реализован и с OpenCV. Во-первых, легко гуглится проект, созданный независимым разработчиком. А во-вторых LSD есть уже в OpenCV 3.0, можно его взять и оттуда (просто скопировать исходники). Там же есть ссылки на примеры работы алгоритма. Вот кто-то ищет границы купюры: исходник и результат. Вполне себе ничего. [off] Кстати! Можно сделать приложение для смартфона для туристов: поднести к камере смартфона любую купюру или монету, распознать и выдать курс к любой валюте, к евро, например. Поднести несколько купюр - посчитать их сумму в любой валюте. Эдакий продвинутый визуальный валютный калькулятор. Думаю, что для специалиста по компьютерному зрению проект был бы довольно интересным, но много возни с набором базы, получением курса валют, дизайном и т.п. Нужна команда, конечно. [/off] Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 2, 2014 Приправа к LSD Grouping Line-segments using Eigenclustering.pdf Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 3, 2014 Nuzhny, по тестил LCD метод интересный, пример с купюрой нашел целый скоп прямых, как только их потом объединить в квадраты и выбрать еще нужный?) Мне кажется сложноватый способ для моей задачи) Пробую дальше через квадраты, выяснил почему не может найти полный контур паспорта, когда он лежит рядом с кромкой, получается при Tresholding граница сканируемого изображения немного засвечивается и поэтому алгоритм уже не может нужный внешний контур найти, сейчас покажу пример, может по советуете чего: Как я ищу: 1) делаю небольшое размытие 2)затем Threshold 3)затем FindContours ищу конутры 4)далее Cv.ApproxPoly и у меня повялется куча наборов точек(контуры) 5)Далее сортируем нужные мне с нужными углами и размерами. 6) Повторяем процесс с другими параметрами в Threshold И та кручу этот цикл и области отлично находятся, вот единственная проблема с краями и засветами, пробовал Канни, а он долго отрабатывает, циклов 10 если поставить так вообще жуть) Share this post Link to post Share on other sites
Nuzhny 243 Report post Posted October 3, 2014 Чтобы писать минимум кода, ты можешь попробовать на чёрном изображении нарисовать, найденные с помощью LSD отрезки, белым цветом и применить преобразование Хафа (Hough transform, есть в OpenCV). Или скинь цветное изображение паспорта (с затёртыми данными), я покажу результат. Share this post Link to post Share on other sites
mrgloom 242 Report post Posted October 3, 2014 Сдается мне что опять бинанизация там не та применяется. Еще раз http://fiji.sc/Auto_Local_Threshold image->type->8 bit color->8bit image->adjust Auto threshold\Auto local threshold. Тут стоит учитывать, что я применял алгоритмы на дефолтных настройках, хотя и так получилось ничего. Кстати я так думаю, что вместо фильтрации(сглаживание и медианная) изображение можно уменьшить в несколько раз и обрабатываться будет быстрее(но это все на уровне покрутить параметры). И еще что интересно орлы выводятся очень хорошо. п.с. не знаю как тут вставлять изображения так чтобы они были ужаты, а при открытии полностью. поэтому просто ссылками. https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/init.jpg https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/scan.png https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/global.png https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/local.png https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/Phansalkar.PNG https://dl.dropboxusercontent.com/u/8841028/passport%20threshold/sauvola.PNG 1 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 6, 2014 mrgloom Идея про уменьшение кстати очень даже хороша, взял на вооружение, заметно шустрей отрабатывает! Я понимаю, что у меня бинаризация в печали, немного не понял что за пример вы скинули, я так понимаю это не OpenCV? Смотрю ваши примеры, очень хороши бинаризация получилась! такие контуры я думаю бы в легкую нашлись, жалко я пока повторить не могу)) image->type->8 bit color->8bit image->adjust Auto threshold\Auto local threshold. Вот это, что имеется ввиду? не совсем уловил) Есть ещё такой ньюанс, если положить паспорт прямо у кромки, то получается, что кромка как бы обрезается, и этот метод совсем уже не срабатывает, пробовал как вариант у скана дорисовывать рамку в 2 пикселя, но это тоже не помогло,у него тогда не получается все нужные прямоугольники найти! Share this post Link to post Share on other sites
mrgloom 242 Report post Posted October 6, 2014 да это не opencv но там формулы рассчёта приведены можно самому написать. image->type->8 bit color->8bit image->adjust Auto threshold\Auto local threshold. это то что надо в fiji нажать для получения результата. Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 9, 2014 Наконец-то дошли руки Оптимизации не делал, просто проверил идею. Пример кода максимизирует расстояние между средним цветом внутри и снаружи прямоугольной области. Максимизирует он это расстояние при помощи подбора параметров этого прямоугольника (методом градиентного спуска). Вот что я имел ввиду, когда говорил непонятные вещи Результат работы программы (изображение может быть и цветным): #include "opencv2/opencv.hpp" #include <vector> using namespace std; using namespace cv; //---------------------------------------------------------- // Это и есть вычисление расстояния между средними цветами //---------------------------------------------------------- double getLikelihood(Mat& img,cv::RotatedRect& rr) { double likelihood=0; Mat mask=Mat::zeros(img.size(),CV_8UC1); // rotated rectangle Point2f rect_points[4]; rr.points( rect_points ); vector<cv::Point> pts(4); for(int i=0;i<4;++i) { pts[i]=rect_points[i]; } cv::fillConvexPoly(mask,pts,Scalar::all(255)); imshow("mask",255-mask); Scalar cc1,cc2; cc1=cv::mean(img,mask); cc2=cv::mean(img,255-mask); likelihood=norm(cc1,cc2,cv::NORM_L2); return likelihood; } //---------------------------------------------------------- // Градиент, чтобы знать куда менять параметры //---------------------------------------------------------- void getLikelihoodGradient(Mat& img,cv::RotatedRect& rr,cv::RotatedRect& drr) { cv::RotatedRect rrdx=rr; rrdx.center.x+=1; cv::RotatedRect rrdy=rr; rrdy.center.y+=1; cv::RotatedRect rrdw=rr; rrdw.size.width+=1; cv::RotatedRect rrdh=rr; rrdh.size.height+=1; cv::RotatedRect rrdang=rr; rrdang.angle+=1; cv::RotatedRect rrdxn=rr; rrdxn.center.x-=1; cv::RotatedRect rrdyn=rr; rrdyn.center.y-=1; cv::RotatedRect rrdwn=rr; rrdwn.size.width-=1; cv::RotatedRect rrdhn=rr; rrdhn.size.height-=1; cv::RotatedRect rrdangn=rr; rrdangn.angle-=1; float l0=getLikelihood(img,rr); cout << l0 << endl; float dlx=getLikelihood(img,rrdx)-getLikelihood(img,rrdxn); float dly=getLikelihood(img,rrdy)-getLikelihood(img,rrdyn); float dlw=getLikelihood(img,rrdw)-getLikelihood(img,rrdwn); float dlh=getLikelihood(img,rrdh)-getLikelihood(img,rrdhn); float dlang=getLikelihood(img,rrdang)-getLikelihood(img,rrdangn); float scale=sqrt(dlx*dlx+dly*dly+dlw*dlw+dlh*dlh+dlang*dlang); dlx/=scale; dly/=scale; dlw/=scale; dlh/=scale; dlang/=scale; drr.center.x=dlx; drr.center.y=dly; drr.size.width=dlw; drr.size.height=dlh; drr.angle=dlang; } //---------------------------------------------------------- // Генерируем тестовое зашумленное изображение //---------------------------------------------------------- void generateTestImage(Mat& img) { img=Mat(512,512,CV_8UC3); cv::RotatedRect rr(cv::Point2f(200,300),Size(140,180),67); img=Scalar::all(0); // rotated rectangle Point2f rect_points[4]; rr.points( rect_points ); vector<cv::Point> pts(4); for(int i=0;i<4;++i) { pts[i]=rect_points[i]; } cv::fillConvexPoly(img,pts,Scalar(255,255,255)); for(int i=0;i<100000;++i) { int x=rand()%512; int y=rand()%512; img.at<Vec3b>(y,x)=Vec3b(255,255,255); } for(int i=0;i<105000;++i) { int x=rand()%512; int y=rand()%512; img.at<Vec3b>(y,x)=Vec3b(0,0,0); } } //---------------------------------------------------------- // //---------------------------------------------------------- int main(int argc, char* argv[]) { Mat img,img_cpy; generateTestImage(img); imshow("testimg",img); cv::waitKey(0); cv::RotatedRect rr(cv::Point2f((float)img.cols/2.0,(float)img.rows/2.0),Size(img.cols-100,img.rows-100),0); cv::RotatedRect drr; while(1) { img_cpy=img.clone(); getLikelihoodGradient(img,rr,drr); // Меняем параметры в сторону увеличения расстояния между средними цветами rr.center+=drr.center; rr.size+=drr.size; rr.angle+=drr.angle; // rotated rectangle Point2f rect_points[4]; rr.points( rect_points ); for( int j = 0; j < 4; j++ ) { line( img_cpy, rect_points[j], rect_points[(j+1)%4], Scalar(0,255,0), 2, CV_AA ); } imshow("img_cpy",img_cpy); waitKey(10); } cv::destroyAllWindows(); return 0; } 3 Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 9, 2014 Smorodov, Обалденно!!! На выходных засяду этот код под мой C# врапер подгонять!) Просто огонь!) Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 9, 2014 Еще небольшой вопрос, вот у меня есть бинаризация Отсу grayClone.Threshold(grayClone, 0, 255, ThresholdType.Otsu); Я так понимаю этот метод заключается в том, что высчитывается средний порог и применяется. А если мне нужно высчитать средний порог и потом его применить к обычной бинаризации, как это можно сделать? Вот сюда: grayClone.Threshold(grayClone, 0, 255, ThresholdType.Binary); На сколько я понимаю этот порог задается в обычной Binary там где у меня 0!? З.ы. Для чего это мне нужно, чтобы можно было средний порог в небольших пределах по варировать! И сделать скоп разных бинаризаций отталкивающихся от среднего! Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 10, 2014 Я так понимаю этот метод заключается в том, что высчитывается средний порог и применяется. Бинаризация Отсу работает с бимодальными гистограммами. Т.е. гисторамма изображения выглядит как два горба порог, это значение яркости, находящееся между этими горбами. Если гистограмма имеет больше/меньше двух горбов, то метод не работает как должен. На сколько я понимаю этот порог задается в обычной Binary там где у меня 0!? Дык, да, вместо нуля ( threshold_value ). Доки здесь можно посмотреть: http://docs.opencv.org/doc/tutorials/imgproc/threshold/threshold.html Это, мне кажется, тоже может быть полезно: http://www.bogotobogo.com/python/OpenCV_Python/python_opencv3_Image_Global_Thresholding_Adaptive_Thresholding_Otsus_Binarization_Segmentations.php Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 12, 2014 По пробовал Adaptive Threshold результаты лучше! Но там я параметры задаю в ручную допустим srcGray.AdaptiveThreshold(dst, 255, AdaptiveThresholdType.MeanC, ThresholdType.Binary, 20); block size = 20. Для некоторых вариантов этот параметров хорошо отрабатывает, но для некоторых нужен немного другой, как можно для адаптивной бинаризации выщитывать этот блок сайз? к чему можно привязатся? Потому что я смотрю, он лучше справляется чем обычный Threshold. Некоторые еле видные грани не сжираются, а некоторые слишком жирные не становятся жирнее... з.ы. Работаю с областью "кем, где выдан" Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 12, 2014 Как вариант, можно попробовать использовать информацию о гистограммах для каждого из блоков изображения (способ маньячный конечно ). Можно собрать образцы таких гистограмм, для хорошо бинаризированного изображения (или средние для множества вариантов), и в дальнейшем подбирать параметры бинаризации ориентируясь на эти гистограммы. Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 13, 2014 Интересно) П о работал с гистограммами, ничего полезного из них вытащить не смог) всял значение константу, вроде для всех вариантов отрабатывает неплохо!) Есть ещё одна идея, но не знаю как реализовать в коде, у меня есть контуры, как закрасить всю область кроме внутринностей этих конутров?) инверсию контуров как то сделать или как?) Share this post Link to post Share on other sites
Smorodov 578 Report post Posted October 13, 2014 Нарисовать контуры черным цветом, предварительно залив изображение белым. Share this post Link to post Share on other sites
VironZizu 2 Report post Posted October 13, 2014 ну немного не то, если я контуры залью черным в них полезные грани замажутся. Мне именно нужно чтобы я замазал все изображение, но содержимое контуров осталось не тронутым! Share this post Link to post Share on other sites