Jump to content
Compvision.ru
Smorodov

Программа распознавания лиц методом главных компонент

Recommended Posts

Пытаюсь переписать распознавание по PCA на новый OpenCv 2.3. Там есть класс РСА, с помощью которого можно реализовать это. Вот что у меня получилось по коду:


#include <opencv2/core/core.hpp>

#include <opencv2/imgproc/imgproc.hpp>

#include <opencv2/gpu/gpu.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/features2d/features2d.hpp>


#include <vector>


using namespace std;


int _tmain(int argc, _TCHAR* argv[])

{

	ArgParser parser(argc, argv);


	char filelist[200]; 


	try {

		if (!parser.queryFilename("filelist", filelist)) {

			printf("Filelist not specified.\n"); 

			_getch();

			return -1;

		}

	}

	catch (char* str) {

		printf("%s\n", str);

		_getch();

		return -1; 

	}


	FilelistProcessor flP(filelist);


	const unsigned numpics = 100;


	vector <cv::Mat> img_tr;


	for (unsigned i = 0; i < numpics; i++) {

		cv::Mat itmp = cv::imread(flP.getfile(i), 0);

		img_tr.push_back(itmp);

	}


	unsigned imsize = img_tr[0].rows*img_tr[0].cols;

	cv::Mat mat_tr(numpics, imsize, img_tr[0].type());


	for (unsigned i = 0; i < numpics; i++) {

		cv::Mat matRow = mat_tr.row(i);

		memcpy(matRow.data, img_tr[i].data, imsize*sizeof(unsigned char));

	}


	const unsigned maxComponents = 60;


	cv::PCA eigenvectorsCompute(mat_tr, cv::Mat(), CV_PCA_DATA_AS_ROW, maxComponents);


	cv::Mat newImg = cv::imread(flP.getfile(numpics + 1), 0);

	cv::Mat newImgTr(1, imsize, img_tr[0].type());

	{

		cv::Mat matRow = newImgTr.row(0);

		memcpy(matRow.data, newImg.data, imsize*sizeof(unsigned char));

	}



	cv::Mat coeffs;

	coeffs.create(1, maxComponents, CV_32F);

	eigenvectorsCompute.project(newImgTr, coeffs);


	return 0;

}

FilelistProcessor - читает список файлов с изображениями лица. Файлов больше 100, поэтому ошибки в количестве векторов быть не может.

Проблема в том, что полученные на выходе coeffs - нулевые. Что может быть не так?

  • Like 1

Share this post


Link to post
Share on other sites

Нашла в чем проблема - изображения, по которым строится РСА должны быть приведены к типу CV_32FC1. Тогда все строится вполне корректно. Хотя в процессе поиска ошибки все переписала заново, код стал другим. Может еще есть какие-то неточности.

  • Like 1

Share this post


Link to post
Share on other sites

А вы бы могли, эту программу сбросить на электронный ящик diana87@mail.by , т.к. я не могу ее скачать....

Share this post


Link to post
Share on other sites

ok, скинул.

Оба варианта, с начала темы и с этой страницы.

PS: Не скачиваться может из-за менеджеров загрузки.

Share this post


Link to post
Share on other sites

С марковскими моделями не стал разбираться, а с PCA сразу с ходу пошло дело. Неплохо работает! Мануал на английском тема)

Share this post


Link to post
Share on other sites

Есть вопрос, подскажите пожалуйста! Я нахожу в кадре лицо каскадами Хаара. Затем выделяю найденную область(как в примере прямоугольником). Как мне найденную область фотографии сохранить в JPG и сделать строго определенного размера? Например 100х100 пикселей. Спасибо.

Share this post


Link to post
Share on other sites

Если в С, то через ROI

http://nashruddin.com/OpenCV_Region_of_Interest_(ROI)

если в с++, то

img(Rect(x,y,w,h)).copyTo(img1);

а затем Resize

http://linuxconfig.org/resize-an-image-with-opencv-cvresize-function

Вот кусок из одной программы подобного назначения:


CvRect * pFaceRect = (CvRect*)cvGetSeqElem(pRectSeq, 0);
cvSetImageROI(pImg, *pFaceRect);
IplImage * pFaceImg =
cvCreateImage( STD_SIZE, IPL_DEPTH_8U, 1 );
cvResize(pImg, pFaceImg, CV_INTER_AREA );
[/code]

  • Like 1

