1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
8 //
9 //
10 // License Agreement
11 // For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, Itseez Inc, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
21 //
22 // * Redistribution's in binary form must reproduce the above copyright notice,
23 // this list of conditions and the following disclaimer in the documentation
24 // and/or other materials provided with the distribution.
25 //
26 // * The name of Intel Corporation may not be used to endorse or promote products
27 // derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 /* Haar features calculation */
43
44 #include "precomp.hpp"
45 #include <stdio.h>
46
47 namespace cv
48 {
49
50 /* field names */
51
52 #define ICV_HAAR_SIZE_NAME "size"
53 #define ICV_HAAR_STAGES_NAME "stages"
54 #define ICV_HAAR_TREES_NAME "trees"
55 #define ICV_HAAR_FEATURE_NAME "feature"
56 #define ICV_HAAR_RECTS_NAME "rects"
57 #define ICV_HAAR_TILTED_NAME "tilted"
58 #define ICV_HAAR_THRESHOLD_NAME "threshold"
59 #define ICV_HAAR_LEFT_NODE_NAME "left_node"
60 #define ICV_HAAR_LEFT_VAL_NAME "left_val"
61 #define ICV_HAAR_RIGHT_NODE_NAME "right_node"
62 #define ICV_HAAR_RIGHT_VAL_NAME "right_val"
63 #define ICV_HAAR_STAGE_THRESHOLD_NAME "stage_threshold"
64 #define ICV_HAAR_PARENT_NAME "parent"
65 #define ICV_HAAR_NEXT_NAME "next"
66
67 namespace haar_cvt
68 {
69
70 struct HaarFeature
71 {
72 enum { RECT_NUM = 3 };
73
HaarFeaturecv::haar_cvt::HaarFeature74 HaarFeature()
75 {
76 tilted = false;
77 for( int i = 0; i < RECT_NUM; i++ )
78 {
79 rect[i].r = Rect(0,0,0,0);
80 rect[i].weight = 0.f;
81 }
82 }
83 bool tilted;
84 struct
85 {
86 Rect r;
87 float weight;
88 } rect[RECT_NUM];
89 };
90
91 struct HaarClassifierNode
92 {
HaarClassifierNodecv::haar_cvt::HaarClassifierNode93 HaarClassifierNode()
94 {
95 f = left = right = 0;
96 threshold = 0.f;
97 }
98 int f, left, right;
99 float threshold;
100 };
101
102 struct HaarClassifier
103 {
104 std::vector<HaarClassifierNode> nodes;
105 std::vector<float> leaves;
106 };
107
108 struct HaarStageClassifier
109 {
110 double threshold;
111 std::vector<HaarClassifier> weaks;
112 };
113
convert(const String & oldcascade,const String & newcascade)114 static bool convert(const String& oldcascade, const String& newcascade)
115 {
116 FileStorage oldfs(oldcascade, FileStorage::READ);
117 if( !oldfs.isOpened() )
118 return false;
119 FileNode oldroot = oldfs.getFirstTopLevelNode();
120
121 FileNode sznode = oldroot[ICV_HAAR_SIZE_NAME];
122 if( sznode.empty() )
123 return false;
124 Size cascadesize;
125 cascadesize.width = (int)sznode[0];
126 cascadesize.height = (int)sznode[1];
127 std::vector<HaarFeature> features;
128
129 int i, j, k, n;
130
131 FileNode stages_seq = oldroot[ICV_HAAR_STAGES_NAME];
132 int nstages = (int)stages_seq.size();
133 std::vector<HaarStageClassifier> stages(nstages);
134
135 for( i = 0; i < nstages; i++ )
136 {
137 FileNode stagenode = stages_seq[i];
138 HaarStageClassifier& stage = stages[i];
139 stage.threshold = (double)stagenode[ICV_HAAR_STAGE_THRESHOLD_NAME];
140 FileNode weaks_seq = stagenode[ICV_HAAR_TREES_NAME];
141 int nweaks = (int)weaks_seq.size();
142 stage.weaks.resize(nweaks);
143
144 for( j = 0; j < nweaks; j++ )
145 {
146 HaarClassifier& weak = stage.weaks[j];
147 FileNode weaknode = weaks_seq[j];
148 int nnodes = (int)weaknode.size();
149
150 for( n = 0; n < nnodes; n++ )
151 {
152 FileNode nnode = weaknode[n];
153 FileNode fnode = nnode[ICV_HAAR_FEATURE_NAME];
154 HaarFeature f;
155 HaarClassifierNode node;
156 node.f = (int)features.size();
157 f.tilted = (int)fnode[ICV_HAAR_TILTED_NAME] != 0;
158 FileNode rects_seq = fnode[ICV_HAAR_RECTS_NAME];
159 int nrects = (int)rects_seq.size();
160
161 for( k = 0; k < nrects; k++ )
162 {
163 FileNode rnode = rects_seq[k];
164 f.rect[k].r.x = (int)rnode[0];
165 f.rect[k].r.y = (int)rnode[1];
166 f.rect[k].r.width = (int)rnode[2];
167 f.rect[k].r.height = (int)rnode[3];
168 f.rect[k].weight = (float)rnode[4];
169 }
170 features.push_back(f);
171 node.threshold = nnode[ICV_HAAR_THRESHOLD_NAME];
172 FileNode leftValNode = nnode[ICV_HAAR_LEFT_VAL_NAME];
173 if( !leftValNode.empty() )
174 {
175 node.left = -(int)weak.leaves.size();
176 weak.leaves.push_back((float)leftValNode);
177 }
178 else
179 {
180 node.left = (int)nnode[ICV_HAAR_LEFT_NODE_NAME];
181 }
182 FileNode rightValNode = nnode[ICV_HAAR_RIGHT_VAL_NAME];
183 if( !rightValNode.empty() )
184 {
185 node.right = -(int)weak.leaves.size();
186 weak.leaves.push_back((float)rightValNode);
187 }
188 else
189 {
190 node.right = (int)nnode[ICV_HAAR_RIGHT_NODE_NAME];
191 }
192 weak.nodes.push_back(node);
193 }
194 }
195 }
196
197 FileStorage newfs(newcascade, FileStorage::WRITE);
198 if( !newfs.isOpened() )
199 return false;
200
201 int maxWeakCount = 0, nfeatures = (int)features.size();
202 for( i = 0; i < nstages; i++ )
203 maxWeakCount = std::max(maxWeakCount, (int)stages[i].weaks.size());
204
205 newfs << "cascade" << "{:opencv-cascade-classifier"
206 << "stageType" << "BOOST"
207 << "featureType" << "HAAR"
208 << "height" << cascadesize.width
209 << "width" << cascadesize.height
210 << "stageParams" << "{"
211 << "maxWeakCount" << (int)maxWeakCount
212 << "}"
213 << "featureParams" << "{"
214 << "maxCatCount" << 0
215 << "}"
216 << "stageNum" << (int)nstages
217 << "stages" << "[";
218
219 for( i = 0; i < nstages; i++ )
220 {
221 int nweaks = (int)stages[i].weaks.size();
222 newfs << "{" << "maxWeakCount" << (int)nweaks
223 << "stageThreshold" << stages[i].threshold
224 << "weakClassifiers" << "[";
225 for( j = 0; j < nweaks; j++ )
226 {
227 const HaarClassifier& c = stages[i].weaks[j];
228 newfs << "{" << "internalNodes" << "[";
229 int nnodes = (int)c.nodes.size(), nleaves = (int)c.leaves.size();
230 for( k = 0; k < nnodes; k++ )
231 newfs << c.nodes[k].left << c.nodes[k].right
232 << c.nodes[k].f << c.nodes[k].threshold;
233 newfs << "]" << "leafValues" << "[";
234 for( k = 0; k < nleaves; k++ )
235 newfs << c.leaves[k];
236 newfs << "]" << "}";
237 }
238 newfs << "]" << "}";
239 }
240
241 newfs << "]"
242 << "features" << "[";
243
244 for( i = 0; i < nfeatures; i++ )
245 {
246 const HaarFeature& f = features[i];
247 newfs << "{" << "rects" << "[";
248 for( j = 0; j < HaarFeature::RECT_NUM; j++ )
249 {
250 if( j >= 2 && fabs(f.rect[j].weight) < FLT_EPSILON )
251 break;
252 newfs << "[" << f.rect[j].r.x << f.rect[j].r.y <<
253 f.rect[j].r.width << f.rect[j].r.height << f.rect[j].weight << "]";
254 }
255 newfs << "]";
256 if( f.tilted )
257 newfs << "tilted" << 1;
258 newfs << "}";
259 }
260
261 newfs << "]" << "}";
262 return true;
263 }
264
265 }
266
convert(const String & oldcascade,const String & newcascade)267 bool CascadeClassifier::convert(const String& oldcascade, const String& newcascade)
268 {
269 bool ok = haar_cvt::convert(oldcascade, newcascade);
270 if( !ok && newcascade.size() > 0 )
271 remove(newcascade.c_str());
272 return ok;
273 }
274
275 }
276