X-Git-Url: http://git.maemo.org/git/?p=opencv;a=blobdiff_plain;f=apps%2Fhaartraining%2Fcvhaarclassifier.cpp;fp=apps%2Fhaartraining%2Fcvhaarclassifier.cpp;h=004508b43a552ad6c002b02a1db4f2fea2a15e2a;hp=0000000000000000000000000000000000000000;hb=e4c14cdbdf2fe805e79cd96ded236f57e7b89060;hpb=454138ff8a20f6edb9b65a910101403d8b520643 diff --git a/apps/haartraining/cvhaarclassifier.cpp b/apps/haartraining/cvhaarclassifier.cpp new file mode 100644 index 0000000..004508b --- /dev/null +++ b/apps/haartraining/cvhaarclassifier.cpp @@ -0,0 +1,826 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +/* + * cvhaarclassifier.cpp + * + * haar classifiers (stump, CART, stage, cascade) + */ + +#include "_cvhaartraining.h" + + +CvIntHaarClassifier* icvCreateCARTHaarClassifier( int count ) +{ + CvCARTHaarClassifier* cart; + size_t datasize; + + datasize = sizeof( *cart ) + + ( sizeof( int ) + + sizeof( CvTHaarFeature ) + sizeof( CvFastHaarFeature ) + + sizeof( float ) + sizeof( int ) + sizeof( int ) ) * count + + sizeof( float ) * (count + 1); + + cart = (CvCARTHaarClassifier*) cvAlloc( datasize ); + memset( cart, 0, datasize ); + + cart->feature = (CvTHaarFeature*) (cart + 1); + cart->fastfeature = (CvFastHaarFeature*) (cart->feature + count); + cart->threshold = (float*) (cart->fastfeature + count); + cart->left = (int*) (cart->threshold + count); + cart->right = (int*) (cart->left + count); + cart->val = (float*) (cart->right + count); + cart->compidx = (int*) (cart->val + count + 1 ); + cart->count = count; + cart->eval = icvEvalCARTHaarClassifier; + cart->save = icvSaveCARTHaarClassifier; + cart->release = icvReleaseHaarClassifier; + + return (CvIntHaarClassifier*) cart; +} + + +void icvReleaseHaarClassifier( CvIntHaarClassifier** classifier ) +{ + cvFree( classifier ); + *classifier = NULL; +} + + +void icvInitCARTHaarClassifier( CvCARTHaarClassifier* carthaar, CvCARTClassifier* cart, + CvIntHaarFeatures* intHaarFeatures ) +{ + int i; + + for( i = 0; i < cart->count; i++ ) + { + carthaar->feature[i] = intHaarFeatures->feature[cart->compidx[i]]; + carthaar->fastfeature[i] = intHaarFeatures->fastfeature[cart->compidx[i]]; + carthaar->threshold[i] = cart->threshold[i]; + carthaar->left[i] = cart->left[i]; + carthaar->right[i] = cart->right[i]; + carthaar->val[i] = cart->val[i]; + carthaar->compidx[i] = cart->compidx[i]; + } + carthaar->count = cart->count; + carthaar->val[cart->count] = cart->val[cart->count]; +} + + +float icvEvalCARTHaarClassifier( CvIntHaarClassifier* classifier, + sum_type* sum, sum_type* tilted, float normfactor ) +{ + int idx = 0; + + do + { + if( cvEvalFastHaarFeature( + ((CvCARTHaarClassifier*) classifier)->fastfeature + idx, sum, tilted ) + < (((CvCARTHaarClassifier*) classifier)->threshold[idx] * normfactor) ) + { + idx = ((CvCARTHaarClassifier*) classifier)->left[idx]; + } + else + { + idx = ((CvCARTHaarClassifier*) classifier)->right[idx]; + } + } while( idx > 0 ); + + return ((CvCARTHaarClassifier*) classifier)->val[-idx]; +} + + +CvIntHaarClassifier* icvCreateStageHaarClassifier( int count, float threshold ) +{ + CvStageHaarClassifier* stage; + size_t datasize; + + datasize = sizeof( *stage ) + sizeof( CvIntHaarClassifier* ) * count; + stage = (CvStageHaarClassifier*) cvAlloc( datasize ); + memset( stage, 0, datasize ); + + stage->count = count; + stage->threshold = threshold; + stage->classifier = (CvIntHaarClassifier**) (stage + 1); + + stage->eval = icvEvalStageHaarClassifier; + stage->save = icvSaveStageHaarClassifier; + stage->release = icvReleaseStageHaarClassifier; + + return (CvIntHaarClassifier*) stage; +} + + +void icvReleaseStageHaarClassifier( CvIntHaarClassifier** classifier ) +{ + int i; + + for( i = 0; i < ((CvStageHaarClassifier*) *classifier)->count; i++ ) + { + if( ((CvStageHaarClassifier*) *classifier)->classifier[i] != NULL ) + { + ((CvStageHaarClassifier*) *classifier)->classifier[i]->release( + &(((CvStageHaarClassifier*) *classifier)->classifier[i]) ); + } + } + + cvFree( classifier ); + *classifier = NULL; +} + + +float icvEvalStageHaarClassifier( CvIntHaarClassifier* classifier, + sum_type* sum, sum_type* tilted, float normfactor ) +{ + int i; + float stage_sum; + + stage_sum = 0.0F; + for( i = 0; i < ((CvStageHaarClassifier*) classifier)->count; i++ ) + { + stage_sum += + ((CvStageHaarClassifier*) classifier)->classifier[i]->eval( + ((CvStageHaarClassifier*) classifier)->classifier[i], + sum, tilted, normfactor ); + } + + return stage_sum; +} + + +CvIntHaarClassifier* icvCreateCascadeHaarClassifier( int count ) +{ + CvCascadeHaarClassifier* ptr; + size_t datasize; + + datasize = sizeof( *ptr ) + sizeof( CvIntHaarClassifier* ) * count; + ptr = (CvCascadeHaarClassifier*) cvAlloc( datasize ); + memset( ptr, 0, datasize ); + + ptr->count = count; + ptr->classifier = (CvIntHaarClassifier**) (ptr + 1); + + ptr->eval = icvEvalCascadeHaarClassifier; + ptr->save = NULL; + ptr->release = icvReleaseCascadeHaarClassifier; + + return (CvIntHaarClassifier*) ptr; +} + + +void icvReleaseCascadeHaarClassifier( CvIntHaarClassifier** classifier ) +{ + int i; + + for( i = 0; i < ((CvCascadeHaarClassifier*) *classifier)->count; i++ ) + { + if( ((CvCascadeHaarClassifier*) *classifier)->classifier[i] != NULL ) + { + ((CvCascadeHaarClassifier*) *classifier)->classifier[i]->release( + &(((CvCascadeHaarClassifier*) *classifier)->classifier[i]) ); + } + } + + cvFree( classifier ); + *classifier = NULL; +} + + +float icvEvalCascadeHaarClassifier( CvIntHaarClassifier* classifier, + sum_type* sum, sum_type* tilted, float normfactor ) +{ + int i; + + for( i = 0; i < ((CvCascadeHaarClassifier*) classifier)->count; i++ ) + { + if( ((CvCascadeHaarClassifier*) classifier)->classifier[i]->eval( + ((CvCascadeHaarClassifier*) classifier)->classifier[i], + sum, tilted, normfactor ) + < ( ((CvStageHaarClassifier*) + ((CvCascadeHaarClassifier*) classifier)->classifier[i])->threshold + - CV_THRESHOLD_EPS) ) + { + return 0.0; + } + } + + return 1.0; +} + + +void icvSaveHaarFeature( CvTHaarFeature* feature, FILE* file ) +{ + fprintf( file, "%d\n", ( ( feature->rect[2].weight == 0.0F ) ? 2 : 3) ); + fprintf( file, "%d %d %d %d %d %d\n", + feature->rect[0].r.x, + feature->rect[0].r.y, + feature->rect[0].r.width, + feature->rect[0].r.height, + 0, + (int) (feature->rect[0].weight) ); + fprintf( file, "%d %d %d %d %d %d\n", + feature->rect[1].r.x, + feature->rect[1].r.y, + feature->rect[1].r.width, + feature->rect[1].r.height, + 0, + (int) (feature->rect[1].weight) ); + if( feature->rect[2].weight != 0.0F ) + { + fprintf( file, "%d %d %d %d %d %d\n", + feature->rect[2].r.x, + feature->rect[2].r.y, + feature->rect[2].r.width, + feature->rect[2].r.height, + 0, + (int) (feature->rect[2].weight) ); + } + fprintf( file, "%s\n", &(feature->desc[0]) ); +} + + +void icvLoadHaarFeature( CvTHaarFeature* feature, FILE* file ) +{ + int nrect; + int j; + int tmp; + int weight; + + nrect = 0; + fscanf( file, "%d", &nrect ); + + assert( nrect <= CV_HAAR_FEATURE_MAX ); + + for( j = 0; j < nrect; j++ ) + { + fscanf( file, "%d %d %d %d %d %d", + &(feature->rect[j].r.x), + &(feature->rect[j].r.y), + &(feature->rect[j].r.width), + &(feature->rect[j].r.height), + &tmp, &weight ); + feature->rect[j].weight = (float) weight; + } + for( j = nrect; j < CV_HAAR_FEATURE_MAX; j++ ) + { + feature->rect[j].r.x = 0; + feature->rect[j].r.y = 0; + feature->rect[j].r.width = 0; + feature->rect[j].r.height = 0; + feature->rect[j].weight = 0.0f; + } + fscanf( file, "%s", &(feature->desc[0]) ); + feature->tilted = ( feature->desc[0] == 't' ); +} + + +void icvSaveCARTHaarClassifier( CvIntHaarClassifier* classifier, FILE* file ) +{ + int i; + int count; + + count = ((CvCARTHaarClassifier*) classifier)->count; + fprintf( file, "%d\n", count ); + for( i = 0; i < count; i++ ) + { + icvSaveHaarFeature( &(((CvCARTHaarClassifier*) classifier)->feature[i]), file ); + fprintf( file, "%e %d %d\n", + ((CvCARTHaarClassifier*) classifier)->threshold[i], + ((CvCARTHaarClassifier*) classifier)->left[i], + ((CvCARTHaarClassifier*) classifier)->right[i] ); + } + for( i = 0; i <= count; i++ ) + { + fprintf( file, "%e ", ((CvCARTHaarClassifier*) classifier)->val[i] ); + } + fprintf( file, "\n" ); +} + + +CvIntHaarClassifier* icvLoadCARTHaarClassifier( FILE* file, int step ) +{ + CvCARTHaarClassifier* ptr; + int i; + int count; + + ptr = NULL; + fscanf( file, "%d", &count ); + if( count > 0 ) + { + ptr = (CvCARTHaarClassifier*) icvCreateCARTHaarClassifier( count ); + for( i = 0; i < count; i++ ) + { + icvLoadHaarFeature( &(ptr->feature[i]), file ); + fscanf( file, "%f %d %d", &(ptr->threshold[i]), &(ptr->left[i]), + &(ptr->right[i]) ); + } + for( i = 0; i <= count; i++ ) + { + fscanf( file, "%f", &(ptr->val[i]) ); + } + icvConvertToFastHaarFeature( ptr->feature, ptr->fastfeature, ptr->count, step ); + } + + return (CvIntHaarClassifier*) ptr; +} + + +void icvSaveStageHaarClassifier( CvIntHaarClassifier* classifier, FILE* file ) +{ + int count; + int i; + float threshold; + + count = ((CvStageHaarClassifier*) classifier)->count; + fprintf( file, "%d\n", count ); + for( i = 0; i < count; i++ ) + { + ((CvStageHaarClassifier*) classifier)->classifier[i]->save( + ((CvStageHaarClassifier*) classifier)->classifier[i], file ); + } + + threshold = ((CvStageHaarClassifier*) classifier)->threshold; + + /* to be compatible with the previous implementation */ + /* threshold = 2.0F * ((CvStageHaarClassifier*) classifier)->threshold - count; */ + + fprintf( file, "%e\n", threshold ); +} + + + +CvIntHaarClassifier* icvLoadCARTStageHaarClassifierF( FILE* file, int step ) +{ + CvStageHaarClassifier* ptr = NULL; + + //CV_FUNCNAME( "icvLoadCARTStageHaarClassifierF" ); + + __BEGIN__; + + if( file != NULL ) + { + int count; + int i; + float threshold; + + count = 0; + fscanf( file, "%d", &count ); + if( count > 0 ) + { + ptr = (CvStageHaarClassifier*) icvCreateStageHaarClassifier( count, 0.0F ); + for( i = 0; i < count; i++ ) + { + ptr->classifier[i] = icvLoadCARTHaarClassifier( file, step ); + } + + fscanf( file, "%f", &threshold ); + + ptr->threshold = threshold; + /* to be compatible with the previous implementation */ + /* ptr->threshold = 0.5F * (threshold + count); */ + } + if( feof( file ) ) + { + ptr->release( (CvIntHaarClassifier**) &ptr ); + ptr = NULL; + } + } + + __END__; + + return (CvIntHaarClassifier*) ptr; +} + + +CvIntHaarClassifier* icvLoadCARTStageHaarClassifier( const char* filename, int step ) +{ + CvIntHaarClassifier* ptr = NULL; + + CV_FUNCNAME( "icvLoadCARTStageHaarClassifier" ); + + __BEGIN__; + + FILE* file; + + file = fopen( filename, "r" ); + if( file ) + { + CV_CALL( ptr = icvLoadCARTStageHaarClassifierF( file, step ) ); + fclose( file ); + } + + __END__; + + return ptr; +} + +/* tree cascade classifier */ + +/* evaluates a tree cascade classifier */ + +float icvEvalTreeCascadeClassifier( CvIntHaarClassifier* classifier, + sum_type* sum, sum_type* tilted, float normfactor ) +{ + CvTreeCascadeNode* ptr; + + ptr = ((CvTreeCascadeClassifier*) classifier)->root; + + while( ptr ) + { + if( ptr->stage->eval( (CvIntHaarClassifier*) ptr->stage, + sum, tilted, normfactor ) + >= ptr->stage->threshold - CV_THRESHOLD_EPS ) + { + ptr = ptr->child; + } + else + { + while( ptr && ptr->next == NULL ) ptr = ptr->parent; + if( ptr == NULL ) return 0.0F; + ptr = ptr->next; + } + } + + return 1.0F; +} + +/* sets path int the tree form the root to the leaf node */ + +void icvSetLeafNode( CvTreeCascadeClassifier* tcc, CvTreeCascadeNode* leaf ) +{ + CV_FUNCNAME( "icvSetLeafNode" ); + + __BEGIN__; + + CvTreeCascadeNode* ptr; + + ptr = NULL; + while( leaf ) + { + leaf->child_eval = ptr; + ptr = leaf; + leaf = leaf->parent; + } + + leaf = tcc->root; + while( leaf && leaf != ptr ) leaf = leaf->next; + if( leaf != ptr ) + CV_ERROR( CV_StsError, "Invalid tcc or leaf node." ); + + tcc->root_eval = ptr; + + __END__; +} + +/* evaluates a tree cascade classifier. used in filtering */ + +float icvEvalTreeCascadeClassifierFilter( CvIntHaarClassifier* classifier, sum_type* sum, + sum_type* tilted, float normfactor ) +{ + CvTreeCascadeNode* ptr; + CvTreeCascadeClassifier* tree; + + tree = (CvTreeCascadeClassifier*) classifier; + + + + ptr = ((CvTreeCascadeClassifier*) classifier)->root_eval; + while( ptr ) + { + if( ptr->stage->eval( (CvIntHaarClassifier*) ptr->stage, + sum, tilted, normfactor ) + < ptr->stage->threshold - CV_THRESHOLD_EPS ) + { + return 0.0F; + } + ptr = ptr->child_eval; + } + + return 1.0F; +} + +/* creates tree cascade node */ + +CvTreeCascadeNode* icvCreateTreeCascadeNode() +{ + CvTreeCascadeNode* ptr = NULL; + + CV_FUNCNAME( "icvCreateTreeCascadeNode" ); + + __BEGIN__; + size_t data_size; + + data_size = sizeof( *ptr ); + CV_CALL( ptr = (CvTreeCascadeNode*) cvAlloc( data_size ) ); + memset( ptr, 0, data_size ); + + __END__; + + return ptr; +} + +/* releases all tree cascade nodes accessible via links */ + +void icvReleaseTreeCascadeNodes( CvTreeCascadeNode** node ) +{ + //CV_FUNCNAME( "icvReleaseTreeCascadeNodes" ); + + __BEGIN__; + + if( node && *node ) + { + CvTreeCascadeNode* ptr; + CvTreeCascadeNode* ptr_; + + ptr = *node; + + while( ptr ) + { + while( ptr->child ) ptr = ptr->child; + + if( ptr->stage ) ptr->stage->release( (CvIntHaarClassifier**) &ptr->stage ); + ptr_ = ptr; + + while( ptr && ptr->next == NULL ) ptr = ptr->parent; + if( ptr ) ptr = ptr->next; + + cvFree( &ptr_ ); + } + } + + __END__; +} + + +/* releases tree cascade classifier */ + +void icvReleaseTreeCascadeClassifier( CvIntHaarClassifier** classifier ) +{ + if( classifier && *classifier ) + { + icvReleaseTreeCascadeNodes( &((CvTreeCascadeClassifier*) *classifier)->root ); + cvFree( classifier ); + *classifier = NULL; + } +} + + +void icvPrintTreeCascade( CvTreeCascadeNode* root ) +{ + //CV_FUNCNAME( "icvPrintTreeCascade" ); + + __BEGIN__; + + CvTreeCascadeNode* node; + CvTreeCascadeNode* n; + char buf0[256]; + char buf[256]; + int level; + int i; + int max_level; + + node = root; + level = max_level = 0; + while( node ) + { + while( node->child ) { node = node->child; level++; } + if( level > max_level ) { max_level = level; } + while( node && !node->next ) { node = node->parent; level--; } + if( node ) node = node->next; + } + + printf( "\nTree Classifier\n" ); + printf( "Stage\n" ); + for( i = 0; i <= max_level; i++ ) printf( "+---" ); + printf( "+\n" ); + for( i = 0; i <= max_level; i++ ) printf( "|%3d", i ); + printf( "|\n" ); + for( i = 0; i <= max_level; i++ ) printf( "+---" ); + printf( "+\n\n" ); + + node = root; + + buf[0] = 0; + while( node ) + { + sprintf( buf + strlen( buf ), "%3d", node->idx ); + while( node->child ) + { + node = node->child; + sprintf( buf + strlen( buf ), + ((node->idx < 10) ? "---%d" : ((node->idx < 100) ? "--%d" : "-%d")), + node->idx ); + } + printf( " %s\n", buf ); + + while( node && !node->next ) { node = node->parent; } + if( node ) + { + node = node->next; + + n = node->parent; + buf[0] = 0; + while( n ) + { + if( n->next ) + sprintf( buf0, " | %s", buf ); + else + sprintf( buf0, " %s", buf ); + strcpy( buf, buf0 ); + n = n->parent; + } + printf( " %s |\n", buf ); + } + } + printf( "\n" ); + fflush( stdout ); + + __END__; +} + + + +CvIntHaarClassifier* icvLoadTreeCascadeClassifier( const char* filename, int step, + int* splits ) +{ + CvTreeCascadeClassifier* ptr = NULL; + CvTreeCascadeNode** nodes = NULL; + + CV_FUNCNAME( "icvLoadTreeCascadeClassifier" ); + + __BEGIN__; + + size_t data_size; + CvStageHaarClassifier* stage; + char stage_name[PATH_MAX]; + char* suffix; + int i, num; + FILE* f; + int result, parent=0, next=0; + int stub; + + if( !splits ) splits = &stub; + + *splits = 0; + + data_size = sizeof( *ptr ); + + CV_CALL( ptr = (CvTreeCascadeClassifier*) cvAlloc( data_size ) ); + memset( ptr, 0, data_size ); + + ptr->eval = icvEvalTreeCascadeClassifier; + ptr->release = icvReleaseTreeCascadeClassifier; + + sprintf( stage_name, "%s/", filename ); + suffix = stage_name + strlen( stage_name ); + + for( i = 0; ; i++ ) + { + sprintf( suffix, "%d/%s", i, CV_STAGE_CART_FILE_NAME ); + f = fopen( stage_name, "r" ); + if( !f ) break; + fclose( f ); + } + num = i; + + if( num < 1 ) EXIT; + + data_size = sizeof( *nodes ) * num; + CV_CALL( nodes = (CvTreeCascadeNode**) cvAlloc( data_size ) ); + + for( i = 0; i < num; i++ ) + { + sprintf( suffix, "%d/%s", i, CV_STAGE_CART_FILE_NAME ); + f = fopen( stage_name, "r" ); + CV_CALL( stage = (CvStageHaarClassifier*) + icvLoadCARTStageHaarClassifierF( f, step ) ); + + result = ( f && stage ) ? fscanf( f, "%d%d", &parent, &next ) : 0; + if( f ) fclose( f ); + + if( result != 2 ) + { + num = i; + break; + } + + printf( "Stage %d loaded\n", i ); + + if( parent >= i || (next != -1 && next != i + 1) ) + CV_ERROR( CV_StsError, "Invalid tree links" ); + + CV_CALL( nodes[i] = icvCreateTreeCascadeNode() ); + nodes[i]->stage = stage; + nodes[i]->idx = i; + nodes[i]->parent = (parent != -1 ) ? nodes[parent] : NULL; + nodes[i]->next = ( next != -1 ) ? nodes[i] : NULL; + nodes[i]->child = NULL; + } + for( i = 0; i < num; i++ ) + { + if( nodes[i]->next ) + { + (*splits)++; + nodes[i]->next = nodes[i+1]; + } + if( nodes[i]->parent && nodes[i]->parent->child == NULL ) + { + nodes[i]->parent->child = nodes[i]; + } + } + ptr->root = nodes[0]; + ptr->next_idx = num; + + __END__; + + cvFree( &nodes ); + + return (CvIntHaarClassifier*) ptr; +} + + +CvTreeCascadeNode* icvFindDeepestLeaves( CvTreeCascadeClassifier* tcc ) +{ + CvTreeCascadeNode* leaves; + + //CV_FUNCNAME( "icvFindDeepestLeaves" ); + + __BEGIN__; + + int level, cur_level; + CvTreeCascadeNode* ptr; + CvTreeCascadeNode* last; + + leaves = last = NULL; + + ptr = tcc->root; + level = -1; + cur_level = 0; + + /* find leaves with maximal level */ + while( ptr ) + { + if( ptr->child ) { ptr = ptr->child; cur_level++; } + else + { + if( cur_level == level ) + { + last->next_same_level = ptr; + ptr->next_same_level = NULL; + last = ptr; + } + if( cur_level > level ) + { + level = cur_level; + leaves = last = ptr; + ptr->next_same_level = NULL; + } + while( ptr && ptr->next == NULL ) { ptr = ptr->parent; cur_level--; } + if( ptr ) ptr = ptr->next; + } + } + + __END__; + + return leaves; +} + +/* End of file. */