Share this post


Link to post
Share on other sites

Спасибо большое! Применил cvSetImageROI, все прекрасно работает под C++/cli.

Share this post


Link to post
Share on other sites

Еще вопросик есть по этой теме. Для распознавания лица методом главных компонент обязательно преобразовывать цветное изображение в градации серого? Как в этом ПРИМЕРЕ . И если обязательно, то как это сделать? Наверняка есть какая то встроенная функция, но поискав я нашел только работу с каналами RGB. Пробовал копировать 3-х канальное изображение в созданное вот таким методом cvCreateImage( STD_SIZE, IPL_DEPTH_8U, 1 ), сразу вылезает ошибка. Я так понял что нельзя запихнуть автоматом цветное изображение в черно-белое. Как быть?

Share this post


Link to post
Share on other sites

Как конвертировать нашел. Функция cvCvtColor(img, im2, CV_BGR2GRAY). Но про необходимость этого конвертирования вопрос актуален)

Share this post


Link to post
Share on other sites

можно сразу грузить в грей, конвертировать скорее надо т.к. полезной информации в 3-х каналах не так много(опять же цвет волос) или можно по 3-м каналам отдельно смотреть.

Share this post


Link to post
Share on other sites

Нужен совет! Последния два дня меня убивает непонятная вещь, а именно виснет приложение, которое фотографирует, находит лицо ресайзит его и записывает в БД на компьютере. Причем оно виснет оно самым странным образом.

1)Запускаю приложение. При этом сразу отображается видео с камеры на форму.

2)Нажимаю кнопку сфотографировать.

3)Находит лицо.

4)Фотографирует, ресайзит и сохраняет в БД все успешно.

5)Видео продолжает отображаться и вроде все впорядке. Можно даже нажать "Закрыть" и все закроется как надо.

НО

6) Если взять окно и попробовать перетащить его, сразу же "Завершена работа программы.." и "Widows ищет поиск решения данной проблемы.."

Еще одно - на ноутбуке все работает замечательно, ничего подобного не происходит. Практически всё идентично: ОС Windows 7, MS Visual Studio 2010, MS SQL 2008, разве что на ноутбуке стоит 64-х разрядная система.

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

К тому же иногда работает все прекрасно и на компьютере. В связи с чем такое может быть, куда смотреть, что делать даж не знаю. Может у кого то были подобные проблемы?

Спасибо за ваши ответы!

Share this post


Link to post
Share on other sites

А если скомпилировать под х64, работает ?

Share this post


Link to post
Share on other sites

Если не секрет, как это сделать?) На компьютере где висне стоит ОС 32 разрядная. На ноуте 64-х. Где именно копилировать надо? И как поменять настойки сборки, чтобы это сделать.

Share this post


Link to post
Share on other sites

Перетрудился я сегодня, тупить начал )).

А он и в отладочной и в релизной версии одинаково глючит?

Share this post


Link to post
Share on other sites

Нет, в отладочной версии еще при запуске "Возникла точка останова" и на ноуте и на компе. Но я отладочную версю запускал с библиотеками OpenCV для релизной версии. Может из-за этого?

Я еще думал что мож из-за фреймворка такое может быть каким то образом? Хотя и на ноутбуке и на компьютере ставился новый 4,5 вроде со студией. Приложение я пытаюсь сделать на 3-м фреймворке. Реально уже не знаю, что придумать.

Еще есть такое, что без нахождения лица работает стабильно. Может слишком много дейсвий при нажатии кнопки происходит и 32-х разрядная система не справляется? Хотя вроде ересь.

Share this post


Link to post
Share on other sites

Может. Если отладочную версию с релизными библиотеками запускать, GUI-шные функции глючат по-черному.

Share this post


Link to post
Share on other sites

Эх, а что ж делать с моим багом при релизной версии?

Может туплю п острашному.

Нашел еще один момент.

Для того чтоб получить при фотографировании картинку качества получше, увеличиваю разрешение считываемого кадра, т.к. видео с камеры отображается в миниатюрном окошке, если убрать это изменение кадра, то все работает, но фото конечно отстойного качества. Может надо как то оптимизировать эту задачу? Хотя все тоже - на ноуте работает с любыми настройками.


                                 timer1->Stop();//


				 Counter = 0; //счетчик времени для показа "Данные записаны в БД"


				 //BuffCount =0;


                                 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 1280); 

				 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 1024);


				 frame = cvQueryFrame( capture );


				 //-------/возврат к миниатюрному изображению/-----------//

				 cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, WidthFrame); 

			         cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, HieghtFrame);


Спасибо еще раз, за ваши ответы!

Share this post


Link to post
Share on other sites

Сильно похоже на переполнение стека, у Вас таймер останавливается на время вывода кадра?

timer1->Stop(); - это остановка таймера вызывающего функцию или это профилировка ?

Просто ситуация может быть такая:

Таймер вызывает функцию с интервалом времени, почти точно равным времени выполнения этой функции. Когда дергаете окно мышью, сообщения таймера задерживаются, и при первой возможности идут пачкой с короткими интервалами. Функция вызывается много раз, и стек переполняется, или возникают проблемы с потоками.

Резюме: Попробуйте останавливать таймер в функции обратного вызова, увеличьте интервал таймера, или уменьшите время выполнения функции обратного вызова.

  • Like 1

Share this post


Link to post
Share on other sites

timer1->Stop(); <-- это у меня остановка таймера, который отвечает за воспроизведение кадров в pictureBox.

Спаибо за ответ, очень похоже что у меня как раз эта проблема. Но т.к. я еще новичек в этом деле, особенно с таймерами. Что есть функция обратного вызова у таймера Windows Forms? У системного таймера есть такая функция.

Share this post


Link to post
Share on other sites

Smorodov, А почему количество векторов базиса это количество изображений - 1 ?

Share this post


Link to post
Share on other sites

2JoQeR: Функция обратного вызова, это та функция, которая вызывается таймером по истечении заданного интервала времени, то есть та самая функция, в которой Вы пишите что должно произойти по таймеру.

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

количество изображений - 1 - это, как мне думается, такая opencv-шная фишка (ранних версий),

в 2.4 я считал собственные векторы, этого ограничения нет

http://www.compvision.ru/forum/index.php?showtopic=852&st=20 (пост №37).

Share this post


Link to post
Share on other sites

нет -1 это от матана\линала такая фишка(http://www.cognotics.com/opencv/servo_2007_series/part_4/page_2.html ), что когда проецируем можем спроецировать на n-1 измерение, я так понимаю, можем и на меньшее кол-во ,а на большее не можем.

The PCA Subspace

However, the number of principal components we can find is also limited by the number of data points. To see why that is, think of a dataset that consists of just one point. What's the direction of maximum separation for this dataset? There isn't one, because there's nothing to separate. Now consider a dataset with just two points. The line connecting these two points is the first principal component. But there's no second principal component, because there's nothing more to separate: both points are fully on the line.

We can extend this idea indefinitely. Three points define a plane, which is a 2D object, so a dataset with three data points can never have more than two principal components, even if it's in a 3D, or higher, coordinate system. And so on.

In eigenface, each 50x50 face image is treated as one data point (in a 2,500 dimensional "space"). So the number of principal components we can find will never be more than the number of face images minus one.

Share this post


Link to post
Share on other sites

А, ну да, это идет от экономного способа поиска матрицы ковариации.

http://opencv.itseez.com/modules/core/doc/operations_on_arrays.html?highlight=calccovarmatrix#cv.CalcCovarMatrix

Там перемножаются транспонированные матрицы точек, результат имеет размерность NxN, где N количество изображений.

Есть и другой (стандартный) способ, без транспонирования, там матрица ковариации получается размерностью MxM, где M размерность вектора (кол-во точек в изображении).

Прикол в том, что максимальные собственные векторы в этих двух случаях совпадают.

Share this post


Link to post
Share on other sites

А кто нибудь реализовывал порог отсечения левых лиц в этой проге? по статье на хабре там порог 2.2 у него а у меня что то расстояния редко больше 2х получаются...

или в данном коде


for (i=0; i < nEigens; i++)

        {

            float d_i = projectedTestFace[i] - coeffs[iTrain][i];

            distSq += d_i * d_i/EigenVals->data.fl[i];

        }

считается эвклидово расстояние? а в статье я так понял расстояние Махаланобиса. Кто знает как его посчитать?

Я так понял что по PCA проще сделать порог отсечения, чем по марковским моделям

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×