Министерствообразования и науки Российской Федерации
Южно-Уральскийгосударственный университет
Кафедра Автоматикаи Управление
Курсоваяработа
на тему
Реализация методаглавных компонент с помощью библиотеки OpenCV
Выполнил:Пушников А.А.
Группа:ПС-669
ПроверилРазнополов К.О.
Дата «____»_____________2006 г.
Челябинск
2006 г
Оглавление
Метод главных компонент 2
Реализация метода главныхкомпонент в OpenCV_ 3
Текст программы_ 4
Методглавных компонент
Метод главных компонент (PrincipalComponent Analysis, PCA) применяется для сжатия информации без существенныхпотерь информативности. Он состоит в линейном ортогональном преобразованиивходного вектора X размерности N в выходной вектор Y размерности M, N. При этомкомпоненты вектора Y являются некоррелированными и общая дисперсия послепреобразования остаётся неизменной. Матрица X состоит из всех примеровизображений обучающего набора. Решив уравнение />,получаем матрицу собственных векторов />, где />– ковариационная матрица для X, а />–диагональная матрица собственных чисел. Выбрав из />подматрицу/>, соответствующую M наибольшим собственным числам,получим, что преобразование />, где />– нормализованный вектор с нулевым математическиможиданием, характеризует большую часть общей дисперсии и отражает наиболеесущественные изменения X.
Выбор первых M главных компонентразбивает векторное пространство на главное (собственное) пространство />, содержащее главные компоненты, и его ортогональноедополнение />.
Применение для задачи распознаванияизображений имеет следующий вид. Входные вектора представляют собойотцентрированные и приведённые к единому масштабу изображения. Собственныевектора, вычисленные для всего набора изображений, называются собственными объектами(eigenobject). С помощью вычисленных ранее матриц входное изображениеразлагается на набор линейных коэффициентов, называемых главными компонентами.Сумма главных компонент, умноженных на соответствующие собственные вектора,является реконструкцией изображения.
Для каждого изображения лицавычисляются его главные компоненты. Обычно берётся от 5 до 200 главныхкомпонент. Остальные компоненты кодируют мелкие различия между эталоном и шум.Процесс распознавания заключается в сравнении главных компонент неизвестногоизображения с компонентами всех остальных изображений. Для этого обычноприменяют какую-либо метрику (простейший случай – Евклидово расстояние). Приэтом предполагается, что изображения, соответствующие одному эталону,сгруппированы в кластеры в собственном пространстве. Из базы данных (илитренировочного набора) выбираются изображения-кандидаты, имеющие наименьшеерасстояние от входного (неизвестного) изображения.
Дальнейшее совершенствованиезаключалось в использовании метрики Махаланобиса и Гауссовского распределениядля оценки близости изображений. Для учёта различных ракурсов в этой же работеиспользовалось многомодальное распределение изображений в собственномпространстве.
Основное преимущество примененияанализа главных компонент – это хранение и поиск изображений в больших базахданных, реконструкция изображений.
Основной недостаток – высокиетребования к условиям съёмки изображений. Изображения должны быть получены вблизких условиях освещённости, одинаковом ракурсе. Должна быть проведенакачественная предварительная обработка, приводящая изображения к стандартнымусловиям (масштаб, поворот, центрирование, выравнивание яркости, отсечениефона).
Реализацияметода главных компонент в OpenCV
Библиотека OpenCV реализует описанный выше алгоритм следующимифункциями:
Функция, вычисляет собственныеобъекты эталонов:
void cvCalcEigenObjects(int nObjects, void* input, void* output, int ioFlags, int ioBufSize, void*userData, CvTermCriteria* calcLimit, IplImage* avg, float* eigVals ),
где
nObjects – число эталонов
input — указатель на массивизображений-эталонов (изображения глубиной 8 бит)
output – (выход функции) указатель намассив собственных объектов (изображения глубиной 32 бит)
ioFlags – флаги ввода/вывода. Дляработы с памятью.
ioBufSize – размер буфера. Дляработы с памятью.
userData – указатель на структуру дляработы с памятью.
calcLimit – критерий прекращениявычислений. Два варианта: по количеству итераций и по ко точности (?)
avg – (выход функции) усредненноеизображение эталонов
eigVals (выход функции) указатель насобственные числа (может быть NULL)
Функция, вычисляет коэффициентыразложения:
void cvEigenDecomposite( IplImage* obj, int eigenvec_count, void* eigInput, int ioFlags, void* userData, IplImage* avg, float*coeffs ),
где
obj – исследуемое изображение
eigenvec_count – число собственныхобъектов
eigInput — указатель на массивсобственных объектов (изображения глубиной 32 бит)
ioFlags – флаги ввода/вывода. Дляработы с памятью.
userData – указатель на структуру дляработы с памятью.
avg — (выход функции) усредненноеизображение эталонов
coeffs — (выход функции) коэффициентыразложения (?)
Функция, вычисляет проекцию исследуемогоизображения на пространство собственных объектов:
void cvEigenProjection(void* input_vecs, int eigenvec_count, int io_flags, void* userdata, float*coeffs, IplImage* avg, IplImage* proj ),
где
input_vec — указатель на массивсобственных объектов (изображения глубиной 32 бит)
eigenvec_count – число собственныхобъектов
io_flags – флаги ввода/вывода. Дляработы с памятью.
userdata – указатель на структуру дляработы с памятью.
coeffs — коэффициенты разложения (?)
avg — усредненное изображениеэталонов
proj — проекция исследуемогоизображения на пространство собственных объектов
В полученной проекции имеет смыслубрать излишние компоненты (например, с помощью функции cvThreshold – отсечениепо порогу). Далее полученный результат можно сравнивать с эталонами, дляпринятия решения. Способов сравнения много, это может быть, например,минимальное расстояние (Евклидово) или корреляция с эталонами.
Текстпрограммы
//—————————————————————————
#include
#pragma hdrstop
#include «Unit1.h»
#include «cxcore.h»
#include «cv.h»
//—————————————————————————
#pragma package(smart_init)
#pragma resource “*.dfm”
TForm1 *Form1;
IplImage **Objs, *Pro, *Object;
int obj_number=3;
HINSTANCE highgui,cv,cvaux;
IplImage* (__stdcall *cvLoadImage)( const char* filename,int iscolor);
int (__stdcall *cvSaveImage)( const char* filename, constCvArr* image);
int (__stdcall *cvNamedWindow)( const char* name, intflags );
void (__stdcall *cvShowImage)( const char* name, constCvArr* image );
IplImage* (__stdcall *cvCreateImage_)( CvSize size, intdepth, int channels );
double (__stdcall *cvDotProduct_)(const CvArr* src1, constCvArr* src2 );
void (__stdcall *cvMul_)(const CvArr* src1, const CvArr*src2, CvArr* dst, double scale=1 );
void (__stdcall *cvThreshold_)(const CvArr* src, CvArr*dst, double threshold,double max_value, int threshold_type);
//—————————————————————————
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//—————————————————————————
void show_im(TCanvas*c,IplImage *p)
{
for(int i=0;iwidth;i++)
for(int j=0;jheight;j++)
{
int a=p->imageDataOrigin[p->widthStep*j+i];
c->Pixels[i][j]=a&0x0000ff|(a
}
}
void pca(int obj_number, IplImage **Objs,CvTermCriterialimit, IplImage *Object,IplImage *Pro)
{
CvSize size;
int m1=obj_number;
IplImage **EigObjs, *Avg;
float *coeffs;
HINSTANCE hDLL = LoadLibrary(«cvaux100.dll»);
if (!hDLL) return;
void (__stdcall *cvCalcEigenObjects)( int nObjects, void*input, void* output, int ioFlags, int ioBufSize, void* userData,CvTermCriteria* calcLimit, IplImage* avg, float* eigVals );
cvCalcEigenObjects = (void(__stdcall *)( int nObjects,void* input, void* output, int ioFlags, int ioBufSize, void* userData,CvTermCriteria* calcLimit, IplImage* avg, float* eigVals ))GetProcAddress(hDLL,«cvCalcEigenObjects»);
if (!cvCalcEigenObjects) return;
void (__stdcall *cvEigenDecomposite)( IplImage* obj, intnEigObjs, void* eigInput, int ioFlags, void* userData, IplImage* avg, float*coeffs );
cvEigenDecomposite = (void(__stdcall *)( IplImage* obj,int nEigObjs, void* eigInput, int ioFlags, void* userData, IplImage* avg,float* coeffs ))GetProcAddress(hDLL, «cvEigenDecomposite»);
if (!cvEigenDecomposite) return;
void (__stdcall *cvEigenProjection)( void* eigInput, intnEigObjs, int ioFlags, void* userData, float* coeffs, IplImage* avg, IplImage*proj );
cvEigenProjection = (void(__stdcall *)( void* eigInput,int nEigObjs, int ioFlags, void* userData, float* coeffs, IplImage* avg,IplImage* proj ))GetProcAddress(hDLL, «cvEigenProjection»);
if (!cvEigenProjection) return;
EigObjs=new IplImage*[m1];
coeffs=new float[m1];
size.width = Object->width; size.height =Object->height;
Avg = cvCreateImage_( size, IPL_DEPTH_32F, 1 );
for(int i=0; i
{
EigObjs[i] = cvCreateImage_( size, IPL_DEPTH_32F, 1 );
}
cvCalcEigenObjects( obj_number, (void*)Objs,(void*)EigObjs, 0, 0, NULL, &limit, Avg, NULL );
cvEigenDecomposite( Object, m1, (void*)EigObjs, 0, NULL,Avg, coeffs );
cvEigenProjection ( (void*)EigObjs, m1, 0, NULL, coeffs,Avg, Pro );
FreeLibrary(hDLL);
// cvReleaseImage( &Avg );
// for(int i=0; i
// {
// cvReleaseImage( &EigObjs[i] );
// }
// cvFree( &coeffs);
}
void __fastcall TForm1::FormCreate(TObject *Sender)
{
highgui = LoadLibrary(«highgui100.dll»);
if (!highgui) return;
cvLoadImage = (IplImage*(__stdcall *)( const char*filename, int iscolor))GetProcAddress(highgui, «cvLoadImage»);
if (!cvLoadImage) return;
cvSaveImage = (int(__stdcall *)( const char* filename,const CvArr* image))GetProcAddress(highgui, «cvSaveImage»);
if (!cvSaveImage) return;
cvNamedWindow = (int(__stdcall *)( const char* name, intflags ))GetProcAddress(highgui, «cvNamedWindow»);
if (!cvNamedWindow) return;
cvShowImage = (void(__stdcall *)( const char* name, constCvArr* image ))GetProcAddress(highgui, «cvShowImage»);
if (!cvShowImage) return;
cv = LoadLibrary(«cxcore100.dll»);
if (!cv) return;
cvCreateImage_ = (IplImage*(__stdcall *)( CvSize size, intdepth, int channels ))GetProcAddress(cv, «cvCreateImage»);
if (!cvCreateImage_) return;
cvDotProduct_ = (double(__stdcall *)( const CvArr* src1,const CvArr* src2))GetProcAddress(cv, «cvDotProduct»);
if (!cvDotProduct_) return;
cvMul_ = (void(__stdcall *)( const CvArr* src1, constCvArr* src2, CvArr* dst, double scale=1))GetProcAddress(cv, «cvMul»);
if (!cvMul_) return;
cvaux = LoadLibrary(«cv100.dll»);
if (!cvaux) return;
cvThreshold_ = (void(__stdcall *)(const CvArr* src, CvArr*dst, double threshold,double max_value, intthreshold_type))GetProcAddress(cvaux, «cvThreshold»);
if (!cvThreshold_) return;
Objs=new IplImage*[obj_number];
Objs[0] = cvLoadImage( “.\\et\\1.bmp”, 0);
show_im(Image1->Canvas,Objs[0]);
Objs[1] = cvLoadImage( “.\\et\\2.bmp”, 0);
show_im(Image2->Canvas,Objs[1]);
Objs[2] = cvLoadImage( “.\\et\\3.bmp”, 0);
show_im(Image3->Canvas,Objs[2]);
String fname=«6.bmp»;
Object = cvLoadImage((“.\\in\\”+fname).c_str(),0);
show_im(Image4->Canvas,Object);
}
//—————————————————————————
void __fastcall TForm1::Button1Click(TObject *Sender)
{
float e[3];
CvTermCriteria limit;
CvSize size;
size.width = Object->width; size.height =Object->height;
Pro = cvCreateImage_( size, IPL_DEPTH_8U, 1 );
limit.type = CV_TERMCRIT_EPS;
limit.max_iter = 1;
limit.epsilon = 0.1;
show_im(Image4->Canvas,Object);
pca(obj_number,Objs,limit,Object,Pro);
show_im(Image5->Canvas,Pro);
cvThreshold_(Pro,Object,200,255,CV_THRESH_BINARY);
show_im(Image6->Canvas,Object);
cvMul_(Object,Objs[0],Pro);
show_im(Image7->Canvas,Pro);
cvMul_(Object,Objs[1],Pro);
show_im(Image8->Canvas,Pro);
cvMul_(Object,Objs[2],Pro);
show_im(Image9->Canvas,Pro);
e[0]=cvDotProduct_(Object,Objs[0])/cvDotProduct_(Objs[0],Objs[0]);
e[1]=cvDotProduct_(Object,Objs[1])/cvDotProduct_(Objs[1],Objs[1]);
e[2]=cvDotProduct_(Object,Objs[2])/cvDotProduct_(Objs[2],Objs[2]);
Label1->Caption=FloatToStr(int(e[0]*1000)/1000.);
Label2->Caption=FloatToStr(int(e[1]*1000)/1000.);
Label3->Caption=FloatToStr(int(e[2]*1000)/1000.);
if(e[0]>e[1])
if(e[0]>e[2])
ShowMessage(«1»);
if(e[1]>e[0])
if(e[1]>e[2])
ShowMessage(«2»);
if(e[2]>e[1])
if(e[2]>e[0])
ShowMessage(«3»);
}
//—————————————————————————
void __fastcall TForm1::Image1Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
Objs[0] =cvLoadImage(OpenPictureDialog1->FileName.c_str(), 0);
show_im(Image1->Canvas,Objs[0]);
}
}
//—————————————————————————
void __fastcall TForm1::Image2Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
Objs[1] =cvLoadImage(OpenPictureDialog1->FileName.c_str(), 0);
show_im(Image2->Canvas,Objs[1]);
}
}
//—————————————————————————
void __fastcall TForm1::Image3Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
Objs[2] =cvLoadImage(OpenPictureDialog1->FileName.c_str(), 0);
show_im(Image3->Canvas,Objs[2]);
}
}
//—————————————————————————
void __fastcall TForm1::Image4Click(TObject *Sender)
{
if(OpenPictureDialog1->Execute())
{
Object =cvLoadImage(OpenPictureDialog1->FileName.c_str(), 0);
show_im(Image4->Canvas,Object);
}
}
//—————————————————————————