Перейти к содержимому
Compvision.ru
Captain

Поиск максимумов

Recommended Posts

Как найти координаты всех максимумов в одноканальном изображении? Функция cvMinMaxLoc подошла бы, но находит только один, самый первый максимум.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

тоже сталкивался с этим вопросом, но руки не дошли.

тут проблема в том, что надо найти N сильнейших локальных максимумов, но если делать в лоб, то получиться, что последующие за первым максимумы с большой вероятностью будут стоять рядом с первым, значит после нахождения одного максимума, надо исключать вокруг него окрестность какого то размера из дальнейшего рассмотрения.(но и этот вариант не до конца правильный, если неправильно выбрать радиус окрестности)

вообще наверно поможет что то типа local threshold с последующей работой с выделенными областями.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да, тут нужна более конкретная постановка задачи. Возможны варианты:

1. локальные максимумы в некоторой окрестности;

2. просто пороговое преобразование для нахождения значений больше заданного;

3. 1 и два одновременно.

Посмотри как пример операцию математической морфологии tophat с последующей бинаризацией результата. На её основе тоже можно поиск максимумов в каждой найденной зоне замутить. Или подойдёт "голая" tophat?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

tophat не решает проблему, а только дает более узкую область в которой находится максимум.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ага, более корректную границу окрестности. То есть надо сделать tophat, провести бинаризацию, сегментацию и уже в каждом сегменте-блобе искать 1 максимум.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

еще watershed имеет какие то выходные маркеры, возможно их как то приспособить

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Найти максимумы не трудно. Странно что в OpenCv я не нашёл функции.

Сглаживаем картинку подойдёт любой алгоритм. Можно сделать через функцию Smooth правда не знаю доделали её для произвольного радиуса(апертуры) или нет.

Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних.

После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний).

Дальше по желанию можно отсортировать и взять N самых больших максимумов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Найти максимумы не трудно. Странно что в OpenCv я не нашёл функции.

Сглаживаем картинку подойдёт любой алгоритм. Можно сделать через функцию Smooth правда не знаю доделали её для произвольного радиуса(апертуры) или нет.

Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних.

После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний).

Дальше по желанию можно отсортировать и взять N самых больших максимумов.

Тут зависит от исходных данных. Очень часто часть изображения может быть засвечена или просто с бликами. Тогда все максимумы будут находиться именно в области засветки. В таком случае надо выделять области равномерной освещённости и в таких областях находить только один максимум. Или при анализе данных с тепловизора.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Затем поиск локального максимума. Локальный максимум считаеться пиксель больше соседних.

После сглаживания достаточно проверить 4 соседних пикселя(левый, правый, верхний, нижний).

что то я не понял смысл, зачем сглаживание?

image.png

вот например, если так делать, то все максимумы будут в самом белом кружке, а это не тот результат который хотелось бы получить.

тут надо что то типа сегментации чтобы поделить на обалсти, но только чтобы еще и выдавался максимум области, а если область однородная то наверно ее центр тяжести.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сглаживание нужно, чтобы выделить однородные области и избавиться от шума. оноже регулирует что считать локальным максимумом, а что нет.

Тогда все максимумы будут находиться именно в области засветки.

Не будут. Мы ищем локальные максимумы, а не глобальные.

N_local_out.png

Единственный минус если область не просто однородна(монотонная), но и имеет одно значение(const). То да алгоритм выберет одинаковы точку(при условии >=). Но тут можно опять таки доработать поиск центра тяжести.

N_local_out1.png

Картинку лучше рассматривать под увеличением всего 25 точек несколько лишних видимо из-за сжатия исходного.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Можно еще distanceTransform применить и тогда максимумы будут в центрах однородных областей.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

По поводу distanceTransform.

Можно считать 2 способами быстро и точно.

Быстрый метод будет аналогично сглаживанию.

А точный съест время. А артефакты будут аналогичными(в точный центр ты не попадёшь) хотя результат немного и будут отличаться(возможно немного точнее).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

пытаюсь найти 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]

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я бы взял черное изображение, записал несколько точек с известными значениями и прогнал алгоритм поиска в отладчике.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

вообще странно, если например так

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;


}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

так и не понял, в чём там ошибка, но этот метод вроде работает.

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;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

А что первый вариант вообще что то не то выдает? Или немного ошибается?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

ну например должен выдавать максимум 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;

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×