mrgloom 242 Жалоба Опубликовано March 16, 2011 Пытаюсь выделить линии на изображении методом Хафа(cvHoughLines2) в примере почему то используется cvCanny, который дает двойные,не ровные,с разрывами линии и много мусора. есть идея проводить бинаризацию cvThreshold. так вот вопрос как после бинаризации убрать мусор (объекты слишком маленькие\большие элементы по кол-ву пикселей или слишком длинные\короткие по максимальной длине)? потом еще наверно необходимо линии которые останутся утоньшить(как это сделать? только эрозия или какая нить скелетонизация есть?), ибо cvHoughLines2 с толстыми линиями наверно будет плохо работать. у найденных линий необходимо найти лучший(по какому то признаку возможно определить лучшую линию) или средний угол наклона, рассматриваются линии которые не намного отклонены от горизонтали или вертикали и необходимо повернуть изображения на этот угол рис.1 , но тут вопрос не будет ли больше погрешность? и 2 вопрос рис.2 более сложный если мы знает что линия задана какой то кривой, то возможно подобрать преобразование для изображения чтобы преобразовать линию в прямую или преобразование будет не одно? 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано March 16, 2011 cvErode Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано March 16, 2011 cvErode не подходит,т.к. во первых не угадаешь число требуемых итераций ,а во вторых, т.к. он делает линии разрывными ,т.к. они имеют не одинаковую толщину по всей длине. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано March 16, 2011 А что за изображение? Если на нем контуры, то можно найти контуры, и проводить их анализ. Что касается второй части, то существует обобщенное преобразование Хафа (Generalised Hough transform), позволяющее найти любые кривые, только кривые эти надо предварительно параметризовать. И делать это надо руками, встроенной функции нет. Вот ссылка с теорией: http://homepages.inf.ed.ac.uk/rbf/HIPR2/hough.htm Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано March 16, 2011 изображение на котором много полосок(они практически белые, можно хорошо их выделить даже бинаризацией otsu, после бинаризации остается немного мусора в виде точек и сами полоски немного неровные), полоски под небольшим наклоном, надо определить этот наклон чтобы сделать поворот изображения. пример как на увеличении выглядит полоска, красным отмечены длины высота и ширина в середине(возможно надо брать максимальную ширину ограничивающего наклонного прямоугольника, но хз как его строить), более важна высота полоски, т.к. лучше всего выделить самую длинную полоску(для уменьшения погрешности определения угла), а ширина скорее для определения лишних объектов или горизонтальных полос. вообщем если возможно рассматривать такой объект как контур и получить такие характеристики то все норм, а так я уже смотрю в сторону блобов (а в opencv они сделаны отдельно? http://opencv.willowgarage.com/wiki/cvBlobsLib или http://code.google.com/p/cvblob/) т.е. если возможно у такого объекта определить высоту именно как на рисунке, а не как если бы мы его ограничили прямоугольником и посчитали высоту прямоугольника, то это наверно даже будет точнее чем преобразование хафа, но и медленней. вообщем все упирается в вопрос как сделать проще и быстрее либо Хафом, либо блобы, либо как то еще. Что касается второй части, то существует обобщенное преобразование Хафа (Generalised Hough transform), позволяющее найти любые кривые, только кривые эти надо предварительно параметризовать. И делать это надо руками, встроенной функции нет. ну заранее нет возможности узнать, что это за кривая, кривую ее еще надо сдетектировать на изображении, а это тоже непонятно как делать) вообщем в итоге думаю плохая это затея (или сложная). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано March 17, 2011 еще вопрос может есть какая то морфологическая операция чтобы убрать маленькие элементы на бинарном изображении? и при это не затронуть большие объекты? пример на увеличении(соответственно весь мусор надо убрать, полоски оставить) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
quosego 5 Жалоба Опубликовано March 17, 2011 еще вопрос может есть какая то морфологическая операция чтобы убрать маленькие элементы на бинарном изображении? и при это не затронуть большие объекты? Я думаю вашу задачу можно решить с помощью операции размыкания (англ OPEN). В общем случае она сглаживает контуры, обрывает узкие перешейки и ликвидирует выступы небольшой ширины. Фактически размыкание это дилатация эрозии. Но нужно грамотно подобрать ядро. В общем случае оно не должно быть больше объектов или их частей (выступов) которые вы удалять не собираетесь Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
quosego 5 Жалоба Опубликовано March 17, 2011 как-то так... int an=4; IplConvKernel* element = cvCreateStructuringElementEx(an*an+1, an*an+1, (an*an+1)/2, (an*an+1)/2, CV_SHAPE_ELLIPSE); cvMorphologyEx(image,image,NULL,element,CV_MOP_OPEN,1); Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано March 17, 2011 обрывает узкие перешейки хмм это может быть критично. а так результат довольно неплохой получился. нельзя ли сделать такую эрозию чтобы скажем есть объект и он по краям объедается по 1 пикселю и так чтобы по середине осталась толщина в 1 пиксель? (хотя я тут возможно не учел, что если так объедать скажем вертикальный или горизонтальный объект, то получим правильный его "скелет" просто линию, а если какой то наклонный скажем овал с бугристыми краями то мы не сможем получить "правильную" наклонную линию) а как подбирается ядро? если неизвестен изначально размер линий? возможно снять какую то статистику? и еще дополнительно как убрать маленькие элементы не затронув больших линий? (выделено на картинке) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
quosego 5 Жалоба Опубликовано March 17, 2011 нельзя ли сделать такую эрозию чтобы скажем есть объект и он по краям объедается по 1 пикселю и так чтобы по середине осталась толщина в 1 пиксель? можно, это называется скелетизация. Обсуждали здесь http://www.compvision.ru/forum/index.php?showtopic=30&st=0& а как подбирается ядро? если неизвестен изначально размер линий? возможно снять какую то статистику? Как я уже сказал, зависит от того, какой резултат вы хотите получить. Объекты размер которых больше ядра удалены не будут. С формой ядра сложнее, зависит от обработываемых блобов, думаю нужно поэксперементировать. и еще дополнительно как убрать маленькие элементы не затронув больших линий? Морфологически никак. Придется выделять блобы и считать площадь каждого 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 27, 2011 опять вернулся к этой задаче пытаюсь получить результат как тут http://www.mathworks.com/help/toolbox/images/ref/bwareaopen.html использую // Function to remove small blobs from the binary image IplImage* remove_small_objects( IplImage* img_in, int size ) { IplImage* img_out = cvCloneImage( img_in ); // return image CvMemStorage* storage = cvCreateMemStorage( 0 ); // container of retrieved contours CvSeq* contours = NULL; CvScalar black = CV_RGB( 0, 0, 0 ); // black color CvScalar white = CV_RGB( 255, 255, 255 ); // white color double area=0; // find contours in binary image cvFindContours( img_in, storage, &contours, sizeof( CvContour ), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE ); while( contours ) // loop over all the contours { area = cvContourArea( contours, CV_WHOLE_SEQ ); if( fabs( area ) <= size ) // if the area of the contour is less than threshold remove it { // draws the contours into a new image cvDrawContours( img_out, contours, black, black, -1, CV_FILLED, 8 ); // removes white dots } //else // { // cvDrawContours( img_out, contours, white, white, -1, CV_FILLED, 8 ); // fills in holes // } contours = contours->h_next; // jump to the next contour } cvReleaseMemStorage( &storage ); return img_out; } IplImage* img = cvLoadImage("img.bmp", 1); IplImage* grey = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1); cvCvtColor(img, grey, CV_BGR2GRAY); cvThreshold(grey, grey, 100, 255, CV_THRESH_OTSU); IplImage* out= remove_small_objects(grey,20); cvSaveImage("img.png",img); cvSaveImage("grey.png",grey); cvSaveImage("out.png",out); получаю результат. исходное грей (но испорченное после процедуры) конечное во-первых непонятно можно ли выбирать связность компонентов используя cvFindContours (и какая там используется по умолчанию?) как данный алгоритм умудряется "выедать" дополнительно пиксели в буквах e,a? почему портится изображение которое подается в remove_small_objects? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 27, 2011 По поводу связности: связность определяется младшими битами слова флагов. Может быть 4 или 8. flags The operation flags. Lower bits contain connectivity value, 4 (by default) or 8, used within the function. А если здесь вместо black, black поставить что то другое (разные цвета заполнения и контура), то скорее всего прояснится проблема "выедания". cvDrawContours( img_out, contours, black, black, -1, CV_FILLED, 8 ); // removes white dots Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 27, 2011 кстати у меня теперь почему то IplImage* img_out= cvCreateImage(cvSize(img_in->width,img_in->height), IPL_DEPTH_8U, 3); выдает приходится делать cvZero(img_out); возможно это как то связано с тем что бьется изображение. ну да ситуация вроде прояснилась, находятся еще и внутренние контуры. нельзя определить какой внешний, а какой внутренний? (т.е. мне надо из площади внешнего получается вычесть площади всех внутренних) Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано July 27, 2011 Первая картинка вполне нормальная, система выделяет память, но никто не говорит что она заполнена нулями. Что касается второго, то можно попробовать использовать иерархию контуров, как в примере contours с рожицами. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 28, 2011 можно еще смотреть наверно boundingRect на пересечение\вхождение, хотя это наверно медленней чем иерархия контуров. но меня и так в целом устраивает(получается баг процедуры только в том, что у внутренних контуров которые меньше порога выедается область толщиной в 1 пиксель). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 28, 2011 еще вопрос про морфологию как сделать так чтобы удалялись только горизональные перешейки, а вертикальные не трогались? вертикальные перешейки горизонтальные перешейки Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано July 28, 2011 еще вопросы 1.есть ли какие то алгоритмы позволяющие производить бинаризацию с информацией о том, что на изображении присутствует много граней\линий и т.д. т.е. более интеллектуальная бинаризация. 2.по сути описанный прямоугольник уже есть, хотелось бы получить максимальный вписанный прямоугольник для объектов на картинке. пробовал находить моменты Ху и искать тела похожие на прямоугольники CvMoments moments; CvHuMoments huMoments; cvMoments( contours, &moments ); cvGetHuMoments( &moments, &huMoments ); //только прямоугольные области //порог int thresh= 100; int hu1= (int)(huMoments.hu1*thresh); int hu2= (int)(huMoments.hu2*thresh); int hu3= (int)(huMoments.hu3*thresh); int hu4= (int)(huMoments.hu4*thresh); int hu5= (int)(huMoments.hu5*thresh); int hu6= (int)(huMoments.hu6*thresh); int hu7= (int)(huMoments.hu7*thresh); if(hu1>0&& hu2>0&& hu3==0&& hu4==0&& hu5==0&& hu6==0&& hu7==0) {...} но то ли я не правильно делаю, то ли метод сам не точный, в зависимости от thresh выдает совсем уж различные результаты. хотя возможно я не правильно понял у прямоугольника Ху первые 2 момента должны быть положительны, а остальные по нулям? 3.хотелось бы уметь разрешать такие ситуации,т.е. видно что много маленьких разрывных участков составляют линию, как их соединить в одно? по какому критерию? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2011 матлабовский bwareaopen на opencv /** * OpenCV equivalent of Matlab's bwareaopen. * image must be 8 bits, 1 channel, black and white (objects) * with values 0 and 255 respectively */ void bwareaopen(IplImage* image, int size) { CvMemStorage *storage; CvSeq *contour; IplImage *input; double area; if (image == NULL || size == 0) return; input = cvCloneImage(image); storage = cvCreateMemStorage(0); cvFindContours(input, storage, &contour, sizeof (CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); while(contour) { area = cvContourArea(contour, CV_WHOLE_SEQ, 1); if (-size <= area && area <= 0) { // removes white dots cvDrawContours(image, contour, CV_RGB(0,0,0), CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0, 0)); } else if (0 < area && area <= size) { // fills in black holes cvDrawContours(image, contour, CV_RGB(0xff,0xff,0xff), CV_RGB(0xff,0xff,0xff), -1, CV_FILLED, 8, cvPoint(0,0)); } contour = contour->h_next; } cvReleaseMemStorage(&storage); cvReleaseImage(&input); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано November 29, 2011 матлабовский bwareaopen на opencv /** * OpenCV equivalent of Matlab's bwareaopen. * image must be 8 bits, 1 channel, black and white (objects) * with values 0 and 255 respectively */ void bwareaopen(IplImage* image, int size) { CvMemStorage *storage; CvSeq *contour; IplImage *input; double area; if (image == NULL || size == 0) return; input = cvCloneImage(image); storage = cvCreateMemStorage(0); cvFindContours(input, storage, &contour, sizeof (CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); while(contour) { area = cvContourArea(contour, CV_WHOLE_SEQ, 1); if (-size <= area && area <= 0) { // removes white dots cvDrawContours(image, contour, CV_RGB(0,0,0), CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0, 0)); } else if (0 < area && area <= size) { // fills in black holes cvDrawContours(image, contour, CV_RGB(0xff,0xff,0xff), CV_RGB(0xff,0xff,0xff), -1, CV_FILLED, 8, cvPoint(0,0)); } contour = contour->h_next; } cvReleaseMemStorage(&storage); cvReleaseImage(&input); } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах