Smorodov 579 Жалоба Опубликовано May 17, 2009 Архив с проектом здесь: skeleton.rar 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 20, 2009 Программка иллюстрирующая один из алгоритмов нахождения скелета изображения. Щелкаем мышкой по левой зеленой сетке (задаем исходное изображение), затем нажимаем "итерация 1", дальше "<-->", потом "итерация 2", "<-->", и сначала. Программка очень простая. Разобраться несложно. Для компиляции нужны компоненты со странички http://smorodov.narod.ru/Builder.htm. Архив с проектом: Skeletonizator.rar Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
sanarov 0 Жалоба Опубликовано June 1, 2009 В комментариях в программе написано что описание работы процедуры скелетизации будет дано позже. Хотелось бы побольше узнать об этой процедуре. Как работает? Зачем фильтры и т.д. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано June 1, 2009 В комментариях в программе написано что описание работы процедуры скелетизации будет дано позже. Хотелось бы побольше узнать об этой процедуре. Как работает? Зачем фильтры и т.д. Конкретно про алгоритм скелетизации тут: скелетизация.rar Про свертку тут: Свертка.pdf Оставшиеся вопросы можно задать на форуме или в комментах к статьям. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
FingerScan 0 Жалоба Опубликовано September 5, 2010 В описании алогоритма есть строчки: Где А(Р1)-число конфигураций 01 в последовательности P2,P3,P4,P5,P6,P7,P8,P9 , замыкая эту цепочку на Р2 ,т.е. вокруг этого пикселя существует только один переход от 0 к 1. Собственно вопрос: А есть ли в OpenCV функция, возвращающая количество этих переходов из 0 в 1, или придется вручную гонять циклами? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано September 5, 2010 В описании алогоритма есть строчки: Где А(Р1)-число конфигураций 01 в последовательности P2,P3,P4,P5,P6,P7,P8,P9 , замыкая эту цепочку на Р2 ,т.е. вокруг этого пикселя существует только один переход от 0 к 1. Собственно вопрос: А есть ли в OpenCV функция, возвращающая количество этих переходов из 0 в 1, или придется вручную гонять циклами? В OpenCV, в примере выше это делается последовательной сверткой изображения, полученного дистанционным преобразованием (из бинарного изображения) при помощи нескольких различных ядер, так как считать отдельные пиксели очень затратно. Кусок кода оттуда: // ядра ---------------------- float L0[]={ -1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, -1,-1,-1,-1,-1 }; float L45[]={ 0,-1,-1, 0, 2, -1,-1, 0, 2, 0, -1, 0, 2, 0,-1, 0, 2, 0,-1,-1, 2, 0,-1,-1, 0 }; float L90[]={ -1, 0, 2, 0,-1, -1, 0, 2, 0,-1, -1, 0, 2, 0,-1, -1, 0, 2, 0,-1, -1, 0, 2, 0,-1 }; float L135[]={ 2, 0,-1,-1, 0, 0, 2, 0,-1,-1, -1, 0, 2, 0,-1, -1,-1, 0, 2, 0, 0,-1,-1, 0, 2 }; //........ cvDistTransform(back_project,distsrc,CV_DIST_L2,5); cvFilter2D(distsrc,S00,&kern00); cvFilter2D(distsrc,S45,&kern45); cvFilter2D(distsrc,S90,&kern90); cvFilter2D(distsrc,S135,&kern135); for (int y=0; y < out->height; y++){ for (int x=0; x< out->width; x++){ Smax = MAX( MAX(((float*)(S00->imageData + y* S00->widthStep))[x], ((float*)(S45->imageData + y* S45->widthStep))[x]), MAX(((float*)(S90->imageData + y* S90->widthStep))[x], ((float*)(S135->imageData + y* S135->widthStep))[x])); ((float*)(out->imageData + y* out->widthStep))[x] = Smax > 0 ? Smax: 0.0; } } cvThreshold(out,out,7,1,CV_THRESH_BINARY);[/code] В документации описан альтернативный вариант, который применяется в демонстрационном примере. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Halloween 0 Жалоба Опубликовано April 22, 2011 Архив с проектом skeleton.rar не запускается!Возникает ошибка следующего характера: Не пойму где прокол... Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 23, 2011 Вначале файла надо поставить: #define _STLP_NO_CSTD_FUNCTION_IMPORTS #define _FM_NO_REMAP[/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Halloween 0 Жалоба Опубликовано April 23, 2011 Поставил ,теперь вылезла такая история: А нету этого же проекта в Visual Studio,с ним запар поменьше будет? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 23, 2011 cos, sin, tan и иже с ними заменяете на cosl, sinl, tanl и т. д. этого бага не будет. Кстати, а заголовочники Вы родные, не правленые брали, или правленые с этого форума? вот заголовочники отдельно: opencv.rar ЗЫ: Этого же проекта на VS нету. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Halloween 0 Жалоба Опубликовано April 23, 2011 Заголовочные я с разных проектов пособирал. Всё сделал как Вы сказали,проект прокомпилировался без ошибок ,но в результате выдал нерабочую форму: Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 23, 2011 Возможно камеру не нашел. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Halloween 0 Жалоба Опубликовано April 24, 2011 А возможен вариант переделки программы под статическое изображение.Чтоб просто загружать нужную картинку? Просто для меня сделать это в Builder туговато,поэтому и спрашивал про VS. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано April 24, 2011 Можно. C и в Африке C. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Halloween 0 Жалоба Опубликовано April 24, 2011 Что верно,то верно Спасибо! Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Almighty 1 Жалоба Опубликовано May 2, 2011 Все статьи лежат тут. Конкретно про алгоритм скелетизации тут: скелетизация Про фильтры и свертку Более развернутое описание будет когда переведу еще кусок документации. Док. по cvDistTransform сегодня будет там же. Оставшиеся вопросы можно задать на форуме или в комментах к статьям. Что-то ссылки не открываются Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано May 2, 2011 Что-то ссылки не открываются Да файлы отвалились при смене Wiki движка. Документ по алгоритму Зонга-Суня прикрепил (выше), остальное восстановлю позже файлы уже нашел, из doku-wiki в человеческий вид переведу, и будут тут pdf-ки. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Almighty 1 Жалоба Опубликовано May 24, 2011 Благодарю! Не сразу заметил прикрепленные файлы. Демонстрационный пример супер, не думал, что все настолько просто Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 1, 2011 пара материалов по теме на русском. http://www.graphicon.ru/1998/Image_Processing_&%20_Computational_Geometry/D_Ivanov_Kuzmin%20.pdf http://www.graphicon.ru/1998/Image_Processing_&%20_Computational_Geometry/Mestetskiy.pdf http://www.graphicon.ru/1999/Image_Processin_%20&_Pattern_Recognition/Reyer.pdf +еще http://www.graphicon.ru/2002/pdf/Pisarevsky_Re.pdf http://www.graphicon.ru/2001/Computational_Geometry/Kuchuganov.pdf http://www.graphicon.ru/2001/Computational_Geometry/Lagno_Sobolev.pdf http://www.graphicon.ru/html/proceedings/2010/conference/RU/Se4/058.pdf http://www.graphicon.ru/html/proceedings/2010/conference/RU/Se4/110.pdf http://www.graphicon.ru/html/proceedings/2009/young/section2/127/127_Paper.pdf http://www.graphicon.ru/html/proceedings/2009/conference/se14/124/124_Paper.pdf http://www.graphicon.ru/2008/proceedings/Russian/SR3/Paper_1.pdf http://www.graphicon.ru/2008/proceedings/Russian/SR4/Paper_3.pdf http://www.graphicon.ru/2007/proceedings/Papers/Paper_44.pdf и программа http://www.graphicon.ru/1998/bin/leo_mes.exe 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано June 9, 2011 Zhang-Suen algorithm. http://xa.yimg.com/kq/groups/1986690/749653118/name/skeleton.c #include <OpenCV/cv.h> #include <OpenCV/highgui.h> #define NORTH 1 #define SOUTH 3 void skeletonize(IplImage *src); int main (int argc, char * const argv[]) { IplImage *image = 0, *srcCopy = 0; int w, h, i, j, r, g, b; CvScalar pixel, pixOut; if(argc != 2) { printf("Usage: skeletonize <image_file>\n"); exit(1); } image = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE); //image = cvLoadImage(argv[1], 1); if (!image) { printf("Can't find %s\n", argv[1]); exit(1); } w = image->width; h = image->height; //srcCopy = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 3); srcCopy = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixel = cvGet2D(image, i, j); b = pixel.val[0]; if (b > 50) pixOut.val[0] = 255; else pixOut.val[0] = 0; cvSet2D(srcCopy, i, j, pixOut); } } skeletonize(srcCopy); cvNamedWindow("Original", CV_WINDOW_AUTOSIZE); cvMoveWindow("Original", 100, 100); cvShowImage("Original", image); cvNamedWindow("Skeleton", CV_WINDOW_AUTOSIZE); cvMoveWindow("Skeleton", 150, 150); cvShowImage("Skeleton", srcCopy); cvWaitKey(0); // Release images' buffers... cvReleaseImage(&image); cvReleaseImage(&srcCopy); //...and windows cvDestroyWindow("Original"); cvDestroyWindow("Skeleton"); return 0; } // 1-neighbors of pixel. int nays8(IplImage *im, int r, int c) { CvScalar pixel; int blue, k = 0, i, j; for (i = r-1; i <= r+1; i++) for (j = c-1; j <= c+1; j++) if (i != r || c != j) { pixel = cvGet2D(im, i, j); blue = pixel.val[0]; if (blue >= 1) k++; } return k; } int connectivity(IplImage *im, int r, int c) { int N = 0, b1, b2; CvScalar pixel; pixel = cvGet2D(im, r, c+1); b1 = pixel.val[0]; pixel = cvGet2D(im, r-1, c+1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r-1, c+1); b1 = pixel.val[0]; pixel = cvGet2D(im, r-1, c); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r-1, c); b1 = pixel.val[0]; pixel = cvGet2D(im, r-1, c-1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r-1, c-1); b1 = pixel.val[0]; pixel = cvGet2D(im, r, c-1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r, c-1); b1 = pixel.val[0]; pixel = cvGet2D(im, r+1, c-1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r+1, c-1); b1 = pixel.val[0]; pixel = cvGet2D(im, r+1, c); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r+1, c); b1 = pixel.val[0]; pixel = cvGet2D(im, r+1, c+1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; pixel = cvGet2D(im, r+1, c+1); b1 = pixel.val[0]; pixel = cvGet2D(im, r, c+1); b2 = pixel.val[0]; if (b1 >= 1 && b2 == 0) N++; return N; } void deleteCB(IplImage *im, IplImage *tmp) { int w, h, blue, i, j; CvScalar pixel; w = im->width; h = im->height; for (i = 1; i < h-1; i++) for (int j = 1; j < w-1; j++) { pixel = cvGet2D(tmp, i, j); blue = pixel.val[0]; if (blue == 1) { pixel.val[0] = 0; cvSet2D(im, i, j, pixel); cvSet2D(tmp, i, j, pixel); } } } void stair(IplImage *im, IplImage *tmp, int dir) { int i, j, b1, b2, b3, b4, b5, b6, b7, b8, b9, w, h; CvScalar pixel; int N, S, E, W, NE, NW, SE, SW, C; w = im->width; h = im->height; if (dir == NORTH) for (i = 1; i < h-1; i++) for (j = 1; j < w-1; j++) { pixel = cvGet2D(im, i-1, j-1); b1 = pixel.val[0]; pixel = cvGet2D(im, i-1, j); b2 = pixel.val[0]; pixel = cvGet2D(im, i-1, j+1); b3 = pixel.val[0]; pixel = cvGet2D(im, i, j-1); b4 = pixel.val[0]; pixel = cvGet2D(im, i, j); b5 = pixel.val[0]; pixel = cvGet2D(im, i, j+1); b6 = pixel.val[0]; pixel = cvGet2D(im, i+1, j-1); b7 = pixel.val[0]; pixel = cvGet2D(im, i+1, j); b8 = pixel.val[0]; pixel = cvGet2D(im, i+1, j+1); b9 = pixel.val[0]; if (b1 == 1) NW = 1; else NW = 0; if (b2 == 1) N = 1; else N = 0; if (b3 == 1) NE = 1; else NE = 0; if (b4 == 1) W = 1; else W = 0; if (b5 == 1) C = 1; else C = 0; if (b6 == 1) E = 1; else E = 0; if (b7 == 1) SW = 1; else SW = 0; if (b8 == 1) S = 1; else S = 0; if (b9 == 1) SE = 1; else SE = 0; if (dir == NORTH) { if (C && !(N && ((E && !NE && !SW && (!W || !S)) || (W && !NW && !SE && (!E || !S))))) { pixel.val[0] = 0; cvSet2D(tmp, i, j, pixel); } else { pixel.val[0] = 1; cvSet2D(tmp, i, j, pixel); } } else if (dir == SOUTH) { if (C && !(S && ((E && !SE && !NW && (!W || !N)) || (W && !SW && !NE && (!E || !N))))) { pixel.val[0] = 0; cvSet2D(tmp, i, j, pixel); } else { pixel.val[0] = 1; cvSet2D(tmp, i, j, pixel); } } } } // Zhang-Suen algorithm. void skeletonize(IplImage *im) { int janelaAH[][2] = { {1, 0}, {0, -1}, {-1, 0}, {0, 1} }; int janelaH[][2] = { {0, -1}, {1, 0}, {0, 1}, {-1, 0} }; int aBlue[6]; int w, h, i, v, j, k, blue, lin, col, iJanela, again = 1; CvScalar pixel, pixOut; IplImage *tmp = 0; w = im->width; h = im->height; tmp = cvCreateImage(cvGetSize(im), IPL_DEPTH_8U, 1); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { pixel = cvGet2D(im, i, j); blue = pixel.val[0]; if (blue > 0) pixel.val[0] = 0; else pixel.val[0] = 1; cvSet2D(im, i, j, pixel); pixOut.val[0] = 0; cvSet2D(tmp, i, j, pixOut); } } while (again) { again = 0; for (i = 1; i < h-1; i++) for (j = 1; j < w-1; j++) { pixel = cvGet2D(im, i, j); blue = pixel.val[0]; if (blue != 1) continue; k = nays8(im, i, j); iJanela = 0; if ((k >= 2 && k <= 6) && connectivity(im, i, j) == 1) { for (v = 0; v < 6; v++) { col = j + janelaAH[iJanela][0]; lin = i + janelaAH[iJanela][1]; pixel = cvGet2D(im, lin, col); aBlue[v] = pixel.val[0]; iJanela++; if (v == 2) iJanela = 1; } if (aBlue[0]*aBlue[1]*aBlue[2] == 0 && aBlue[3]*aBlue[4]*aBlue[5] == 0) { pixOut.val[0] = 1; cvSet2D(tmp, i, j, pixOut); again = 1; } } // if ((k >= 2... } // for (j = 1;... deleteCB(im, tmp); if (!again) break; for (i = 1; i < h-1; i++) for (j = 1; j < w-1; j++) { pixel = cvGet2D(im, i, j); blue = pixel.val[0]; if (blue != 1) continue; k = nays8(im, i, j); iJanela = 0; if ((k >= 2 && k <= 6) && connectivity(im, i, j) == 1) { for (v = 0; v < 6; v++) { col = j + janelaH[iJanela][0]; lin = i + janelaH[iJanela][1]; pixel = cvGet2D(im, lin, col); aBlue[v] = pixel.val[0]; iJanela++; if (v == 2) iJanela = 1; } if (aBlue[0]*aBlue[1]*aBlue[2] == 0 && aBlue[3]*aBlue[4]*aBlue[5] == 0) { pixOut.val[0] = 1; cvSet2D(tmp, i, j, pixOut); again = 1; } } // if ((k >= 2... } // for (j = 1;... deleteCB(im, tmp); } // while stair(im, tmp, NORTH); deleteCB(im, tmp); stair(im, tmp, SOUTH); deleteCB(im, tmp); for (i = 1; i < h-1; i++) for (j = 1; j < w-1; j++) { pixel = cvGet2D(im, i, j); blue = pixel.val[0]; if (blue > 0) pixel.val[0] = 0; else pixel.val[0] = 255; cvSet2D(im, i, j, pixel); } } // End skeletonize 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано August 1, 2011 http://www.geometry.caltech.edu/pubs/DCAD11.pdf 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано August 3, 2011 A Fast Parallel Algorithm for Thinning Digital Patterns http://cgm.cs.mcgill.ca/~godfried/teaching/projects97/azar/skeleton.html http://fourier.eng.hmc.edu/e161/lectures/morphology/node3.html http://www.rupj.net/portfolio/docs/skeletonization.pdfp236-zhang.pdf Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано October 4, 2011 http://pacific.mpi-cbg.de/wiki/index.php?title=AnalyzeSkeleton&oldid=4897&printable=yes простой анализ скелета 1 Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано October 31, 2011 http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/ http://en.wikipedia.org/wiki/Topological_skeleton http://en.wikipedia.org/wiki/Medial_axis http://www.ima.ge.cnr.it/ima/smg/research.html алгоритмы скелетизации Stentiford Thinning Zhang Suen Thinning Medial Axis Transform Hilditch, Rosenfeld, Zhang-Suen, and Nagendraprasad -Wang-Gupta Thinning http://www.rupj.net/portfolio/docs/skeletonization.pdf Stentiford thinning (F.W.M. Stentiford,R.G.Mortimer,"Some new Heuristics for thinning binary handprinted Characters for OCR",IEE Trans.on Sys,Man & Cybernetics,1983) Holt's Staircase removal (C.M.Holt,et.al,"An Improved parallel Thinning Algorithm",ACM,1987). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
DirecTwiX 4 Жалоба Опубликовано October 31, 2011 Была идея написать такой алгоритм, когда распознавание текста писал. Оказывается такое уже есть в большом количестве) Сейчас вот думаю... Если у букв выделить скелет, а потом распознать с помощью Hu моментов, то поидее должно быть очень неплохо. З.ы. В проге из второго поста есть небольшой баг - при нажатии на "<->" пиксели, лежащие на нижней границе первого изображения, не затираются. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах