?? eigenfaces.c
字號:
/***
** libface - Library of face recognition and supporting algorithms
Copyright (c) 2003 Stefan Farthofer
This file is part of libface, which is
free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information seek us at http://sourceforge.net/projects/openbio/
** or write an email to dimitri.pissarenko@gmx.net or farthofer@chello.at.
***/
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>
#include <IL/IL.h>
#include "frbase.h"
#include "fr.h"
#include "recoalgo.h"
#include "eigenfaces.h"
#include "matrix.h"
/* functions used internally */
void _efSortIdx(float* v, int* idx, unsigned int nrImages);
/* this is used to construct the FRrecoAlgo struct */
FRrecoAlgo* _efGetAlgo(void) {
FRrecoAlgo* algo;
algo = (FRrecoAlgo*)malloc(sizeof(FRrecoAlgo));
if (algo == NULL) return NULL;
memset(algo, 0, sizeof(algo));
algo->init = _efInit;
algo->getName = _efGetName;
algo->getType = _efGetType;
algo->setupAlgoInstance = _efSetupAlgoInstance;
algo->getParametersSize = _efGetParametersSize;
algo->serializeParameters = _efSerializeParameters;
algo->freeParameters = _efFreeParameters;
algo->copyParameters = _efCopyParameters;
algo->computeTrait = _efComputeTrait;
algo->compareTraits = _efCompareTraits;
algo->getTraitSize = _efGetTraitSize;
algo->serializeTrait = _efSerializeTrait;
algo->freeTrait = _efFreeTrait;
algo->trainedDataToImages = _efTrainedDataToImages;
algo->trainedDataToText = _efTrainedDataToText;
algo->traitToImages = _efTraitToImages;
algo->traitToText = _efTraitToText;
return algo;
}
int _efInit(void) {
return FR_OK;
}
const char* _efGetName(void) {
return "Eigenfaces";
}
int _efGetType(void) {
return FR_TYPE_EIGENFACES;
}
/* don't blame me for the goto's unless you have a better idea for the error handling */
/* maybe something like an allocation stack.... */
int _efSetupAlgoInstance(FRrecognitionParameters* gParms, FRalgoParam* algoParms, unsigned int nrAlgoParms, FRimage* images, unsigned int nrImages, BYTE** parms) {
unsigned int nrFaces = 0, i, j, * idx;
unsigned int pixels = gParms->width*gParms->height;
float* matA, * matAt, * average, * matL, * vecValues, * matEvSmall, * temp;
int err = FR_ERR_NOMEM;
/* check if we got enough training images */
if (nrImages < 2)
return FR_ERR_INVALID_PARMS;
/* process parameters */
for (i=0; i < nrAlgoParms; i++) {
switch(algoParms[i].id) {
case EF_FACES:
nrFaces = *(int*)algoParms[i].data;
break;
default:
break;
}
}
if (nrFaces > nrImages-1 || nrFaces < 1)
nrFaces = nrImages-1;
/* allocations */
if (!(matA = (float*) malloc(sizeof(float)*pixels*nrImages))) goto LmatA;
if (!(matAt = (float*) malloc(sizeof(float)*pixels*nrImages))) goto LmatAt;
if (!(matL = (float*) malloc(sizeof(float)*nrImages*nrImages))) goto LmatL;
if (!(vecValues = (float*) malloc(nrImages*sizeof(float)))) goto LvecValues;
if (!(matEvSmall = (float*) malloc(nrImages*nrImages*sizeof(float)))) goto LmatEvSmall;
if (!(idx = (unsigned int*) malloc(sizeof(unsigned int)*nrImages))) goto Lidx;
if (!(*parms = (BYTE*) malloc(sizeof(int) + pixels*(nrFaces+1)*sizeof(float)))) goto Lparms;
average = (float*)(*parms + sizeof(int));
memset(average, 0, (size_t)pixels*sizeof(float));
*(int*)*parms = nrFaces;
/* generate matA - copy values and compute average, each column holds an image */
for (i=0; i < pixels; i++) {
for (j=0; j < nrImages; j++) {
matA[j+i*nrImages] = images[j].imgdata[i];
average[i] += images[j].imgdata[i];
}
average[i] /= nrImages;
}
/* generate matA - subtract average */
for (i=0; i < pixels; i++) {
for (j=0; j < nrImages; j++) {
matA[j+i*nrImages] -= average[i];
}
}
/* now calculate A^t and then L=A^t*A */
_matTransposeD(matAt, matA, pixels, nrImages);
_matMultiplyD(matL, matAt, matA, nrImages, pixels, nrImages);
/* now calculate eigenvectors and values of L and sort */
if (err =_matEigenSD(matL, nrImages, vecValues, matEvSmall)) goto Lcleanup;
_matTransposeQ(matEvSmall, nrImages); /* we the want vectors in the rows */
_efSortIdx(vecValues, idx, nrImages);
/* and calculate the eigenvectors of C=A*A^t
* the i-the eigenvector is calculated such that
* e_i = A*es_i
* where es_i is the i-th eigenvector of the small matrix
*/
temp = (float*)(average + pixels);
for (i=0; i < nrFaces; i++, temp+=pixels) {
_matMultiplyD(temp, matA, matEvSmall+idx[i]*nrImages, pixels, nrImages, 1);
}
/* note: since the last operation that touched err must have set it to FR_OK to reach
* this point we don't have to set it now
*/
/* deallocate everything */
Lcleanup:
Lparms:
free(idx);
Lidx:
free(matEvSmall);
LmatEvSmall:
free(vecValues);
LvecValues:
free(matL);
LmatL:
free(matAt);
LmatAt:
free(matA);
LmatA:
return err;
}
size_t _efGetParametersSize(FRrecognitionParameters* gParms, BYTE* parms) {
int pixels = gParms->width*gParms->height;
/* one int for number of eigenfaces, average picture, eigenfaces */
return sizeof(int)+(pixels*(*((int*)parms))+pixels)*sizeof(float);
}
int _efSerializeParameters(FRrecognitionParameters* gParms, BYTE** parms, BYTE** mem, size_t maxsz, BYTE direction) {
int nrFaces, pixels = gParms->width*gParms->height;
/* sanity check */
if (direction == FR_OUT && maxsz < _efGetParametersSize(gParms, *parms))
return FR_ERR_ALLOCMORE;
if (direction == FR_IN) { /* we need the size in advance, so we can allocate memory */
nrFaces = **((int **)mem);
*parms = (BYTE*) malloc(sizeof(int)+(nrFaces+1)*pixels*sizeof(float));
if (*parms == NULL) return FR_ERR_NOMEM;
} else {
nrFaces = *((int*)*parms);
}
/* copy number of eigenfaces and float data */
frCopyMem(mem, *parms, sizeof(int), direction);
frCopyMem(mem, *parms, (nrFaces+1)*pixels*sizeof(float), direction);
return FR_OK;
}
void _efFreeParameters(FRrecognitionParameters* gParms, BYTE** parms) {
free(*parms);
*parms = NULL;
}
int _efCopyParameters(FRrecognitionParameters* gParms, BYTE** parmsDst, BYTE *parmsSrc) {
size_t sz;
sz = _efGetParametersSize(gParms, parmsSrc);
*parmsDst = (BYTE*) malloc(sz);
if (*parmsDst == NULL) return FR_ERR_NOMEM;
memcpy((void*)*parmsDst, (const void*)parmsSrc,sz);
return FR_OK;
}
/* our traits are weights for eigenfaces, these are calculate with this formula:
* w_i = ef_i * (image - average)
* note that we don't have to transpose one of the vectors since the memory
* layout of a row vector is the same as that of a column vector
*/
int _efComputeTrait(FRrecognitionParameters* gParms, BYTE* parms, FRimage* image, BYTE** trait) {
float* img, * ef, * w;
int err = FR_ERR_NOMEM, i;
unsigned int pixels = gParms->width*gParms->height;
if (!(img = (float*)malloc(sizeof(float)*pixels))) goto Limg;
if (!(*trait = (BYTE*)malloc(sizeof(float)* *(int*)parms))) goto Ltrait;
_matSubtractD(img, image->imgdata, (float*)(parms+sizeof(int)), pixels, 1);
ef = (float*)(parms+sizeof(int)+pixels*sizeof(float));
w = (float*)*trait;
for (i=*(int*)parms-1; i >= 0; i--, w++, ef+=pixels) {
_matMultiplyD(w, ef, img, 1, pixels, 1);
}
err = FR_OK;
Ltrait:
free(img);
Limg:
return err;
}
/* compares two weight sets, if the distance is less than a threshold, the range [0, threshold]
* is normalized to [0,1], for distance we use
*/
int _efCompareTraits(FRrecognitionParameters* gParms, BYTE* parms, BYTE* trait1, BYTE* trait2, float* probability) {
int i;
float f;
*probability = 0;
for(i=*(int*)parms-1; i >= 0; i--) {
printf("\nFactor for ef%2d: ", i);
f = (((float*)trait1)[i] - ((float*)trait2)[i])*(((float*)trait1)[i] - ((float*)trait2)[i]);
while (f > 1.0f) {
printf("*");
f = f/10;
}
*probability += (((float*)trait1)[i] - ((float*)trait2)[i])*(((float*)trait1)[i] - ((float*)trait2)[i]);
}
*probability = (float)sqrt(*probability);
printf("\ndistance is %f\n", *probability);
if (*probability < EF_DIST_TRESH) {
*probability /= EF_DIST_TRESH;
*probability -= 1;
*probability *= -1;
} else {
*probability = 0.0f;
}
return FR_OK;
}
size_t _efGetTraitSize(FRrecognitionParameters* gParms, BYTE* parms, BYTE* trait) {
return sizeof(float)*(*((int*)parms));
}
int _efSerializeTrait(FRrecognitionParameters* gParms, BYTE* parms, BYTE** trait, BYTE** mem, size_t maxsz, BYTE direction) {
size_t sz;
sz = sizeof(float) * *((int*)parms);
if (direction == FR_IN) {
*trait = (BYTE*) malloc(sz);
if (*trait == NULL) return FR_ERR_NOMEM;
} else if (sz < maxsz) return FR_ERR_ALLOCMORE;
frCopyMem(mem, *trait, sz, direction);
return FR_OK;
}
void _efFreeTrait(FRrecognitionParameters* gParms, BYTE* parms, BYTE** trait) {
free(*trait);
*trait = NULL;
}
int _efTrainedDataToImages(FRrecognitionParameters* gParms, BYTE* parms, FRimage** images, unsigned int* nrImages) {
float min, max, * efdata, * temp;
int pixels = gParms->width * gParms->height, i, j, nrEf, err = FR_ERR_NOMEM;
nrEf = *(int*)parms;
if (! (*images = (FRimage*) malloc(sizeof(FRimage)* (nrEf+1)))) return FR_ERR_NOMEM;
/* the first image is our average image ... */
if (!((**images).imgdata = malloc(sizeof(float)*pixels))) {
free(*images);
return FR_ERR_NOMEM;
}
memcpy((**images).imgdata, parms+sizeof(int), pixels*sizeof(float));
(**images).height = gParms->height;
(**images).width = gParms->width;
efdata = (float*) (parms + sizeof(int) + pixels*sizeof(float));
/* we normalize the images to [0,1], maybe I'll find a better way later */
min = efdata[0];
max = efdata[0];
for (i = pixels * nrEf - 1; i > 0; i--) { /* we don't have to consider efdata[0] since this was used for init */
if (efdata[i] > max) max = efdata[i];
else if (efdata[i] < min) min = efdata[i];
}
max -= min;
for (i = 1; i < nrEf+1; i++) {
if (!((*images)[i].imgdata = malloc(sizeof(float) * pixels))) break;
(*images)[i].height = gParms->height;
(*images)[i].width = gParms->width;
temp = (*images)[i].imgdata;
for (j = 0; j < pixels; j++, temp++, efdata++)
*temp = (*efdata-min)/max; /* copy and normalize */
}
if (i != nrEf+1) { /* something went wrong, dealloc */
for(i--; i > 0; i--) {
free((*images)[i].imgdata);
}
free(*images);
} else { /* everything ok */
err = FR_OK;
*nrImages = nrEf+1;
}
return err;
}
int _efTrainedDataToText(FRrecognitionParameters* gParms, BYTE* parms, char** text) {
return FR_ERR_NOTIMPL;
}
int _efTraitToImages(FRrecognitionParameters* gParms, BYTE* parms, BYTE* trait, FRimage** images, unsigned int* nrImages) {
int i,j, nrFaces = *(int*)parms, pixels = gParms->width*gParms->height;
float* avg = (float*) (parms+sizeof(int)), * ef = avg+pixels, * weights = (float*) trait;
float min, max;
/* allocate space for image structs*/
if ((*images = (FRimage*) malloc(sizeof(FRimage)*(nrFaces+1))) == NULL) return FR_ERR_NOMEM;
/* compute components */
for (i=0; i < nrFaces; i++) {
if (((*images)[i].imgdata = (float*) malloc(sizeof(float)*pixels)) == NULL) break;
(*images)[i].height = gParms->height;
(*images)[i].width = gParms->width;
_matMultiplyD((*images)[i].imgdata, weights+i, ef+pixels*i,1,1,pixels);
}
if (i < nrFaces) { /* something went wrong */
for (; i >= 0; i--) {
free((*images)[i].imgdata);
}
return FR_ERR_NOMEM;
}
if (((*images)[i].imgdata = (float*) malloc(sizeof(float)*pixels)) == NULL) {
for (; i >= 0; i--) {
free((*images)[i].imgdata);
}
return FR_ERR_NOMEM;
}
(*images)[i].height = gParms->height;
(*images)[i].width = gParms->width;
memset((*images)[i].imgdata, 0, sizeof(float)*pixels);
/* add images up to reconstructed view */
for (i=0; i < nrFaces; i++) {
_matAdd((*images)[nrFaces].imgdata, (*images)[i].imgdata, 1, pixels);
}
/* add average to complete reconstruction */
_matAdd((*images)[nrFaces].imgdata, avg, 1, pixels);
*nrImages = nrFaces+1;
/* get min and max */
min = (*images)[0].imgdata[0];
max = (*images)[0].imgdata[0];
for (i=0; i < nrFaces+1; i++) {
for (j=0; j < pixels; j++) {
if ((*images)[i].imgdata[j] > max) max = (*images)[i].imgdata[j];
if ((*images)[i].imgdata[j] < min) min = (*images)[i].imgdata[j];
}
}
printf("\n MAX=%f MIN=%f\n", max, min);
return FR_OK;
}
int _efTraitToText(FRrecognitionParameters* gParms, BYTE* parms, BYTE* trait, char** text) {
return FR_ERR_NOTIMPL;
}
void _efSortIdx(float* values, int* index, unsigned int nr) {
unsigned int i, j, maxIndex;
float max;
//init index
for (i=0; i < nr; i++)
index[i] = i;
//sort
for (i=0; i < nr; i++) {
max = values[index[i]];
maxIndex = i;
for (j=i+1; j < nr; j++) {
if (max < values[index[j]]) {
maxIndex = j;
max = values[index[j]];
}
}
if (maxIndex != i) {
j = index[i];
index[i] = index[maxIndex];
index[maxIndex] = j;
}
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -