Home | History | Annotate | Download | only in src
      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