diff --git a/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp b/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp index f0881eb31..2c0aee46b 100644 --- a/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp +++ b/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp @@ -63,20 +63,41 @@ namespace optflow struct CV_EXPORTS_W GPCPatchDescriptor { static const unsigned nFeatures = 18; // number of features in a patch descriptor - Vec feature; + Vec< double, nFeatures > feature; GPCPatchDescriptor( const Mat *imgCh, int i, int j ); }; -typedef std::pair GPCPatchSample; -typedef std::vector GPCSamplesVector; +typedef std::pair< GPCPatchDescriptor, GPCPatchDescriptor > GPCPatchSample; +typedef std::vector< GPCPatchSample > GPCSamplesVector; + +/** @brief Class encapsulating training samples. + */ +class CV_EXPORTS_W GPCTrainingSamples +{ +private: + GPCSamplesVector samples; + +public: + /** @brief This function can be used to extract samples from a pair of images and a ground truth flow. + * Sizes of all the provided vectors must be equal. + */ + static Ptr< GPCTrainingSamples > create( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo, + const std::vector< String > > ); + + size_t size() const { return samples.size(); } + + operator GPCSamplesVector() const { return samples; } + + operator GPCSamplesVector &() { return samples; } +}; class CV_EXPORTS_W GPCTree : public Algorithm { public: struct Node { - Vec coef; // hyperplane coefficients + Vec< double, GPCPatchDescriptor::nFeatures > coef; // hyperplane coefficients double rhs; unsigned left; unsigned right; @@ -87,7 +108,7 @@ public: private: typedef GPCSamplesVector::iterator SIter; - std::vector nodes; + std::vector< Node > nodes; bool trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth ); @@ -98,23 +119,38 @@ public: void read( const FileNode &fn ); - static Ptr create() { return makePtr(); } + static Ptr< GPCTree > create() { return makePtr< GPCTree >(); } bool operator==( const GPCTree &t ) const { return nodes == t.nodes; } }; -template class CV_EXPORTS_W GPCForest : public Algorithm +template < int T > class CV_EXPORTS_W GPCForest : public Algorithm { private: GPCTree tree[T]; public: + /** @brief Train the forest using one sample set for every tree. + * Please, consider using the next method instead of this one for better quality. + */ void train( GPCSamplesVector &samples ) { for ( int i = 0; i < T; ++i ) tree[i].train( samples ); } + /** @brief Train the forest using individual samples for each tree. + * It is generally better to use this instead of the first method. + */ + void train( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo, const std::vector< String > > ) + { + for ( int i = 0; i < T; ++i ) + { + Ptr< GPCTrainingSamples > samples = GPCTrainingSamples::create( imagesFrom, imagesTo, gt ); // Create training set for the tree + tree[i].train( *samples ); + } + } + void write( FileStorage &fs ) const { fs << "ntrees" << T << "trees" @@ -136,28 +172,7 @@ public: tree[i].read( *it ); } - static Ptr create() { return makePtr(); } -}; - -/** @brief Class encapsulating training samples. - */ -class CV_EXPORTS_W GPCTrainingSamples -{ -private: - GPCSamplesVector samples; - -public: - /** @brief This function can be used to extract samples from a pair of images and a ground truth flow. - * Sizes of all the provided vectors must be equal. - */ - static Ptr create( const std::vector &imagesFrom, const std::vector &imagesTo, - const std::vector > ); - - size_t size() const { return samples.size(); } - - operator GPCSamplesVector() const { return samples; } - - operator GPCSamplesVector &() { return samples; } + static Ptr< GPCForest > create() { return makePtr< GPCForest >(); } }; } diff --git a/modules/optflow/samples/gpc_train.cpp b/modules/optflow/samples/gpc_train.cpp index 67c6a81e1..d4583f925 100644 --- a/modules/optflow/samples/gpc_train.cpp +++ b/modules/optflow/samples/gpc_train.cpp @@ -14,7 +14,7 @@ int main( int argc, const char **argv ) } nSequences /= 3; - std::vector img1, img2, gt; + std::vector< cv::String > img1, img2, gt; for ( int i = 0; i < nSequences; ++i ) { @@ -23,12 +23,8 @@ int main( int argc, const char **argv ) gt.push_back( argv[1 + i * 3 + 2] ); } - cv::Ptr ts = cv::optflow::GPCTrainingSamples::create( img1, img2, gt ); - - std::cout << "Got " << ts->size() << " samples." << std::endl; - - cv::Ptr< cv::optflow::GPCForest > forest = cv::optflow::GPCForest::create(); - forest->train( *ts ); + cv::Ptr< cv::optflow::GPCForest< nTrees > > forest = cv::optflow::GPCForest< nTrees >::create(); + forest->train( img1, img2, gt ); forest->save( "forest.dump" ); return 0; diff --git a/modules/optflow/src/sparse_matching_gpc.cpp b/modules/optflow/src/sparse_matching_gpc.cpp index 459966a0e..476898e15 100644 --- a/modules/optflow/src/sparse_matching_gpc.cpp +++ b/modules/optflow/src/sparse_matching_gpc.cpp @@ -72,10 +72,10 @@ struct Magnitude struct PartitionPredicate1 { - Vec coef; + Vec< double, GPCPatchDescriptor::nFeatures > coef; double rhs; - PartitionPredicate1( const Vec &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {} + PartitionPredicate1( const Vec< double, GPCPatchDescriptor::nFeatures > &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {} bool operator()( const GPCPatchSample &sample ) const { @@ -87,10 +87,10 @@ struct PartitionPredicate1 struct PartitionPredicate2 { - Vec coef; + Vec< double, GPCPatchDescriptor::nFeatures > coef; double rhs; - PartitionPredicate2( const Vec &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {} + PartitionPredicate2( const Vec< double, GPCPatchDescriptor::nFeatures > &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {} bool operator()( const GPCPatchSample &sample ) const { @@ -110,13 +110,14 @@ bool checkBounds( int i, int j, Size sz ) void getTrainingSamples( const Mat &from, const Mat &to, const Mat >, GPCSamplesVector &samples ) { const Size sz = gt.size(); - std::vector mag; + std::vector< Magnitude > mag; for ( int i = patchRadius; i + patchRadius < sz.height; ++i ) for ( int j = patchRadius; j + patchRadius < sz.width; ++j ) - mag.push_back( Magnitude( normL2Sqr( gt.at( i, j ) ), i, j ) ); + mag.push_back( Magnitude( normL2Sqr( gt.at< Vec2f >( i, j ) ), i, j ) ); - size_t n = mag.size() * thresholdMagnitudeFrac; + size_t n = mag.size() * thresholdMagnitudeFrac; // As suggested in the paper, we discard part of the training samples + // with a small displacement and train to better distinguish hard pairs. std::nth_element( mag.begin(), mag.begin() + n, mag.end() ); mag.resize( n ); std::random_shuffle( mag.begin(), mag.end() ); @@ -131,8 +132,8 @@ void getTrainingSamples( const Mat &from, const Mat &to, const Mat >, GPCSampl { int i0 = mag[k].i; int j0 = mag[k].j; - int i1 = i0 + cvRound( gt.at( i0, j0 )[1] ); - int j1 = j0 + cvRound( gt.at( i0, j0 )[0] ); + int i1 = i0 + cvRound( gt.at< Vec2f >( i0, j0 )[1] ); + int j1 = j0 + cvRound( gt.at< Vec2f >( i0, j0 )[0] ); if ( checkBounds( i1, j1, sz ) ) samples.push_back( std::make_pair( GPCPatchDescriptor( fromCh, i0, j0 ), GPCPatchDescriptor( toCh, i1, j1 ) ) ); } @@ -149,7 +150,7 @@ double getRandomCauchyScalar() /* Sample random vector from Cauchy distribution (pointwise, i.e. vector whose components are independent random * variables from Cauchy distribution) */ -void getRandomCauchyVector( Vec &v ) +void getRandomCauchyVector( Vec< double, GPCPatchDescriptor::nFeatures > &v ) { for ( unsigned i = 0; i < GPCPatchDescriptor::nFeatures; ++i ) v[i] = getRandomCauchyScalar(); @@ -162,25 +163,25 @@ GPCPatchDescriptor::GPCPatchDescriptor( const Mat *imgCh, int i, int j ) Mat freqDomain; dct( imgCh[0]( roi ), freqDomain ); - feature[0] = freqDomain.at( 0, 0 ); - feature[1] = freqDomain.at( 0, 1 ); - feature[2] = freqDomain.at( 0, 2 ); - feature[3] = freqDomain.at( 0, 3 ); + feature[0] = freqDomain.at< float >( 0, 0 ); + feature[1] = freqDomain.at< float >( 0, 1 ); + feature[2] = freqDomain.at< float >( 0, 2 ); + feature[3] = freqDomain.at< float >( 0, 3 ); - feature[4] = freqDomain.at( 1, 0 ); - feature[5] = freqDomain.at( 1, 1 ); - feature[6] = freqDomain.at( 1, 2 ); - feature[7] = freqDomain.at( 1, 3 ); + feature[4] = freqDomain.at< float >( 1, 0 ); + feature[5] = freqDomain.at< float >( 1, 1 ); + feature[6] = freqDomain.at< float >( 1, 2 ); + feature[7] = freqDomain.at< float >( 1, 3 ); - feature[8] = freqDomain.at( 2, 0 ); - feature[9] = freqDomain.at( 2, 1 ); - feature[10] = freqDomain.at( 2, 2 ); - feature[11] = freqDomain.at( 2, 3 ); + feature[8] = freqDomain.at< float >( 2, 0 ); + feature[9] = freqDomain.at< float >( 2, 1 ); + feature[10] = freqDomain.at< float >( 2, 2 ); + feature[11] = freqDomain.at< float >( 2, 3 ); - feature[12] = freqDomain.at( 3, 0 ); - feature[13] = freqDomain.at( 3, 1 ); - feature[14] = freqDomain.at( 3, 2 ); - feature[15] = freqDomain.at( 3, 3 ); + feature[12] = freqDomain.at< float >( 3, 0 ); + feature[13] = freqDomain.at< float >( 3, 1 ); + feature[14] = freqDomain.at< float >( 3, 2 ); + feature[15] = freqDomain.at< float >( 3, 3 ); feature[16] = cv::sum( imgCh[1]( roi ) )[0] / ( 2 * patchRadius ); feature[17] = cv::sum( imgCh[2]( roi ) )[0] / ( 2 * patchRadius ); @@ -198,11 +199,11 @@ bool GPCTree::trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth ) // Select the best hyperplane unsigned globalBestScore = 0; - std::vector values; + std::vector< double > values; for ( int j = 0; j < globalIters; ++j ) { // Global search step - Vec coef; + Vec< double, GPCPatchDescriptor::nFeatures > coef; unsigned localBestScore = 0; getRandomCauchyVector( coef ); @@ -280,13 +281,13 @@ void GPCTree::write( FileStorage &fs ) const void GPCTree::read( const FileNode &fn ) { fn["nodes"] >> nodes; } -Ptr GPCTrainingSamples::create( const std::vector &imagesFrom, const std::vector &imagesTo, - const std::vector > ) +Ptr< GPCTrainingSamples > GPCTrainingSamples::create( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo, + const std::vector< String > > ) { CV_Assert( imagesFrom.size() == imagesTo.size() ); CV_Assert( imagesFrom.size() == gt.size() ); - Ptr ts = makePtr(); + Ptr< GPCTrainingSamples > ts = makePtr< GPCTrainingSamples >(); for ( size_t i = 0; i < imagesFrom.size(); ++i ) { Mat from = imread( imagesFrom[i] );