写在前面:
本文仅为记录编程经验和思路,所给程序并无识别作用(可能是由于特征太少)。
程序主要实现功能:
时间紧迫...这个程序效果很差,只能算个demo。但是还是实现了一下几个主要功能,代码全部为自己编写。
1. 完成了adaboost框架。
2. logistic二值分类作为弱分类器,使用梯度下降法计算(10w次迭代)得到。
3. 计算了几个简单的特征。(灰度均值,颜色均值,灰度方差)。实践表明这些特征不足以描述人脸特征(如果程序没问题的话)。
编程遇到的问题:
logistic回归也是有weighted形式的,类似的只要:在中加入w参数就行了。具体推到过程中,将权重参数w加入到似然函数指数中即可。
freopen("CON","r",stdin)表示回到控制台输入。
贴上自己的代码:(写的不规范,请见谅)。其中输入数据:pos.txt中记录正样本及target位置(可用ObjectMarker标出), neg.txt中记录负样本。
#include <opencv2\opencv.hpp>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <ctime>
using namespace cv;
using std::memset;
using std::pow;
using std::fabs;
using std::log;
using std::exp;
const int MAX_SAMPLES = 1000;
const int MAX_DIMENSION = 200;
//number of features;
int dimension;
int nsamples, npositive, nnegative;
//features of image calculated by CALFEATURES function
double features[MAX_SAMPLES][MAX_DIMENSION];
int isPositive[MAX_SAMPLES];
double y[MAX_SAMPLES];
//struct for weakclassifier
const int MAX_CLASSIFIER = 200;
struct weakClassifier
{
//theta[0] = b;
double theta[MAX_DIMENSION];
//classifier vote weight;
double alpha;
double error;
void clear()
{
for(int i = 0 ; i < MAX_DIMENSION; i++)
theta[i] = 1;
alpha = 0;
error = 1;
}
double cal(double x[MAX_DIMENSION])
{
double ans = 0 ;
for(int i = 0 ; i < dimension; i++)
ans += theta[i]*x[i];
return 1/(1 + exp(-ans));
}
}weakclassifier[MAX_CLASSIFIER];
//parameter for adaboost
int nweakclassifier = 100;
double weight[MAX_SAMPLES];
int calbystrongclassifier(double x[MAX_DIMENSION])
{
int ans = 0;
for(int i = 0 ; i < nweakclassifier; i++)
{
double temp = weakclassifier[i].cal(x);
if(temp > 0.5)
ans += weakclassifier[i].alpha * 1;
else
ans += weakclassifier[i].alpha * -1;
}
if(ans > 0)
return 1;
else
return -1;
}
//cal the feature of the image
int calfeatures(IplImage *inputImage, double features[MAX_DIMENSION])
{
int nfeatures = 0;
int width = inputImage->width;
int height = inputImage->height;
double thisfeature;
double ave;
//create gray image
IplImage* gray = cvCreateImage(cvGetSize(inputImage),inputImage->depth,1);
cvCvtColor(inputImage, gray, CV_BGR2GRAY);
//cal hist
double hist[256];
memset(hist, 0, sizeof(hist));
for(int i = 0 ; i < gray->height; i++)
{
for(int j = 0 ; j < gray->width; j++)
{
//here it must be strongly converted to type-unsigned char
int value = unsigned char(gray->imageData[i*gray->widthStep+j]);
hist[value] += 1.0/gray->width/gray->height;
}
}
//init features[0] = 1;
features[nfeatures++] = 1;
//cal 1st feature: average grey
thisfeature = 0;
for(int i = 0 ; i < 256; i++)
thisfeature += i*hist[i];
features[nfeatures] = thisfeature;
ave = thisfeature;
nfeatures++;
//cal 2st feature: average green
thisfeature = 0;
int sumgreen = 0;
for(int i = 0 ; i < height; i++)
{
uchar* ptr = (uchar*)(inputImage->imageData + i * inputImage->widthStep);
for(int j = 0 ; j < width; j++)
{
int value = ptr[3*j];
sumgreen += value;
}
}
features[nfeatures] = sumgreen*1.0/width/height;
ave = thisfeature;
nfeatures++;
//cal 3st feature: average red
thisfeature = 0;
int sumred = 0;
for(int i = 0 ; i < height; i++)
{
uchar* ptr = (uchar*)(inputImage->imageData + i * inputImage->widthStep);
for(int j = 0 ; j < width; j++)
{
int value = ptr[3*j+2];
sumred += value;
}
}
features[nfeatures] = sumred*1.0/width/height;
ave = thisfeature;
nfeatures++;
//cal 4st feature: average blue
thisfeature = 0;
int sumblue = 0;
for(int i = 0 ; i < height; i++)
{
uchar* ptr = (uchar*)(inputImage->imageData + i * inputImage->widthStep);
for(int j = 0 ; j < width; j++)
{
int value = ptr[3*j+1];
sumblue += value;
}
}
features[nfeatures] = sumblue*1.0/width/height;
ave = thisfeature;
nfeatures++;
//cal 5nd feature: grey variance
thisfeature = 0;
for(int i = 0 ; i < 256; i++)
thisfeature += hist[i]*(i-features[0])*(i-features[0]);
features[nfeatures] = sqrt(thisfeature*1.0);
nfeatures++;
cvReleaseImage(&gray);
return nfeatures;
}
//train weak classifier using logisitic regression
weakClassifier trainweakclassifier()
{
weakClassifier ans;
ans.clear();
//cal parameter thetas
for(int k = 0 ; k < 100000; k++)
{
int i = rand()%nsamples;
int j = rand()%(dimension);
ans.theta[j] = ans.theta[j] + weight[i]*0.01*(isPositive[i] - ans.cal(features[i]))*features[i][j];
}
//cal error
int rightnum = 0;
for(int i = 0 ; i < nsamples; i++)
{
double tmp = ans.cal(features[i]);
if(tmp > 0.5 && isPositive[i] || tmp < 0.5 && isPositive[i] == false)
rightnum ++;
}
ans.error = (nsamples - rightnum)*1.0/nsamples;
//cal alpha
ans.alpha = 1.0/2*std::log((1-ans.error)/ans.error);
return ans;
}
int main()
{
srand(int(time(0)));
char filename[100];
IplImage *inputImage = NULL;
nsamples = npositive = nnegative = 0;
//read the positive samples to cal the features
freopen("pos.txt","r",stdin);
while(scanf("%s",filename)!=EOF)
{
int num_1,x1,y1,width1, height1;
scanf("%d%d%d%d%d",&num_1,&x1, &y1, &width1, &height1);
CvRect roi = cvRect(x1, y1, width1, height1);
inputImage = cvLoadImage(filename);
cvSetImageROI(inputImage, roi);
IplImage* temp = cvCreateImage(cvSize(width1, height1), inputImage->depth, inputImage->nChannels);
cvCopy(inputImage, temp);
//cvShowImage("a",temp);
//cvWaitKey(0);
cvReleaseImage(&inputImage);
inputImage = NULL;
dimension = calfeatures(temp,features[nsamples]);
cvReleaseImage(&temp);
isPositive[nsamples] = 1;
y[nsamples] = 1;
nsamples++;
npositive++;
}
//output the features;
freopen("CON","w",stdout);
for(int i = 0 ; i < nsamples; i++)
{
for(int j = 0 ; j < dimension; j++)
printf("%lf ", features[i][j]);
printf("\n ");
}
//read the negative samples to cal the features
freopen("neg.txt","r",stdin);
while(scanf("%s",filename)!=EOF)
{
inputImage = cvLoadImage(filename);
dimension = calfeatures(inputImage, features[nsamples]);
//cvShowImage("a",inputImage);
//cvWaitKey(0);
cvReleaseImage(&inputImage);
isPositive[nsamples] = 0;
y[nsamples] = -1;
nsamples++;
nnegative++;
}
//output the features;
freopen("CON","w",stdout);
for(int i = npositive ; i < nsamples; i++)
{
for(int j = 0 ; j < dimension; j++)
printf("%lf ", features[i][j]);
printf("\n");
}
//adaboost framework
for(int i = 0 ; i < nsamples; i++)
{
weight[i] = 1.0/nsamples;
}
for(int classifierindex = 0 ; classifierindex < nweakclassifier; classifierindex++)
{
weakclassifier[classifierindex] = trainweakclassifier();
double error = weakclassifier[classifierindex].error;
double alpha = weakclassifier[classifierindex].alpha;
if(error > 0.5 || alpha < 0)
printf("Error: wrong classifier has been generated. %lf\n", error);
printf("%d classifier: %lf\n",classifierindex, error);
for(int i = 0 ; i < dimension; i++)
printf("%lf ",weakclassifier[classifierindex].theta[i]);
printf("\n");
double identitysum = 0;
for(int sampleindex = 0 ; sampleindex < nsamples; sampleindex++)
{
if(weakclassifier[classifierindex].cal(features[sampleindex]) > 0.5)
weight[sampleindex] *= exp(-alpha*y[sampleindex]*1);
else
weight[sampleindex] *= exp(-alpha*y[sampleindex]*-1);
identitysum += weight[sampleindex];
}
//reweight
for(int sampleindex = 0 ; sampleindex < nsamples; sampleindex++)
{
weight[sampleindex] /= identitysum;
}
}
double rightsum = 0;
for(int i = 0 ; i < npositive; i++)
{
if(calbystrongclassifier(features[i]) == 1 && isPositive[i] == 1)
rightsum += 1;
if(calbystrongclassifier(features[i]) == -1 && isPositive[i] == 0)
rightsum += 1;
}
printf("测试集的准确率为:%lf\n", rightsum/nsamples);
//test
freopen("CON","r",stdin);
printf("please input the directory of test image\n");
scanf("%s",filename);
cvReleaseImage(&inputImage);
inputImage = cvLoadImage(filename);
cvShowImage("a",inputImage);
//cvWaitKey(0);
int width = inputImage->width;
int height = inputImage->height;
int ansx = 0, ansy = 0, answ = 0, ansh = 0;
//cvShowImage("a",temp);
//cvWaitKey(0);
for(int x1 = 0 ; x1 < width; x1 += 10)
{
for(int y1 = 0; y1 < height; y1 += 10)
{
for(int width1 = 100; x1 + width1 < width; width1 += 10)
{
for(int height1 = 123; y1 + height1 < height; height1 += 10)
{
IplImage* temp = cvCreateImage(cvSize(width1,height1),inputImage->depth, inputImage->nChannels);
CvRect roi = cvRect(x1, y1, width1, height1);
cvSetImageROI(inputImage, roi);
cvCopy(inputImage,temp);
cvResetImageROI(inputImage);
double tempfeatures[MAX_DIMENSION];
//cvShowImage("a",temp);
//cvWaitKey(0);
calfeatures(temp,tempfeatures);
if(calbystrongclassifier( tempfeatures ) == 1)
{
ansx = x1;
ansy = y1;
answ = width1;
ansh = height1;
cvShowImage("检测结果",temp);
cvWaitKey(0);
}
cvReleaseImage(&temp);
}
}
}
}
if(answ && ansh)
{
IplImage* ans = cvCreateImage(cvSize(answ,ansh),inputImage->depth, inputImage->nChannels);
cvSetImageROI(inputImage,cvRect(ansx,ansy,answ,ansh));
cvCopy(inputImage, ans);
cvShowImage("检测结果",ans);
cvWaitKey(0);
}
else
{
printf("Can not detect.\n");
}
}