Commit 17831add authored by Vladislav Samsonov's avatar Vladislav Samsonov

Added new method for training forest

parent 7f93d951
...@@ -63,20 +63,41 @@ namespace optflow ...@@ -63,20 +63,41 @@ namespace optflow
struct CV_EXPORTS_W GPCPatchDescriptor struct CV_EXPORTS_W GPCPatchDescriptor
{ {
static const unsigned nFeatures = 18; // number of features in a patch descriptor static const unsigned nFeatures = 18; // number of features in a patch descriptor
Vec<double, nFeatures> feature; Vec< double, nFeatures > feature;
GPCPatchDescriptor( const Mat *imgCh, int i, int j ); GPCPatchDescriptor( const Mat *imgCh, int i, int j );
}; };
typedef std::pair<GPCPatchDescriptor, GPCPatchDescriptor> GPCPatchSample; typedef std::pair< GPCPatchDescriptor, GPCPatchDescriptor > GPCPatchSample;
typedef std::vector<GPCPatchSample> GPCSamplesVector; 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 > &gt );
size_t size() const { return samples.size(); }
operator GPCSamplesVector() const { return samples; }
operator GPCSamplesVector &() { return samples; }
};
class CV_EXPORTS_W GPCTree : public Algorithm class CV_EXPORTS_W GPCTree : public Algorithm
{ {
public: public:
struct Node struct Node
{ {
Vec<double, GPCPatchDescriptor::nFeatures> coef; // hyperplane coefficients Vec< double, GPCPatchDescriptor::nFeatures > coef; // hyperplane coefficients
double rhs; double rhs;
unsigned left; unsigned left;
unsigned right; unsigned right;
...@@ -87,7 +108,7 @@ public: ...@@ -87,7 +108,7 @@ public:
private: private:
typedef GPCSamplesVector::iterator SIter; typedef GPCSamplesVector::iterator SIter;
std::vector<Node> nodes; std::vector< Node > nodes;
bool trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth ); bool trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth );
...@@ -98,23 +119,38 @@ public: ...@@ -98,23 +119,38 @@ public:
void read( const FileNode &fn ); void read( const FileNode &fn );
static Ptr<GPCTree> create() { return makePtr<GPCTree>(); } static Ptr< GPCTree > create() { return makePtr< GPCTree >(); }
bool operator==( const GPCTree &t ) const { return nodes == t.nodes; } bool operator==( const GPCTree &t ) const { return nodes == t.nodes; }
}; };
template <int T> class CV_EXPORTS_W GPCForest : public Algorithm template < int T > class CV_EXPORTS_W GPCForest : public Algorithm
{ {
private: private:
GPCTree tree[T]; GPCTree tree[T];
public: 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 ) void train( GPCSamplesVector &samples )
{ {
for ( int i = 0; i < T; ++i ) for ( int i = 0; i < T; ++i )
tree[i].train( samples ); 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 > &gt )
{
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 void write( FileStorage &fs ) const
{ {
fs << "ntrees" << T << "trees" fs << "ntrees" << T << "trees"
...@@ -136,28 +172,7 @@ public: ...@@ -136,28 +172,7 @@ public:
tree[i].read( *it ); tree[i].read( *it );
} }
static Ptr<GPCForest> create() { return makePtr<GPCForest>(); } static Ptr< GPCForest > create() { return makePtr< GPCForest >(); }
};
/** @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> &gt );
size_t size() const { return samples.size(); }
operator GPCSamplesVector() const { return samples; }
operator GPCSamplesVector &() { return samples; }
}; };
} }
......
...@@ -14,7 +14,7 @@ int main( int argc, const char **argv ) ...@@ -14,7 +14,7 @@ int main( int argc, const char **argv )
} }
nSequences /= 3; nSequences /= 3;
std::vector<cv::String> img1, img2, gt; std::vector< cv::String > img1, img2, gt;
for ( int i = 0; i < nSequences; ++i ) for ( int i = 0; i < nSequences; ++i )
{ {
...@@ -23,12 +23,8 @@ int main( int argc, const char **argv ) ...@@ -23,12 +23,8 @@ int main( int argc, const char **argv )
gt.push_back( argv[1 + i * 3 + 2] ); gt.push_back( argv[1 + i * 3 + 2] );
} }
cv::Ptr<cv::optflow::GPCTrainingSamples> ts = cv::optflow::GPCTrainingSamples::create( img1, img2, gt ); cv::Ptr< cv::optflow::GPCForest< nTrees > > forest = cv::optflow::GPCForest< nTrees >::create();
forest->train( img1, img2, gt );
std::cout << "Got " << ts->size() << " samples." << std::endl;
cv::Ptr< cv::optflow::GPCForest<nTrees> > forest = cv::optflow::GPCForest<nTrees>::create();
forest->train( *ts );
forest->save( "forest.dump" ); forest->save( "forest.dump" );
return 0; return 0;
......
...@@ -72,10 +72,10 @@ struct Magnitude ...@@ -72,10 +72,10 @@ struct Magnitude
struct PartitionPredicate1 struct PartitionPredicate1
{ {
Vec<double, GPCPatchDescriptor::nFeatures> coef; Vec< double, GPCPatchDescriptor::nFeatures > coef;
double rhs; double rhs;
PartitionPredicate1( const Vec<double, GPCPatchDescriptor::nFeatures> &_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 bool operator()( const GPCPatchSample &sample ) const
{ {
...@@ -87,10 +87,10 @@ struct PartitionPredicate1 ...@@ -87,10 +87,10 @@ struct PartitionPredicate1
struct PartitionPredicate2 struct PartitionPredicate2
{ {
Vec<double, GPCPatchDescriptor::nFeatures> coef; Vec< double, GPCPatchDescriptor::nFeatures > coef;
double rhs; double rhs;
PartitionPredicate2( const Vec<double, GPCPatchDescriptor::nFeatures> &_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 bool operator()( const GPCPatchSample &sample ) const
{ {
...@@ -110,13 +110,14 @@ bool checkBounds( int i, int j, Size sz ) ...@@ -110,13 +110,14 @@ bool checkBounds( int i, int j, Size sz )
void getTrainingSamples( const Mat &from, const Mat &to, const Mat &gt, GPCSamplesVector &samples ) void getTrainingSamples( const Mat &from, const Mat &to, const Mat &gt, GPCSamplesVector &samples )
{ {
const Size sz = gt.size(); const Size sz = gt.size();
std::vector<Magnitude> mag; std::vector< Magnitude > mag;
for ( int i = patchRadius; i + patchRadius < sz.height; ++i ) for ( int i = patchRadius; i + patchRadius < sz.height; ++i )
for ( int j = patchRadius; j + patchRadius < sz.width; ++j ) for ( int j = patchRadius; j + patchRadius < sz.width; ++j )
mag.push_back( Magnitude( normL2Sqr( gt.at<Vec2f>( 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() ); std::nth_element( mag.begin(), mag.begin() + n, mag.end() );
mag.resize( n ); mag.resize( n );
std::random_shuffle( mag.begin(), mag.end() ); std::random_shuffle( mag.begin(), mag.end() );
...@@ -131,8 +132,8 @@ void getTrainingSamples( const Mat &from, const Mat &to, const Mat &gt, GPCSampl ...@@ -131,8 +132,8 @@ void getTrainingSamples( const Mat &from, const Mat &to, const Mat &gt, GPCSampl
{ {
int i0 = mag[k].i; int i0 = mag[k].i;
int j0 = mag[k].j; int j0 = mag[k].j;
int i1 = i0 + cvRound( gt.at<Vec2f>( i0, j0 )[1] ); int i1 = i0 + cvRound( gt.at< Vec2f >( i0, j0 )[1] );
int j1 = j0 + cvRound( gt.at<Vec2f>( i0, j0 )[0] ); int j1 = j0 + cvRound( gt.at< Vec2f >( i0, j0 )[0] );
if ( checkBounds( i1, j1, sz ) ) if ( checkBounds( i1, j1, sz ) )
samples.push_back( std::make_pair( GPCPatchDescriptor( fromCh, i0, j0 ), GPCPatchDescriptor( toCh, i1, j1 ) ) ); samples.push_back( std::make_pair( GPCPatchDescriptor( fromCh, i0, j0 ), GPCPatchDescriptor( toCh, i1, j1 ) ) );
} }
...@@ -149,7 +150,7 @@ double getRandomCauchyScalar() ...@@ -149,7 +150,7 @@ double getRandomCauchyScalar()
/* Sample random vector from Cauchy distribution (pointwise, i.e. vector whose components are independent random /* Sample random vector from Cauchy distribution (pointwise, i.e. vector whose components are independent random
* variables from Cauchy distribution) */ * variables from Cauchy distribution) */
void getRandomCauchyVector( Vec<double, GPCPatchDescriptor::nFeatures> &v ) void getRandomCauchyVector( Vec< double, GPCPatchDescriptor::nFeatures > &v )
{ {
for ( unsigned i = 0; i < GPCPatchDescriptor::nFeatures; ++i ) for ( unsigned i = 0; i < GPCPatchDescriptor::nFeatures; ++i )
v[i] = getRandomCauchyScalar(); v[i] = getRandomCauchyScalar();
...@@ -162,25 +163,25 @@ GPCPatchDescriptor::GPCPatchDescriptor( const Mat *imgCh, int i, int j ) ...@@ -162,25 +163,25 @@ GPCPatchDescriptor::GPCPatchDescriptor( const Mat *imgCh, int i, int j )
Mat freqDomain; Mat freqDomain;
dct( imgCh[0]( roi ), freqDomain ); dct( imgCh[0]( roi ), freqDomain );
feature[0] = freqDomain.at<float>( 0, 0 ); feature[0] = freqDomain.at< float >( 0, 0 );
feature[1] = freqDomain.at<float>( 0, 1 ); feature[1] = freqDomain.at< float >( 0, 1 );
feature[2] = freqDomain.at<float>( 0, 2 ); feature[2] = freqDomain.at< float >( 0, 2 );
feature[3] = freqDomain.at<float>( 0, 3 ); feature[3] = freqDomain.at< float >( 0, 3 );
feature[4] = freqDomain.at<float>( 1, 0 ); feature[4] = freqDomain.at< float >( 1, 0 );
feature[5] = freqDomain.at<float>( 1, 1 ); feature[5] = freqDomain.at< float >( 1, 1 );
feature[6] = freqDomain.at<float>( 1, 2 ); feature[6] = freqDomain.at< float >( 1, 2 );
feature[7] = freqDomain.at<float>( 1, 3 ); feature[7] = freqDomain.at< float >( 1, 3 );
feature[8] = freqDomain.at<float>( 2, 0 ); feature[8] = freqDomain.at< float >( 2, 0 );
feature[9] = freqDomain.at<float>( 2, 1 ); feature[9] = freqDomain.at< float >( 2, 1 );
feature[10] = freqDomain.at<float>( 2, 2 ); feature[10] = freqDomain.at< float >( 2, 2 );
feature[11] = freqDomain.at<float>( 2, 3 ); feature[11] = freqDomain.at< float >( 2, 3 );
feature[12] = freqDomain.at<float>( 3, 0 ); feature[12] = freqDomain.at< float >( 3, 0 );
feature[13] = freqDomain.at<float>( 3, 1 ); feature[13] = freqDomain.at< float >( 3, 1 );
feature[14] = freqDomain.at<float>( 3, 2 ); feature[14] = freqDomain.at< float >( 3, 2 );
feature[15] = freqDomain.at<float>( 3, 3 ); feature[15] = freqDomain.at< float >( 3, 3 );
feature[16] = cv::sum( imgCh[1]( roi ) )[0] / ( 2 * patchRadius ); feature[16] = cv::sum( imgCh[1]( roi ) )[0] / ( 2 * patchRadius );
feature[17] = cv::sum( imgCh[2]( 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 ) ...@@ -198,11 +199,11 @@ bool GPCTree::trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth )
// Select the best hyperplane // Select the best hyperplane
unsigned globalBestScore = 0; unsigned globalBestScore = 0;
std::vector<double> values; std::vector< double > values;
for ( int j = 0; j < globalIters; ++j ) for ( int j = 0; j < globalIters; ++j )
{ // Global search step { // Global search step
Vec<double, GPCPatchDescriptor::nFeatures> coef; Vec< double, GPCPatchDescriptor::nFeatures > coef;
unsigned localBestScore = 0; unsigned localBestScore = 0;
getRandomCauchyVector( coef ); getRandomCauchyVector( coef );
...@@ -280,13 +281,13 @@ void GPCTree::write( FileStorage &fs ) const ...@@ -280,13 +281,13 @@ void GPCTree::write( FileStorage &fs ) const
void GPCTree::read( const FileNode &fn ) { fn["nodes"] >> nodes; } void GPCTree::read( const FileNode &fn ) { fn["nodes"] >> nodes; }
Ptr<GPCTrainingSamples> GPCTrainingSamples::create( const std::vector<String> &imagesFrom, const std::vector<String> &imagesTo, Ptr< GPCTrainingSamples > GPCTrainingSamples::create( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo,
const std::vector<String> &gt ) const std::vector< String > &gt )
{ {
CV_Assert( imagesFrom.size() == imagesTo.size() ); CV_Assert( imagesFrom.size() == imagesTo.size() );
CV_Assert( imagesFrom.size() == gt.size() ); CV_Assert( imagesFrom.size() == gt.size() );
Ptr<GPCTrainingSamples> ts = makePtr<GPCTrainingSamples>(); Ptr< GPCTrainingSamples > ts = makePtr< GPCTrainingSamples >();
for ( size_t i = 0; i < imagesFrom.size(); ++i ) for ( size_t i = 0; i < imagesFrom.size(); ++i )
{ {
Mat from = imread( imagesFrom[i] ); Mat from = imread( imagesFrom[i] );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment