Captain 0 Жалоба Опубликовано January 11, 2012 Как найти координаты всех максимумов в одноканальном изображении? Функция cvMinMaxLoc подошла бы, но находит только один, самый первый максимум. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 11, 2012 тоже сталкивался с этим вопросом, но руки не дошли. тут проблема в том, что надо найти N сильнейших локальных максимумов, но если делать в лоб, то получиться, что последующие за первым максимумы с большой вероятностью будут стоять рядом с первым, значит после нахождения одного максимума, надо исключать вокруг него окрестность какого то размера из дальнейшего рассмотрения.(но и этот вариант не до конца правильный, если неправильно выбрать радиус окрестности) вообще наверно поможет что то типа local threshold с последующей работой с выделенными областями. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 11, 2012 Да, тут нужна более конкретная постановка задачи. Возможны варианты: 1. локальные максимумы в некоторой окрестности; 2. просто пороговое преобразование для нахождения значений больше заданного; 3. 1 и два одновременно. Посмотри как пример операцию математической морфологии tophat с последующей бинаризацией результата. На её основе тоже можно поиск максимумов в каждой найденной зоне замутить. Или подойдёт "голая" tophat? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 11, 2012 tophat не решает проблему, а только дает более узкую область в которой находится максимум. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 11, 2012 Ага, более корректную границу окрестности. То есть надо сделать tophat, провести бинаризацию, сегментацию и уже в каждом сегменте-блобе искать 1 максимум. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 11, 2012 еще watershed имеет какие то выходные маркеры, возможно их как то приспособить Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано January 11, 2012 Найти максимумы не трудно. Странно что в OpenCv я не нашёл функции. Сглаживаем картинку подойдёт любой алгоритм. Можно сделать через функцию Smooth правда не знаю доделали её для произвольного радиуса(апертуры) или нет. Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних. После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний). Дальше по желанию можно отсортировать и взять N самых больших максимумов. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Nuzhny 243 Жалоба Опубликовано January 11, 2012 Найти максимумы не трудно. Странно что в OpenCv я не нашёл функции. Сглаживаем картинку подойдёт любой алгоритм. Можно сделать через функцию Smooth правда не знаю доделали её для произвольного радиуса(апертуры) или нет. Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних. После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний). Дальше по желанию можно отсортировать и взять N самых больших максимумов. Тут зависит от исходных данных. Очень часто часть изображения может быть засвечена или просто с бликами. Тогда все максимумы будут находиться именно в области засветки. В таком случае надо выделять области равномерной освещённости и в таких областях находить только один максимум. Или при анализе данных с тепловизора. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 12, 2012 Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних. После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний). что то я не понял смысл, зачем сглаживание? вот например, если так делать, то все максимумы будут в самом белом кружке, а это не тот результат который хотелось бы получить. тут надо что то типа сегментации чтобы поделить на обалсти, но только чтобы еще и выдавался максимум области, а если область однородная то наверно ее центр тяжести. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано January 12, 2012 Сглаживание нужно, чтобы выделить однородные области и избавиться от шума. оноже регулирует что считать локальным максимумом, а что нет. Тогда все максимумы будут находиться именно в области засветки. Не будут. Мы ищем локальные максимумы, а не глобальные. Единственный минус если область не просто однородна(монотонная), но и имеет одно значение(const). То да алгоритм выберет одинаковы точку(при условии >=). Но тут можно опять таки доработать поиск центра тяжести. Картинку лучше рассматривать под увеличением всего 25 точек несколько лишних видимо из-за сжатия исходного. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 13, 2012 Можно еще distanceTransform применить и тогда максимумы будут в центрах однородных областей. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Pavia00 32 Жалоба Опубликовано January 13, 2012 По поводу distanceTransform. Можно считать 2 способами быстро и точно. Быстрый метод будет аналогично сглаживанию. А точный съест время. А артефакты будут аналогичными(в точный центр ты не попадёшь) хотя результат немного и будут отличаться(возможно немного точнее). Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 30, 2012 пытаюсь найти n максимумов на изображении depth 32 но чо то выдает не то что cvMinMaxLoc. class mPoint { public: mPoint(float in_max,CvPoint in_pt) { max= in_max; pt= in_pt; } float max; CvPoint pt; }; bool sort_points(mPoint a,mPoint { return (a.max>b.max); } vector<CvPoint> find_n_maxima(IplImage* img,int n) { vector<mPoint> vec; int h = img->height; int w = img->width; int step = img->widthStep/sizeof(float); float* data = (float*)img->imageData; for(int y=1;y<h-1;++y) //отступаем на 1 от краёв { for(int x=1;x<w-1;++x) { //8-ми связная область //123 //495 //678 float arr[9]; arr[0]=data[(y-1)*step+x-1]; arr[1]=data[(y-1)*step+x]; arr[2]=data[(y-1)*step+x+1]; arr[3]=data[(y)*step+x-1]; arr[4]=data[(y)*step+x+1]; arr[5]=data[(y+1)*step+x-1]; arr[6]=data[(y+1)*step+x]; arr[7]=data[(y+1)*step+x+1]; arr[8]=data[(y)*step+x]; float max=-1; int id=-1; for(int i=0;i<9;++i) { if(max<=arr[i]) { max=arr[i]; id=i; } } if(id==8) { vec.push_back(mPoint(data[(y)*step+x],cvPoint(x,y))); } } } sort(vec.begin(),vec.end(),sort_points); vector<CvPoint> vec_out; for(int i=0;i<n;++i) //надо дополнительно фильтровать т.е. оставить только уникальные { if(i<vec.size()) vec_out.push_back(vec[i].pt); } return vec_out; }[/code] Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 30, 2012 Я бы взял черное изображение, записал несколько точек с известными значениями и прогнал алгоритм поиска в отладчике. Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 30, 2012 вообще странно, если например так cvZero(img); draw_on_32(img); то точки правильно находит. void draw_on_32(IplImage* img) { int h = img->height; int w = img->width; int step = img->widthStep/sizeof(float); float* data = (float*)img->imageData; data[(2)*step+5]= 0.5; data[(1)*step+100]= 0.7; data[(9)*step+10]= 0.2; } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 30, 2012 так и не понял, в чём там ошибка, но этот метод вроде работает. void MultipleMaxLoc( const IplImage& image, CvPoint** locations, int numMaxima ) { // initialize input variable locations *locations = new CvPoint[numMaxima]; // create array for tracking maxima //double maxima[numMaxima]; double* maxima= new double[numMaxima]; for( int i = 0; i < numMaxima; i++ ) { maxima[i] = 0.0; } // extract the raw data for analysis float* data; int step; CvSize size; cvGetRawData( &image, ( uchar** )&data, &step, &size ); step /= sizeof( data[0] ); for( int y = 0; y < size.height; y++, data += step ) { for( int x = 0; x < size.width; x++ ) { // insert the data value into the array if it is greater than any of the // other array values, and bump the other values below it, down for( int j = 0; j < numMaxima; j++ ) { if( data[x] > maxima[j] ) { // move the maxima down for( int k = numMaxima - 1; k > j; k-- ) { maxima[k] = maxima[k-1]; ( *locations )[k] = ( *locations )[k-1]; } // insert the value maxima[j] = ( double )data[x]; ( *locations )[j].x = x; ( *locations )[j].y = y; break; } } } } delete[] maxima; } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Smorodov 579 Жалоба Опубликовано January 30, 2012 А что первый вариант вообще что то не то выдает? Или немного ошибается? Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
mrgloom 242 Жалоба Опубликовано January 30, 2012 ну например должен выдавать максимум 0.9, а выдает ~0.7 и точки все расположены близко к верхней границе изображения. так например всё правильно но долго vector<CvPoint> find_n_maxima(IplImage* img,int n) { vector<mPoint> vec; int h = img->height; int w = img->width; int step = img->widthStep/sizeof(float); float* data = (float*)img->imageData; for(int y=0;y<h;++y) { for(int x=0;x<w;++x) { //метод когда записываются все а потом просто сортируются vec.push_back(mPoint(data[y*step+x],cvPoint(x,y))); } } sort(vec.begin(),vec.end(),sort_points); vector<CvPoint> vec_out; for(int i=0;i<n;++i) { if(i<vec.size()) vec_out.push_back(vec[i].pt); } return vec_out; } Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах