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 74 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 { 93 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 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 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