OpenCV編寫Adaboost源程序

寫在前面:

本文僅爲記錄編程經驗和思路,所給程序並無識別作用(可能是由於特徵太少)。


程序主要實現功能:

時間緊迫...這個程序效果很差,只能算個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");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章