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