Halloween
-
Количество публикаций
24 -
Зарегистрирован
-
Посещение
Сообщения, опубликованные пользователем Halloween
-
-
Доработал свою программу.Результатом удовлетворен на все 100!
Особая благодарность Nuzhny,направил на путь истины!Большущее спасибо
-
связность какая должна быть? 4-х или 8-ми?
если например устранять разрывы просто соединением конечных точек, то будет не точно наверно, но вполне рабоче, но может можно как то более сложно интерполировать, поэтому я предлагал почитать про сплайны.
наверно можно как то пройтись по точкам и смотреть их связность и помечать/удалять лишние, но например какие лучше удалять внутри контура или снаружи, или без разницы?
+ алгоритмы не учитывают маленькие циклы.(если они появятся)
Желательно 8-ми связные.
Насчет соединения конечных точек,то я сейчас работаю над этим,используя фильтр Калмана(фильтр прогнозирует след. положение точки по траектории).Это должно помочь сгладить места соединений.
Без разницы откуда удалять,лишь бы не получилось лишних разрывов и процесс был автоматизирован.Свою идею как это сделать я представил выше(методом дифференцирования).
-
Посмотри довольно тупую мою реализацию для твоего изображения:
#include <list> #include <limits> #include <highgui.h> #include <cv.h> //////////////////////////////////////////////////////////////////////////// int main() { IplImage* img = cvLoadImage("f:\\test.bmp", 0); IplImage* img2 = cvCloneImage(img); cvShowImage("original", img2); // Немного доработаем исходное изображение для удобного писка контуров cvSubRS(img, cvScalar(255), img); cvDilate(img, img, 0, 1); cvErode(img, img, 0, 1); cvShowImage("img", img); // Ищем контуры CvMemStorage *storage = cvCreateMemStorage(0); CvContourScanner traverse = cvStartFindContours(img, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE); // Контейнер для концевых точек std::list<CvPoint> points; size_t ccounter = 0; for (CvSeq* contour = cvFindNextContour(traverse); contour; contour = cvFindNextContour(traverse)) { // Совершено тупой и нерациональный поиск концевых точек size_t min1 = std::numeric_limits<size_t>::max(); size_t min2 = std::numeric_limits<size_t>::max(); CvPoint min_p1 = cvPoint(0, 0); CvPoint min_p2 = cvPoint(500, 500); for (int i = 0; i < contour->total; ++i) { CvPoint p1 = *(CvPoint*)cvGetSeqElem(contour, i); size_t near_count = 0; for (int j = 0; j < contour->total; ++j) { if (i != j) { CvPoint p2 = *(CvPoint*)cvGetSeqElem(contour, j); if (abs(p1.x - p2.x) < 5 && abs(p1.y - p2.y) < 5) ++near_count; } } if ((near_count < min1) && (abs(p1.x - min_p2.x) > 10 || abs(p1.y - min_p2.y) > 10)) { min1 = near_count; min_p1 = p1; } else if ((near_count < min2) && (abs(min_p1.x - p1.x) > 10 || abs(min_p1.y - p1.y) > 10)) { min2 = near_count; min_p2 = p1; } } points.push_back(min_p1); points.push_back(min_p2); printf("%u\n", ++ccounter); } cvEndFindContours(&traverse); cvReleaseMemStorage(&storage); // Соединяем ближайшие концевые точки прямыми for (std::list<CvPoint>::iterator it1 = points.begin(); it1 != points.end(); it1 = points.erase(it1)) { double min_dist = std::numeric_limits<double>::max(); std::list<CvPoint>::iterator it2 = it1; std::list<CvPoint>::iterator best_it = it1; ++best_it; for (++it2; it2 != points.end(); ++it2) { double dist = sqrt((double)((it1->x - it2->x) * (it1->x - it2->x) + (it1->y - it2->y) * (it1->y - it2->y))); if (dist < min_dist) { min_dist = dist; best_it = it2; } } cvLine(img2, *it1, *best_it, cvScalar(0)); points.erase(best_it); } cvShowImage("result", img2); cvWaitKey(); cvReleaseImage(&img2); cvReleaseImage(&img); cvDestroyAllWindows(); return 0; } ////////////////////////////////////////////////////////////////////////////
Сравни картинки original и result. Это то, что тебе надо?
Практически то,но маленькие разрывы всё-равно остались.Посмотрите как я реализовал свою задачу,воспользовавшись тем,что вы предложили ранее:
Решение действенно,но для него нужно давать четкое изображение без шумов и утолщений,иначе будут баги.
Есть идея почистить изображение с помощью дифференцирования.Поясню алгоритм:
1.Двигаться по горизонтали,пока не найдется точка.
2.Если точка нашлась-двигаться при координате Х этой точки только уже по-вертикали(по Y):
-если точка не нашлась-оставляем найденную и двигаемся дальше;
-если нашлась,то накладываем точку ,найденную по-вертикали на точку,найденную по-горизонтали(логическое ИЛИ).Таким образом получаем нужную нам точку,а остальные отбрасываем.
3.Двигаемся дальше.
Алгоритм вроде оптимальный,но никак не дойду мыслями,как его красиво реализовать в VS.
-
вам скорее нужна не просто однопикселезация, а чтобы кривая была гладкая и неразрывная. (в математической правильности фурмулировки не уверен )
я думаю только морфологией тут не обойтись. думаю тут надо присмотрется к сплайнам.
http://www.gamedev.ru/code/forum/?id=124256
Мне скорее надо убрать лишние помехи (шумы) с линий!Просто если я сделаю кривую гладкой,то я не решу свою задачу ,потому что будут большие потери.А разрывность я устраняю другим методом.
-
Воспользовался следующей морфологией,но потери слишком большие,как их можно уменьшить:
//cvDilate() #include "stdafx.h" #include <cv.h> #include <highgui.h> #include <stdlib.h> #include <stdio.h> #define CV_SHAPE_ELLIPSE 1 IplImage* image = 0; IplImage* dst = 0; IplImage* dilate = 0; int radius = 1; int radius_max=10; // // функция-обработчик ползунка - // радиус ядра void myTrackbarRadius(int pos) { radius = pos; } int iterations = 1; int iterations_max = 10; // // функция-обработчик ползунка - // число итераций void myTrackbarIterations(int pos) { radius = pos; } int main(int argc, char* argv[]) { IplImage* image = cvLoadImage("d:\\test.bmp", 1); // клонируем картинку dst = cvCloneImage(image); dilate = cvCloneImage(image); // окно для отображения картинки cvNamedWindow("original",CV_WINDOW_AUTOSIZE); cvNamedWindow("dilate",CV_WINDOW_AUTOSIZE); cvCreateTrackbar("Radius", "original", &radius, radius_max, myTrackbarRadius); cvCreateTrackbar("Iterations", "original", &iterations, iterations_max, myTrackbarIterations); while(1){ // показываем картинку cvShowImage("original",image); // создаём ядро IplConvKernel* Kern = cvCreateStructuringElementEx(radius+1, radius+1, radius, radius, CV_SHAPE_ELLIPSE); // выполняем преобразования cvDilate(image, dilate, Kern, iterations); // показываем результат cvShowImage("dilate",dilate); //cvSaveImage("dilate.jpg", dilate); cvReleaseStructuringElement(&Kern); char c = cvWaitKey(33); if (c == 27) { // если нажата ESC - выходим cvSaveImage("dilate.jpg", dilate); break; } } // освобождаем ресурсы cvReleaseImage(&image); cvReleaseImage(&dst); cvReleaseImage(&dilate); // удаляем окно cvDestroyWindow("original"); cvDestroyWindow("dilate"); return 0; }
Пробовал на изображении:
потери большие...
-
Что верно,то верно
Спасибо!
-
А возможен вариант переделки программы под статическое изображение.Чтоб просто загружать нужную картинку?
Просто для меня сделать это в Builder туговато,поэтому и спрашивал про VS.
-
-
-
-
Это немного не то,мне нужна скорее именно однопикселизация,а не скелетизация!
-
Есть монохромное изображение с линиями,но линии нечёткие.Пытаюсь однопикселизировать изображение так,чтобы потери были минимальные и остался только контур.
Например,изображение:
Нужно убрать нечеткости такого рода:
Кто сталкивался с подобной проблемой,буду рад за информацию.
-
Например,какую морфологию?Я просто боюсь,что это будет получится тяжелая и заковыристая задача и алгоритм получится громоздким.
-
А можно ли реализовать создание треков так,чтобы они прорисовывались только один раз(однопиксельно) без "утолщений".Это нужно ,чтобы избежать трудностей в дальнейшем.
-
Целесообразно будет использовать функцию с подальшей передачей параметров ?И куда лучше сохранять подошедшие концы.Я немного сбился со своего алгоритма.
//Евклидово расстояние double dist(const CvPoint &w1, const CvPoint &w2) { return sqrt((double)((w2.x - w1.x)*(w2.x - w1.x) +(w2.y - w1.y)*(w2.y - w1.y))) ; }
Или можно сделать все как-то проще?
-
Я разобрался,все работает,проблема была в версии OpenCV.
Я для начала хочу все-таки восстановить элементарное изображение,используя фильтр Калмана,думаю,как правильней будет найти соответствующие концы.
А насчет оптимизации,я думаю ,что все-таки целесообразней будет выполнять восстановление в заданном окне,которое будет перемещаться по изображению,главное правильно размер подобрать.
-
Ошибок нет,но программа не выдает результат!
Выкладываю элементарное изображение:
Для наглядности вот тип изображения,которое должно восстанавливаться в идеале:
-
Программа успешно компилируется,но при запуске выдает ошибку.Пробовал уже и в студии и в Builder.
В Builder:
В студии:
Не могу понять,что ей не нравится.
-
Чувствую,что тоже на нее перейду,потому что Builder ругается на it1,пишет,что он уже был декларирован.Может я где-то что-то и недоглядел :
for (tracks_cont::iterator it1 = tracks.begin(); it1 != tracks.end() { if (it1->size() == 1) it1 = tracks.erase(it1); else ++it1; } for (tracks_cont::iterator it1=tracks.begin(); it1 != tracks.end(); ++it1) { for (points_cont::iterator it2 = it1->begin(); it2 != it1->end(); ++it2) { (second_img->imageData + it2->y * second_img->widthStep + it2->x)[0] = 0; cvShowImage("second_img", second_img); if (cvWaitKey(40) > 0) break; } } [/code]
Сейчас буду пробовать в студии.
-
Спасибо,буду разбираться!Потом отпишусь!А какую среду разработки посоветуешь или без разницы?
-
На данном этапе я пока собрал нужную литературу и додумываю как всё-таки использовать фильтр Калмана,ведь он в основном используется для динамических систем.
Я так понял ,что нужно создать окно,которое будет проходить по изображению и в котором будет проводиться наше восстановление.У меня была идея сделать из линии что-то вроде траектории движения и на разрыве использовать фильтр Калмана до тех пор,пока траектория не продолжится .Но твоё решение вроде смотрится проще,только я пока не сильно понимаю как найти конец какой цепочки подходит к концу другой.Если есть примеры или литература-буду благодарен за просвещение!
-
Есть только изображение,в этом-то и загвоздка!Я так понимаю,что массив с координатами точек надо получить в ходе выполнения задачи.
Мне бы хотя бы разобраться как одну линию соединить,дальше уже буду сам додумывать!
-
Есть изображение с разорванной линией!
Как можно восстановить его в Builder 6,используя фильтр Калмана,который хорошо описан в OpenCV.Пример изображения представлен на рисунке.
Фильтр Калмана прогнозирует следующее положение объекта,в нашем случае линии.
Кто сталкивался или знает как решить эту проблему,видел похожие исходники помогите!
Как прикрутить OpenCV к билдеру?
в OpenCV
Опубликовано · Report reply
Доработал свою программу.Результатом удовлетворен на все 100!
Особая благодарность Nuzhny,направил на путь истины!Большущее тебе спасибо!