Распараллеливание с iANPR SDK и OpenMP / iANPR SDK / Recog.ru - Распознавание образов для программистов


Распараллеливание с iANPR SDK и OpenMP

В библиотеке iANPR SDK нет встроенного распараллеливания, т.е. функция распознавания выполняется в одном потоке. Однако, когда производится работа с большими изображениями, например, 1920x1080, время распознавания на обычном ПК может быть недостаточно для работы в реальном времени. Для решения данной проблемы можно разбить изображение на части и анализировать их параллельно. Здесь, однако, следует помнить, что в случае попадания номера на пересечение частей, то он не будет распознан. Поэтому нужно внести некоторую избыточность, используя пересекающиеся части. Причем уровень пересечения определяется максимально возможными размерами объекта распознавания.
Предположим, что объект распознавания в форме круга, и его максимальный диаметр на изображении составляет Dmax. Тогда ширина области пересечения сегментов должна быть больше Dmax. В этом случае площадь несколько раз анализируемой области (в разных сегментах) будет рассчитываться по следующей формуле:
S = L * Dmax,
где L – длина границ между всеми сегментами. Понятно, что в этом случае S будет зависеть не только от количества сегментов, но и от их формы. На рисунках ниже показано два примера расположения сегментов. Один сегмент серого цвета, а другой белого. Область пересечения показана штрихами.


Недостатком является то, что при полном анализе изображения будет анализироваться не Width*Height площадь изображения, а Width*Height+S.
Предположим, что мы знаем количество ядер процессора, например, 6. Разделим изображение на 6 частей так:

Естественно нужно помнить об области пересечения частей.
1080/6 = 180
Возьмем в качестве максимальной высоты номера высоту в 80 пикселей. Тогда части вверх и вниз увеличатся на 40 пикселей, кроме самого верхнего и нижнего, где увеличение только в одну сторону.
Последовательная программа для теста:
{
	// Последовательно
	CvRect Rects[100];
	int all = 100;
	char** res = new char*[all];
	for(int j=0;j<all;j++) res[j] = new char[20];
	ANPR_OPTIONS a;
	a.Detect_Mode = ANPR_DETECTCOMPLEXMODE;
	a.min_plate_size = 500;
	a.max_plate_size = 50000;
	a.max_text_size = 20;		
	a.type_number = ANPR_RUSSIAN_BASE;		
	a.flags = 0;
	int i;		
	DWORD tick1 = GetTickCount();
	i = anprPlate( Img,  a, &all, Rects, res ); 
	DWORD tick2 = GetTickCount();			
	if ( i == 0 )
		for( int j = 0; j < all; j++ ) {				
			printf( "%s\n", res[j] );
		}
	printf( "Time:%5.3f;\n", (float) ( tick2 - tick1) / 1000 );

	for(int j=0;j<100;j++) delete [] res[j];
	delete [] res;		
}

Параллельная с использованием OpenMP:
// Параллельно
int add_size = 40; // на 40 пикселей увеличить размер блока, 80 - максимальная высота номера

int max = omp_get_num_procs();	
IplImage** Images = new IplImage*[max];
int i;

DWORD tick1 = GetTickCount();

for( i = 0; i < max; i++ )
{
	int k = add_size, h = 0;
	if ( i != 0 && i != max - 1 ) {
		k += add_size;
		h = add_size;
	}
	if ( i == max - 1 ) h = add_size;
	Images[i] = cvCreateImage( cvSize( Img->width, k + Img->height / max ), 8, 1 );
	cvSetImageROI( Img, cvRect( 0, i * int(Img->height / max) - h, Img->width, Img->height / max + k ) );
	cvCopy( Img, Images[i] );
	cvResetImageROI( Img );
}

#pragma omp parallel
{
#pragma omp for
	for( i = 0; i < max; i++ )
	{
		CvRect Rects[100];
		int all = 100;
		char** res = new char*[all];
		for(int j=0;j<all;j++) res[j] = new char[20];
		ANPR_OPTIONS a;
		a.Detect_Mode = ANPR_DETECTCOMPLEXMODE;
		a.min_plate_size = 500;
		a.max_plate_size = 50000;
		a.max_text_size = 20;		
		a.type_number = ANPR_RUSSIAN_BASE;		
		a.flags = 0;

		int i2 = anprPlate( Images[i],  a, &all, Rects, res ); 
		if ( i2 == 0 )
			for( int j = 0; j < all; j++ ) {				
#pragma omp critical
				{
					printf( "%s\n", res[j] );
				}
			}

		for(int j=0;j<100;j++) delete [] res[j];
		delete [] res;		
	}
}
DWORD tick2 = GetTickCount();
printf( "Time:%5.3f;\n", (float) ( tick2 - tick1) / 1000 );

for( i = 0; i < max; i++ )
	cvReleaseImage ( &Images[i] );
delete [] Images;

Для теста использовалось изображение:

Первоначально сравним насколько велика избыточность, откомпилировав программу с выключенным OpenMP. Успешное распознавание было в обоих случаях. Время распознавания:
Последовательный блок 0.297с
Параллельный блок 0.369с
Т.е. избыточность вычислений примерно в 1.24 раз. Во столько замедлилось вычисление.
После включения OpenMP параллельный блок отработал за 0.1с. Т.е. прирост производительности в 2.9 раз.
Почему такой малый прирост? 1) избыточность дополнительная; 2) вычисления в блоках неравномерные – где обнаружился номер, а где нет.
Но в принципе, даже такой прирост производительности – почти в 3 раза. А это позволяет за 1 секунду обработать 10 кадров, что для реального времени может быть достаточно.
  • 0
  • 28 июня 2014, 17:03
  • vidikon

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.