struct TWeakClassifier
{
CvRect Rectangles[2];
};
struct PtrWeakClassifier
{
long *tl0, *tr0, *bl0, *br0;
long *tl1, *tr1, *bl1, *br1;
int offset, size0, size1;
int Threshold;
};
struct ListObjectType
{
int x, y, width, height;
int w;
bool use;
ListObjectType *next;
};
struct TLearnedObject
{
TWeakClassifier *Classifiers;
PtrWeakClassifier *ScaleClassifiers;
int ObjectWidth, ObjectHeight;
int NClassifiers;
};
struct TDetectSettings
{
double ScaleRatio, OffsetX, OffsetY;
int Ignore, MinW;
int StartSubWindow, EndSubWindow;
};
bool LoadDefaultSetting(char *FileName, TDetectSettings &DS);
void LearnClassifiers(unsigned char *IptImage, TLearnedObject &target, int IptWidth, int IptHeight);
int DetectObject(TLearnedObject &target, unsigned char *FrameImage, int Width, int Height, TDetectSettings &DS, CvRect *&Objects);
cvdirectcascade.cpp:
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "cv.h"
#include "cvdirectcascade.h"
bool Overlapped(ListObjectType *obj1, ListObjectType *obj2)
{
int cx = obj1->x + obj1->width / 2;
int cy = obj1->y + obj1->height / 2;
if ((cx > obj2->x) && (cx < obj2->x + obj2->width) && (cy > obj2->y) && (cy < obj2->y + obj2->height))
return true;
cx = obj2->x + obj2->width / 2;
cy = obj2->y + obj2->height / 2;
if ((cx > obj1->x) && (cx < obj1->x + obj1->width) && (cy > obj1->y) && (cy < obj1->y + obj1->height))
return true;
return false;
}
void RestoreImage(unsigned char *IptImage, long *&IntegralImage, int IptWidth, int IptHeight)
{
IntegralImage = new long [(IptWidth + 1) * (IptHeight + 1)];
long *pic = IntegralImage;
for (int i = 0; i < IptWidth + 1; i++)
{
*pic = 0; pic++;
}
for (int j = 0; j < IptHeight; j++)
{
*pic = 0; pic+=IptWidth + 1;
}
unsigned char *pc = IptImage;
long *picx, *picy, *picxy;
picxy = IntegralImage;
pic = picxy + IptWidth + 2;
picx = picxy + IptWidth + 1;
picy = picxy + 1;
for (i = 0; i < IptHeight; i++)
{
for (j = 0; j < IptWidth; j++)
{
*pic = *pc + *picx + *picy - *picxy;
pic++; picx++; picy++; picxy++;
pc++;
}
pic++; picx++; picy++; picxy++;
}
}
int CalculateXBoundary(unsigned char *IptImage, int IptWidth, int IptHeight, int x, int y, int width, int height)
{
int T, NewT = width / 2, C1 = 0, C2 = 0, D1 = 0, D2 = 0;
unsigned char *ptr, *oldptr;
oldptr = IptImage + IptWidth * y + x;
int step = IptWidth - width;
do{
T = NewT;
C1 = 0; C2 = 0; D1 = 0; D2 = 0;
ptr = oldptr;
for (int j = y; j < y + height; j++)
{
for (int i = x; i < x + T; i++)
{
C1 += (i - x) * *ptr;
D1 += *ptr;
ptr++;
}
for (i = x + T; i < x + width; i++)
{
C2 += (i - x) * *ptr;
D2 += *ptr;
ptr++;
}
ptr+=step;
}
C1 = C1 / D1; C2 = C2 / D2;
NewT = (C1 + C2) / 2;
}while (NewT != T);
return T;
}
int CalculateYBoundary(unsigned char *IptImage, int IptWidth, int IptHeight, int x, int y, int width, int height)
{
int T, NewT = height / 2, C1 = 0, C2 = 0, D1 = 0, D2 = 0;
unsigned char *ptr, *oldptr;
oldptr = IptImage + IptWidth * y + x;
int step = IptWidth - width;
do{
T = NewT;
C1 = 0; C2 = 0; D1 = 0; D2 = 0;
ptr = oldptr;
for (int j = y; j < y + T; j++)
{
for (int i = x; i < x + width; i++)
{
C1 += (j - y) * *ptr;
D1 += *ptr;
ptr++;
}
ptr+=step;
}
for (j = y + T; j < y + height; j++)
{
for (int i = x; i < x + width; i++)
{
C2 += (j - y) * *ptr;
D2 += *ptr;
ptr++;
}
ptr+=step;
}
C1 = C1 / D1; C2 = C2 / D2;
NewT = (C1 + C2) / 2;
}while (NewT != T);
return T;
}
void LearnClassifiers(unsigned char *IptImage, TLearnedObject &target, int IptWidth, int IptHeight)
{
long *IntegralImage = NULL;
target.ObjectWidth = IptWidth; target.ObjectHeight = IptHeight;
RestoreImage(IptImage, IntegralImage, IptWidth, IptHeight);
CvRect *close, *open, *record;
record = new CvRect [target.NClassifiers * 2];
TWeakClassifier *cptr;
cptr = target.Classifiers; int NowClassifiers = 0;
close = record; open = record;
record->x = 0; record->y = 0;
record->width = IptWidth; record->height = IptHeight;
do{
int T;
if (close->width > 1)
{
T = CalculateXBoundary(IptImage, IptWidth, IptHeight, close->x, close->y, close->width, close->height);
if ((T > 0) && (T < close->width))
{
cptr->Rectangles[0].x = close->x;
cptr->Rectangles[0].y = close->y;
cptr->Rectangles[0].width = T;
cptr->Rectangles[0].height = close->height;
cptr->Rectangles[1].x = close->x + T;
cptr->Rectangles[1].y = close->y;
cptr->Rectangles[1].width = close->width - T;
cptr->Rectangles[1].height = close->height;
NowClassifiers++; cptr++;
if (NowClassifiers >= target.NClassifiers) break;
open++;
open->x = close->x; open->y = close->y;
open->width = T; open->height = close->height;
open++;
open->x = close->x + T; open->y = close->y;
open->width = close->width - T; open->height = close->height;
}
}
if (close->height > 1)
{
T = CalculateYBoundary(IptImage, IptWidth, IptHeight, close->x, close->y, close->width, close->height);
if ((T > 0) && (T < close->height))
{
cptr->Rectangles[0].x = close->x;
cptr->Rectangles[0].y = close->y;
cptr->Rectangles[0].width = close->width;
cptr->Rectangles[0].height = T;
cptr->Rectangles[1].x = close->x;
cptr->Rectangles[1].y = close->y + T;
cptr->Rectangles[1].width = close->width;
cptr->Rectangles[1].height = close->height - T;
NowClassifiers++; cptr++;
if (NowClassifiers >= target.NClassifiers) break;
open++;
open->x = close->x; open->y = close->y;
open->width = close->width; open->height = T;
open++;
open->x = close->x; open->y = close->y + T;
open->width = close->width; open->height = close->height - T;
}
}
close++;
}while (close <= open);
delete [] record;
cptr = target.Classifiers;
PtrWeakClassifier *scptr;
scptr = target.ScaleClassifiers;
for (int i = 0; i < target.NClassifiers; i++)
{
scptr->tl0 = IntegralImage + cptr->Rectangles[0].y * (IptWidth + 1) + cptr->Rectangles[0].x;
scptr->tr0 = scptr->tl0 + cptr->Rectangles[0].width;
scptr->bl0 = IntegralImage + (cptr->Rectangles[0].y + cptr->Rectangles[0].height) * (IptWidth + 1) + cptr->Rectangles[0].x;
scptr->br0 = scptr->bl0 + cptr->Rectangles[0].width;
scptr->size0 =cptr->Rectangles[0].width * cptr->Rectangles[0].height;
scptr->tl1 = IntegralImage + cptr->Rectangles[1].y * (IptWidth + 1) + cptr->Rectangles[1].x;
scptr->tr1 = scptr->tl1 + cptr->Rectangles[1].width;
scptr->bl1 = IntegralImage + (cptr->Rectangles[1].y + cptr->Rectangles[1].height) * (IptWidth + 1) + cptr->Rectangles[1].x;
scptr->br1 = scptr->bl1 + cptr->Rectangles[1].width;
scptr->size1 =cptr->Rectangles[1].width * cptr->Rectangles[1].height;
int gray = (*(scptr->br0) - *(scptr->bl0) - *(scptr->tr0) + *(scptr->tl0)) / scptr->size0;
gray -= (*(scptr->br1) - *(scptr->bl1) - *(scptr->tr1) + *(scptr->tl1)) / scptr->size1;
scptr->Threshold = gray;
scptr++; cptr++;
}
delete [] IntegralImage;
}
int DetectObject(TLearnedObject &target, unsigned char *FrameImage, int Width, int Height, TDetectSettings &DS, CvRect *&Objects)
{
long *IntegralImage = NULL;
RestoreImage(FrameImage, IntegralImage, Width, Height);
bool smallenough = false;
int ObjectWindow;
if (target.ObjectWidth > target.ObjectHeight) ObjectWindow = target.ObjectWidth; else ObjectWindow = target.ObjectHeight;
double scale = (double)DS.StartSubWindow / (double)ObjectWindow;
double scale_ = 1 / scale, newscalex = scale * DS.OffsetX, newscaley = scale * DS.OffsetY;
int NewWidth = (int)(Width * scale_), NewHeight = (int)(Height * scale_);
int NOWidth = (int)(target.ObjectWidth * scale), NOHeight = (int)(target.ObjectHeight * scale);
int EndWidth, EndHeight;
//size definement
ListObjectType *ListObjects;
ListObjects = new ListObjectType;
ListObjectType *objptr, *oldptr;
objptr = ListObjects;
int ListCount = 0, Count = 0;
//object list
TWeakClassifier *cptr = NULL, *ocptr = target.Classifiers;
PtrWeakClassifier *scptr = NULL, *oscptr = target.ScaleClassifiers;
int Nc = target.NClassifiers;
int Ignore = DS.Ignore, MinW = DS.MinW;
//scaling && detecting
do{
int x, y, swidth, sheight;
cptr = ocptr; scptr = oscptr;
for (int i = 0; i < Nc; i++)
{
x = (int)(cptr->Rectangles[0].x * scale);
y = (int)(cptr->Rectangles[0].y * scale);
swidth = (int)(cptr->Rectangles[0].width * scale);
sheight = (int)(cptr->Rectangles[0].height * scale);
scptr->tl0 = IntegralImage + x + y * (Width + 1);
scptr->tr0 = scptr->tl0 + swidth;
scptr->bl0 = IntegralImage + x + (y + sheight) * (Width + 1);
scptr->br0 = scptr->bl0 + swidth;
scptr->size0 = sheight * swidth;
x = (int)(cptr->Rectangles[1].x * scale);
y = (int)(cptr->Rectangles[1].y * scale);
swidth = (int)(cptr->Rectangles[1].width * scale);
sheight = (int)(cptr->Rectangles[1].height * scale);
scptr->tl1 = IntegralImage + x + y * (Width + 1);
scptr->tr1 = scptr->tl1 + swidth;
scptr->bl1 = IntegralImage + x + (y + sheight) * (Width + 1);
scptr->br1 = scptr->bl1 + swidth;
scptr->size1 = sheight * swidth;
scptr->offset = 0;
scptr++; cptr++;
}
int oldy = 0, diffx = 0, diffy = 0;
double InvWindowArea = 1 / (double)(NOWidth * NOHeight);
if (scale < 1)
{
EndWidth = (int)((Width - NOWidth) / DS.OffsetX);
EndHeight = (int)((Height - NOHeight) / DS.OffsetY);
newscalex = DS.OffsetX; newscaley = DS.OffsetY;
}
else
{
EndWidth = (int)((NewWidth - target.ObjectWidth) / DS.OffsetX);
EndHeight = (int)((NewHeight - target.ObjectHeight) / DS.OffsetY);
newscalex = scale * DS.OffsetX; newscaley = scale * DS.OffsetY;
}
for (i = 0; i < EndHeight; i++)
{
y = (int)(i * newscaley);
diffy = (y - oldy - 1) * (Width + 1); oldy = y;
if (diffy > 0)
{
scptr = oscptr;
for (int k = 0; k < Nc; k++)
{
scptr->tl0+=diffy; scptr->tr0+=diffy;
scptr->bl0+=diffy; scptr->br0+=diffy;
scptr->tl1+=diffy; scptr->tr1+=diffy;
scptr->bl1+=diffy; scptr->br1+=diffy;
scptr++;
}
}
for (int j = 0; j < EndWidth; j++)
{
x = (int)(j * newscalex);
bool Identify = true;
int w = 0;
scptr = oscptr;
for (int k = 0; k < Nc; k++)
{
diffx = x - scptr->offset; scptr->offset = x;
scptr->tl0+=diffx; scptr->tr0+=diffx;
scptr->bl0+=diffx; scptr->br0+=diffx;
scptr->tl1+=diffx; scptr->tr1+=diffx;
scptr->bl1+=diffx; scptr->br1+=diffx;
int gray = (*(scptr->br0) - *(scptr->bl0) - *(scptr->tr0) + *(scptr->tl0)) / scptr->size0;
gray -= (*(scptr->br1) - *(scptr->bl1) - *(scptr->tr1) + *(scptr->tl1)) / scptr->size1;
if ((gray < scptr->Threshold - Ignore) || (gray > scptr->Threshold + Ignore))
{
Identify = false;
break;
}
else
w += abs(scptr->Threshold - gray);
scptr++;
}
if (w > MinW) Identify = false;
if (Identify)
{
objptr->next = new ListObjectType;
objptr = objptr->next;
objptr->x = x; objptr->y = y;
objptr->width = NOWidth; objptr->height = NOHeight;
objptr->w = w; objptr->use = true;
ListCount++;
}
}
x = Width + 1;
scptr = oscptr;
for (int k = 0; k < Nc; k++)
{
diffx = x - scptr->offset; scptr->offset = 0;
scptr->tl0+=diffx; scptr->tr0+=diffx;
scptr->bl0+=diffx; scptr->br0+=diffx;
scptr->tl1+=diffx; scptr->tr1+=diffx;
scptr->bl1+=diffx; scptr->br1+=diffx;
scptr++;
}
}
scale *= DS.ScaleRatio;
scale_ = 1 / scale;
NewWidth = (int)(Width * scale_); NewHeight = (int)(Height * scale_);
NOWidth = (int)(target.ObjectWidth * scale); NOHeight = (int)(target.ObjectHeight * scale);
if ((NOWidth > DS.EndSubWindow) || (NOHeight > DS.EndSubWindow) || (NewWidth < target.ObjectWidth) || (NewHeight < target.ObjectHeight))
smallenough = true;
else
smallenough = false;
}while (!smallenough);
//merging
ListObjectType *objptr2;
objptr = ListObjects->next;
for (int i = 0; i < ListCount; i++)
{
if (objptr->use)
{
objptr2 = objptr->next;
for (int j = i + 1; j < ListCount; j++)
{
if (objptr2->use)
if (Overlapped(objptr, objptr2))
{
if (objptr2->w < objptr->w)
objptr->use = false;
else
objptr2->use = false;
}
objptr2 = objptr2->next;
}
}
objptr = objptr->next;
}
objptr = ListObjects->next; Count = 0;
for (i = 0; i < ListCount; i++)
{
if (objptr->use)
Count++;
objptr = objptr->next;
}
Objects = new CvRect [Count];
CvRect *recptr;
objptr = ListObjects->next;
recptr = Objects;
for (i = 0; i < ListCount; i++)
{
if (objptr->use)
{
recptr->x = objptr->x; recptr->y = objptr->y;
recptr->width = objptr->width; recptr->height = objptr->height;
recptr++;
}
objptr = objptr->next;
}
oldptr = ListObjects; objptr = ListObjects->next;
for (i = 0; i < ListCount; i++)
{
delete oldptr; oldptr = objptr;
objptr = objptr->next;
}
delete oldptr;
delete [] IntegralImage;
return Count;
}
bool LoadDefaultSetting(char *FileName, TDetectSettings &DS)
{
FILE *dsf = fopen(FileName, "r");
if (NULL != dsf)
{
fscanf(dsf, "%g", &DS.ScaleRatio);
fscanf(dsf, "%g %g", &DS.OffsetX, &DS.OffsetY);
fscanf(dsf, "%d %d", &DS.Ignore, &DS.MinW);
fscanf(dsf, "%d %d", &DS.StartSubWindow, &DS.EndSubWindow);
fclose(dsf);
return true;
}
else
return false;
}