mirror of
https://github.com/opencv/opencv_contrib.git
synced 2025-10-19 19:44:14 +08:00
Added new method for training forest
This commit is contained in:
@@ -63,20 +63,41 @@ namespace optflow
|
||||
struct CV_EXPORTS_W GPCPatchDescriptor
|
||||
{
|
||||
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 );
|
||||
};
|
||||
|
||||
typedef std::pair<GPCPatchDescriptor, GPCPatchDescriptor> GPCPatchSample;
|
||||
typedef std::vector<GPCPatchSample> 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<double, GPCPatchDescriptor::nFeatures> 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<Node> 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<GPCTree> create() { return makePtr<GPCTree>(); }
|
||||
static Ptr< GPCTree > create() { return makePtr< GPCTree >(); }
|
||||
|
||||
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:
|
||||
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<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> > );
|
||||
|
||||
size_t size() const { return samples.size(); }
|
||||
|
||||
operator GPCSamplesVector() const { return samples; }
|
||||
|
||||
operator GPCSamplesVector &() { return samples; }
|
||||
static Ptr< GPCForest > create() { return makePtr< GPCForest >(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -14,7 +14,7 @@ int main( int argc, const char **argv )
|
||||
}
|
||||
|
||||
nSequences /= 3;
|
||||
std::vector<cv::String> 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<cv::optflow::GPCTrainingSamples> ts = cv::optflow::GPCTrainingSamples::create( 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 );
|
||||
cv::Ptr< cv::optflow::GPCForest< nTrees > > forest = cv::optflow::GPCForest< nTrees >::create();
|
||||
forest->train( img1, img2, gt );
|
||||
forest->save( "forest.dump" );
|
||||
|
||||
return 0;
|
||||
|
@@ -72,10 +72,10 @@ struct Magnitude
|
||||
|
||||
struct PartitionPredicate1
|
||||
{
|
||||
Vec<double, GPCPatchDescriptor::nFeatures> coef;
|
||||
Vec< double, GPCPatchDescriptor::nFeatures > coef;
|
||||
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
|
||||
{
|
||||
@@ -87,10 +87,10 @@ struct PartitionPredicate1
|
||||
|
||||
struct PartitionPredicate2
|
||||
{
|
||||
Vec<double, GPCPatchDescriptor::nFeatures> coef;
|
||||
Vec< double, GPCPatchDescriptor::nFeatures > coef;
|
||||
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
|
||||
{
|
||||
@@ -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<Magnitude> 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<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() );
|
||||
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<Vec2f>( i0, j0 )[1] );
|
||||
int j1 = j0 + cvRound( gt.at<Vec2f>( 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<double, GPCPatchDescriptor::nFeatures> &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<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[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<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[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<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[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<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[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<double> values;
|
||||
std::vector< double > values;
|
||||
|
||||
for ( int j = 0; j < globalIters; ++j )
|
||||
{ // Global search step
|
||||
Vec<double, GPCPatchDescriptor::nFeatures> 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> GPCTrainingSamples::create( const std::vector<String> &imagesFrom, const std::vector<String> &imagesTo,
|
||||
const std::vector<String> > )
|
||||
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<GPCTrainingSamples> ts = makePtr<GPCTrainingSamples>();
|
||||
Ptr< GPCTrainingSamples > ts = makePtr< GPCTrainingSamples >();
|
||||
for ( size_t i = 0; i < imagesFrom.size(); ++i )
|
||||
{
|
||||
Mat from = imread( imagesFrom[i] );
|
||||
|
Reference in New Issue
Block a user