Merge pull request #55 from vpisarev/ocl_fixes
[profile/ivi/opencv.git] / apps / traincascade / HOGfeatures.cpp
1 #include "opencv2/core/core.hpp"
2 #include "opencv2/core/internal.hpp"
3
4 #include "HOGfeatures.h"
5 #include "cascadeclassifier.h"
6
7
8 CvHOGFeatureParams::CvHOGFeatureParams()
9 {
10     maxCatCount = 0;
11     name = HOGF_NAME;
12     featSize = N_BINS * N_CELLS;
13 }
14
15 void CvHOGEvaluator::init(const CvFeatureParams *_featureParams, int _maxSampleCount, Size _winSize)
16 {
17     CV_Assert( _maxSampleCount > 0);
18     int cols = (_winSize.width + 1) * (_winSize.height + 1);
19     for (int bin = 0; bin < N_BINS; bin++)
20     {
21         hist.push_back(Mat(_maxSampleCount, cols, CV_32FC1));
22     }
23     normSum.create( (int)_maxSampleCount, cols, CV_32FC1 );
24     CvFeatureEvaluator::init( _featureParams, _maxSampleCount, _winSize );
25 }
26
27 void CvHOGEvaluator::setImage(const Mat &img, uchar clsLabel, int idx)
28 {
29     CV_DbgAssert( !hist.empty());
30     CvFeatureEvaluator::setImage( img, clsLabel, idx );
31     vector<Mat> integralHist;
32     for (int bin = 0; bin < N_BINS; bin++)
33     {
34         integralHist.push_back( Mat(winSize.height + 1, winSize.width + 1, hist[bin].type(), hist[bin].ptr<float>((int)idx)) );
35     }
36     Mat integralNorm(winSize.height + 1, winSize.width + 1, normSum.type(), normSum.ptr<float>((int)idx));
37     integralHistogram(img, integralHist, integralNorm, (int)N_BINS);
38 }
39
40 //void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
41 //{
42 //    _writeFeatures( features, fs, featureMap );
43 //}
44
45 void CvHOGEvaluator::writeFeatures( FileStorage &fs, const Mat& featureMap ) const
46 {
47     int featIdx;
48     int componentIdx;
49     const Mat_<int>& featureMap_ = (const Mat_<int>&)featureMap;
50     fs << FEATURES << "[";
51     for ( int fi = 0; fi < featureMap.cols; fi++ )
52         if ( featureMap_(0, fi) >= 0 )
53         {
54             fs << "{";
55             featIdx = fi / getFeatureSize();
56             componentIdx = fi % getFeatureSize();
57             features[featIdx].write( fs, componentIdx );
58             fs << "}";
59         }
60     fs << "]";
61 }
62
63 void CvHOGEvaluator::generateFeatures()
64 {
65     int offset = winSize.width + 1;
66     Size blockStep;
67     int x, y, t, w, h;
68
69     for (t = 8; t <= winSize.width/2; t+=8) //t = size of a cell. blocksize = 4*cellSize
70     {
71         blockStep = Size(4,4);
72         w = 2*t; //width of a block
73         h = 2*t; //height of a block
74         for (x = 0; x <= winSize.width - w; x += blockStep.width)
75         {
76             for (y = 0; y <= winSize.height - h; y += blockStep.height)
77             {
78                 features.push_back(Feature(offset, x, y, t, t));
79             }
80         }
81         w = 2*t;
82         h = 4*t;
83         for (x = 0; x <= winSize.width - w; x += blockStep.width)
84         {
85             for (y = 0; y <= winSize.height - h; y += blockStep.height)
86             {
87                 features.push_back(Feature(offset, x, y, t, 2*t));
88             }
89         }
90         w = 4*t;
91         h = 2*t;
92         for (x = 0; x <= winSize.width - w; x += blockStep.width)
93         {
94             for (y = 0; y <= winSize.height - h; y += blockStep.height)
95             {
96                 features.push_back(Feature(offset, x, y, 2*t, t));
97             }
98         }
99     }
100
101     numFeatures = (int)features.size();
102 }
103
104 CvHOGEvaluator::Feature::Feature()
105 {
106     for (int i = 0; i < N_CELLS; i++)
107     {
108         rect[i] = Rect(0, 0, 0, 0);
109     }
110 }
111
112 CvHOGEvaluator::Feature::Feature( int offset, int x, int y, int cellW, int cellH )
113 {
114     rect[0] = Rect(x, y, cellW, cellH); //cell0
115     rect[1] = Rect(x+cellW, y, cellW, cellH); //cell1
116     rect[2] = Rect(x, y+cellH, cellW, cellH); //cell2
117     rect[3] = Rect(x+cellW, y+cellH, cellW, cellH); //cell3
118
119     for (int i = 0; i < N_CELLS; i++)
120     {
121         CV_SUM_OFFSETS(fastRect[i].p0, fastRect[i].p1, fastRect[i].p2, fastRect[i].p3, rect[i], offset);
122     }
123 }
124
125 void CvHOGEvaluator::Feature::write(FileStorage &fs) const
126 {
127     fs << CC_RECTS << "[";
128     for( int i = 0; i < N_CELLS; i++ )
129     {
130         fs << "[:" << rect[i].x << rect[i].y << rect[i].width << rect[i].height << "]";
131     }
132     fs << "]";
133 }
134
135 //cell and bin idx writing
136 //void CvHOGEvaluator::Feature::write(FileStorage &fs, int varIdx) const
137 //{
138 //    int featComponent = varIdx % (N_CELLS * N_BINS);
139 //    int cellIdx = featComponent / N_BINS;
140 //    int binIdx = featComponent % N_BINS;
141 //
142 //    fs << CC_RECTS << "[:" << rect[cellIdx].x << rect[cellIdx].y <<
143 //        rect[cellIdx].width << rect[cellIdx].height << binIdx << "]";
144 //}
145
146 //cell[0] and featComponent idx writing. By cell[0] it's possible to recover all block
147 //All block is nessesary for block normalization
148 void CvHOGEvaluator::Feature::write(FileStorage &fs, int featComponentIdx) const
149 {
150     fs << CC_RECT << "[:" << rect[0].x << rect[0].y <<
151         rect[0].width << rect[0].height << featComponentIdx << "]";
152 }
153
154
155 void CvHOGEvaluator::integralHistogram(const Mat &img, vector<Mat> &histogram, Mat &norm, int nbins) const
156 {
157     CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );
158     int x, y, binIdx;
159
160     Size gradSize(img.size());
161     Size histSize(histogram[0].size());
162     Mat grad(gradSize, CV_32F);
163     Mat qangle(gradSize, CV_8U);
164
165     AutoBuffer<int> mapbuf(gradSize.width + gradSize.height + 4);
166     int* xmap = (int*)mapbuf + 1;
167     int* ymap = xmap + gradSize.width + 2;
168
169     const int borderType = (int)BORDER_REPLICATE;
170
171     for( x = -1; x < gradSize.width + 1; x++ )
172         xmap[x] = borderInterpolate(x, gradSize.width, borderType);
173     for( y = -1; y < gradSize.height + 1; y++ )
174         ymap[y] = borderInterpolate(y, gradSize.height, borderType);
175
176     int width = gradSize.width;
177     AutoBuffer<float> _dbuf(width*4);
178     float* dbuf = _dbuf;
179     Mat Dx(1, width, CV_32F, dbuf);
180     Mat Dy(1, width, CV_32F, dbuf + width);
181     Mat Mag(1, width, CV_32F, dbuf + width*2);
182     Mat Angle(1, width, CV_32F, dbuf + width*3);
183
184     float angleScale = (float)(nbins/CV_PI);
185
186     for( y = 0; y < gradSize.height; y++ )
187     {
188         const uchar* currPtr = img.data + img.step*ymap[y];
189         const uchar* prevPtr = img.data + img.step*ymap[y-1];
190         const uchar* nextPtr = img.data + img.step*ymap[y+1];
191         float* gradPtr = (float*)grad.ptr(y);
192         uchar* qanglePtr = (uchar*)qangle.ptr(y);
193
194         for( x = 0; x < width; x++ )
195         {
196             dbuf[x] = (float)(currPtr[xmap[x+1]] - currPtr[xmap[x-1]]);
197             dbuf[width + x] = (float)(nextPtr[xmap[x]] - prevPtr[xmap[x]]);
198         }
199         cartToPolar( Dx, Dy, Mag, Angle, false );
200         for( x = 0; x < width; x++ )
201         {
202             float mag = dbuf[x+width*2];
203             float angle = dbuf[x+width*3];
204             angle = angle*angleScale - 0.5f;
205             int bidx = cvFloor(angle);
206             angle -= bidx;
207             if( bidx < 0 )
208                 bidx += nbins;
209             else if( bidx >= nbins )
210                 bidx -= nbins;
211
212             qanglePtr[x] = (uchar)bidx;
213             gradPtr[x] = mag;
214         }
215     }
216     integral(grad, norm, grad.depth());
217
218     float* histBuf;
219     const float* magBuf;
220     const uchar* binsBuf;
221
222     int binsStep = (int)( qangle.step / sizeof(uchar) );
223     int histStep = (int)( histogram[0].step / sizeof(float) );
224     int magStep = (int)( grad.step / sizeof(float) );
225     for( binIdx = 0; binIdx < nbins; binIdx++ )
226     {
227         histBuf = (float*)histogram[binIdx].data;
228         magBuf = (const float*)grad.data;
229         binsBuf = (const uchar*)qangle.data;
230
231         memset( histBuf, 0, histSize.width * sizeof(histBuf[0]) );
232         histBuf += histStep + 1;
233         for( y = 0; y < qangle.rows; y++ )
234         {
235             histBuf[-1] = 0.f;
236             float strSum = 0.f;
237             for( x = 0; x < qangle.cols; x++ )
238             {
239                 if( binsBuf[x] == binIdx )
240                     strSum += magBuf[x];
241                 histBuf[x] = histBuf[-histStep + x] + strSum;
242             }
243             histBuf += histStep;
244             binsBuf += binsStep;
245             magBuf += magStep;
246         }
247     }
248 }