Tree representation.


Classes

class  tree_element
 This struct represents a node of the tree, and has pointers to other structs, thereby representing a branch or the entire tree. More...
struct  ParseError
 A named symbol to throw in the case that tree deserialization fails with a parse error. More...

Functions

vector< ImageRef > tree_detect_corners_all (const Image< byte > &im, const tree_element *detector, int threshold)
vector< ImageRef > tree_detect_corners (const Image< byte > &im, const tree_element *detector, int threshold, Image< int > scores)
tree_elementload_a_tree (istream &i, bool eq_branch)
tree_elementload_a_tree (istream &i)
vector< ImageRef > transform_offsets (const vector< ImageRef > &offsets, int angle, bool r)
void create_offsets ()

Variables

vector< vector
< ImageRef > > 
offsets
int num_offsets
pair< ImageRef,
ImageRef > 
offsets_bbox


Function Documentation

vector<ImageRef> tree_detect_corners_all ( const Image< byte > &  im,
const tree_element detector,
int  threshold 
)

Detect corners without nonmaximal suppression in an image.

This contains a large amount of configurable debugging code to verify the correctness of the detector by comparing different implementations. High speed is achieved by converting the detector in to bytecode and JIT-compiling if possible.

The function recognises the following GVars:

Parameters:
im The image to detect corners in.
detector The corner detector.
threshold The detector threshold.

Definition at line 45 of file faster_tree.cc.

References tree_element::bbox(), block_bytecode::detect(), tree_element::detect_corner(), and tree_element::make_fast_detector().

00046 {
00047     ImageRef tl, br, s;
00048     rpair(tl,br) = detector->bbox();
00049     s = im.size();
00050 
00051     int ymin = 1 - tl.y, ymax = s.y - 1 - br.y;
00052     int xmin = 1 - tl.x, xmax = s.x - 1 - br.x;
00053 
00054     ImageRef pos;
00055     
00056     vector<int> corners;
00057     
00058     block_bytecode f2 = detector->make_fast_detector(im.size().x);
00059 
00060     f2.detect(im, corners, threshold, xmin, xmax, ymin, ymax);
00061     
00062 
00063     if(GV3::get<bool>("debug.verify_detections"))
00064     {
00065         //Detect corners using slowest, but most obvious detector, since it's most likely to 
00066         //be correct.
00067         vector<ImageRef> t;
00068         for(pos.y = ymin; pos.y < ymax; pos.y++)
00069         {
00070             for(pos.x = xmin; pos.x < xmax; pos.x++)
00071                 if(detector->detect_corner(im, pos, threshold))
00072                     t.push_back(pos);
00073         }
00074 
00075         //Verify detected corners against this result
00076         if(t.size() == corners.size())
00077         {
00078             for(unsigned int i=0; i < corners.size(); i++)
00079                 if(im.data() + corners[i] != & im[t[i]])
00080                 {
00081                     cerr << "Fatal error: standard and fast detectors do not match!\n";
00082                     cerr << "Same number of corners, but different positions.\n";
00083                     exit(1);
00084                 }
00085         }
00086         else
00087         {
00088             cerr << "Fatal error: standard and fast detectors do not match!\n";
00089             cerr << "Different number of corners detected.\n";
00090             cerr << corners.size() << " " << t.size() << endl;
00091             exit(1);
00092         }
00093     }
00094 
00095     vector<ImageRef> ret;
00096 
00097     int d = im.size().x;
00098     for(unsigned int i=0; i < corners.size(); i++)
00099     {
00100         int o = corners[i];
00101         ret.push_back(ImageRef(o %d, o/d));
00102     }
00103 
00104     return ret;
00105 }

vector<ImageRef> tree_detect_corners ( const Image< byte > &  im,
const tree_element detector,
int  threshold,
Image< int >  scores 
)

Detect corners with nonmaximal suppression in an image.

This contains a large amount of configurable debugging code to verify the correctness of the detector by comparing different implementations. High speed is achieved by converting the detector in to bytecode and JIT-compiling if possible.

The function recognises the following GVars:

Parameters:
im The image to detect corners in.
detector The corner detector.
threshold The detector threshold.
scores This image will be used to store the corner scores for nonmaximal suppression and is the same size as im. It is passed as a parameter since allocation of an image of this size is a significant expense.

Definition at line 125 of file faster_tree.cc.

References tree_element::bbox(), block_bytecode::detect(), tree_element::detect_corner(), and tree_element::make_fast_detector().

Referenced by learn_detector(), and faster_learn::operator()().

00126 {
00127     ImageRef tl, br, s;
00128     rpair(tl,br) = detector->bbox();
00129     s = im.size();
00130 
00131     int ymin = 1 - tl.y, ymax = s.y - 1 - br.y;
00132     int xmin = 1 - tl.x, xmax = s.x - 1 - br.x;
00133 
00134     ImageRef pos;
00135     scores.zero();
00136     
00137     vector<int> corners;
00138     
00139     block_bytecode f2 = detector->make_fast_detector(im.size().x);
00140 
00141     f2.detect(im, corners, threshold, xmin, xmax, ymin, ymax);
00142     
00143 
00144     if(GV3::get<bool>("debug.verify_detections"))
00145     {
00146         //Detect corners using slowest, but most obvious detector, since it's most likely to 
00147         //be correct.
00148         vector<ImageRef> t;
00149         for(pos.y = ymin; pos.y < ymax; pos.y++)
00150         {
00151             for(pos.x = xmin; pos.x < xmax; pos.x++)
00152                 if(detector->detect_corner(im, pos, threshold))
00153                     t.push_back(pos);
00154         }
00155 
00156         //Verify detected corners against this result
00157         if(t.size() == corners.size())
00158         {
00159             for(unsigned int i=0; i < corners.size(); i++)
00160                 if(im.data() + corners[i] != & im[t[i]])
00161                 {
00162                     cerr << "Fatal error: standard and fast detectors do not match!\n";
00163                     cerr << "Same number of corners, but different positions.\n";
00164                     exit(1);
00165                 }
00166         }
00167         else
00168         {
00169             cerr << "Fatal error: standard and fast detectors do not match!\n";
00170             cerr << "Different number of corners detected.\n";
00171             cerr << corners.size() << " " << t.size() << endl;
00172             exit(1);
00173         }
00174     }
00175 
00176 
00177 
00178     //Compute scores
00179     for(unsigned int j=0; j < corners.size(); j++)
00180     {
00181         int i=threshold + 1;
00182         while(1)
00183         {
00184             int n = f2.detect(im.data() + corners[j], i);
00185             if(n != 0)
00186                 i += n;
00187             else
00188                 break;
00189         }
00190         scores.data()[corners[j]] = i-1;
00191     }
00192 
00193     if(GV3::get<bool>("debug.verify_scores"))
00194     {
00195         //Compute scores using the obvious, but slow recursive implementation.
00196         //This can be used to test the no obvious FAST implementation and the
00197         //non obviouser JIT implementation, if it ever exists.
00198         for(unsigned int j=0; j < corners.size(); j++)
00199         {
00200             int i=threshold + 1;
00201             ImageRef pos =  im.pos(im.data() + corners[j]);
00202             while(1)
00203             {
00204                 int n = detector->detect_corner(im, pos, i);
00205                 if(n != 0)
00206                     i += n;
00207                 else
00208                     break;
00209             }
00210 
00211             if(scores.data()[corners[j]] != i-1)
00212             {
00213                 cerr << "Fatal error: standard and fast scores do not match!\n";
00214                 cerr << "Different score detected at  " << pos << endl;
00215                 exit(1);
00216             }
00217         }
00218     }
00219 
00220     
00221     //Perform non-max suppression the simple way
00222     vector<ImageRef> nonmax;
00223     int d = im.size().x;
00224     for(unsigned int i=0; i < corners.size(); i++)
00225     {
00226         int o = corners[i];
00227         int v = scores.data()[o];
00228 
00229         if( v > *(scores.data() + o + 1    )  &&
00230             v > *(scores.data() + o - 1    )  &&
00231             v > *(scores.data() + o +d + 1 )  &&
00232             v > *(scores.data() + o +d     )  &&
00233             v > *(scores.data() + o +d - 1 )  &&
00234             v > *(scores.data() + o -d + 1 )  &&
00235             v > *(scores.data() + o -d     )  &&
00236             v > *(scores.data() + o -d - 1))
00237         {
00238             nonmax.push_back(ImageRef(o %d, o/d));
00239         }
00240     }
00241 
00242     return nonmax;
00243 }

tree_element* load_a_tree ( istream &  i,
bool  eq_branch 
)

Parses a tree from an istream.

This will deserialize a tree serialized by tree_element::print(). On error, ParseError is thrown.

Parameters:
i The stream to parse
eq_branch Is it an EQ branch? Check the invariant.
Returns:
An allocated tree. Ownership is passed to the callee.

Definition at line 287 of file faster_tree.cc.

References is_corner(), and split().

Referenced by faster_learn::faster_learn(), load_a_tree(), and main().

00288 {   
00289     string line;
00290     getline(i, line);
00291 
00292     vector<string> tok = split(line);
00293 
00294     if(tok.size() == 0)
00295         throw ParseError();
00296 
00297     if(tok[0] == "Is")
00298     {
00299         if(tok.size() != 7)
00300             throw ParseError();
00301 
00302         bool is_corner = ato<bool>(tok[2]);
00303 
00304         if(eq_branch && is_corner)
00305         {
00306             cerr << "Warning: Fixing invariant in tree\n";
00307             is_corner=0;
00308         }
00309 
00310         return new tree_element(is_corner);
00311     }
00312     else
00313     {
00314         if(tok.size() != 5)
00315             throw ParseError();
00316 
00317         int offset = ato<int>(tok[0]);
00318 
00319         auto_ptr<tree_element> t1(load_a_tree(i, false));
00320         auto_ptr<tree_element> t2(load_a_tree(i, true));
00321         auto_ptr<tree_element> t3(load_a_tree(i, false));
00322         auto_ptr<tree_element> ret(new tree_element(t1.release(), t2.release(), t3.release(), offset)); 
00323 
00324         return ret.release();
00325 
00326     }
00327 }

tree_element* load_a_tree ( istream &  i  ) 

Parses a tree from an istream.

This will deserialize a tree serialized by tree_element::print(). On error, ParseError is thrown.

Parameters:
i The stream to parse
Returns:
An allocated tree. Ownership is passed to the callee.

Definition at line 334 of file faster_tree.cc.

References load_a_tree().

00335 {
00336     return load_a_tree(i, true);
00337 }

vector<ImageRef> transform_offsets ( const vector< ImageRef > &  offsets,
int  angle,
bool  r 
)

Rotate a vector<ImageRef> by a given angle, with an optional reflection.

Parameters:
offsets Offsets to rotate.
angle Angle to rotate by.
r Whether to reflect.
Returns:
The rotated offsets.

Definition at line 66 of file offsets.cc.

References ir_rounded().

Referenced by create_offsets().

00067 {
00068     double a = angle * M_PI / 2;    
00069 
00070     double R_[] = { cos(a), sin(a), -sin(a) , cos(a) };
00071     double F_[] = { 1, 0, 0, r?-1:1};
00072 
00073     Matrix<2> R(R_), F(F_);
00074     Matrix<2> T = R*F;
00075 
00076     vector<ImageRef> ret;
00077 
00078     for(unsigned int i=0; i < offsets.size(); i++)
00079     {
00080         Vector<2> v = vec(offsets[i]);
00081         ret.push_back(ir_rounded(T * v));
00082     }
00083     
00084     return ret;
00085 }

void create_offsets (  ) 

Create a list of offsets with various transformation to map the offset number (see Figure 7 in the accompanying paper) to a pixel coordinate, inclusing all combinations of rotation and reflection.

The function populates offsets, and must be called before anything uses this variable.

All possible offsets are selected in an annulus, which uses the following gvars:

Definition at line 156 of file offsets.cc.

Referenced by main(), and run_learn_detector().

00157 {
00158     //Pixel offsets are represented as integer indices in to an array of
00159     //ImageRefs. That means that by choosing the array, the tree can be
00160     //rotated and/or reflected. Here, an annulus of possible offsets is 
00161     //created and rotated by all multiples of 90 degrees, and then reflected.
00162     //This gives a total of 8.
00163     offsets.resize(8);
00164     {   
00165         double min_r = GV3::get<double>("offsets.min_radius");
00166         double max_r = GV3::get<double>("offsets.max_radius");
00167 
00168         ImageRef max((int)ceil(max_r+1), (int)ceil(max_r+1));
00169         ImageRef min = -max, p = min;
00170 
00171         //cout << "Offsets: ";
00172 
00173         do
00174         {
00175             double d = vec(p) * vec(p);
00176 
00177             if(d >= min_r*min_r && d <= max_r * max_r)
00178             {
00179                 offsets[0].push_back(p);
00180                 //cout << offsets[0].back() << " ";
00181             }
00182         }
00183         while(p.next(min, max));
00184 
00185     //  cout << endl;
00186 
00187         offsets_bbox = make_pair(min, max);
00188     }
00189     offsets[1] = transform_offsets(offsets[0], 1, 0);
00190     offsets[2] = transform_offsets(offsets[0], 2, 0);
00191     offsets[3] = transform_offsets(offsets[0], 3, 0);
00192     offsets[4] = transform_offsets(offsets[0], 0, 1);
00193     offsets[5] = transform_offsets(offsets[0], 1, 1);
00194     offsets[6] = transform_offsets(offsets[0], 2, 1);
00195     offsets[7] = transform_offsets(offsets[0], 3, 1);
00196     num_offsets=offsets[0].size();
00197 }


Variable Documentation

vector<vector<ImageRef> > offsets

Actual x,y offset of the offset numbers in the different available orientations.

Definition at line 49 of file offsets.cc.

Referenced by create_offsets(), tree_element::detect_corner(), tree_element::detect_corner_oriented(), draw_offsets(), extract_feature(), main(), tree_element::make_fast_detector(), and tree_element::make_fast_detector_o().

int num_offsets

The number of possible offsets.

Equivalent to offsets[x].size()

Definition at line 52 of file offsets.cc.

Referenced by create_offsets(), extract_feature(), learn_detector(), main(), and random_tree().

pair<ImageRef, ImageRef> offsets_bbox

Bounding box for offsets in all orientations.

This is therefore a bounding box for the detector.

Definition at line 55 of file offsets.cc.

Referenced by tree_element::bbox(), create_offsets(), and main().


Generated on Mon Mar 2 12:47:12 2009 for FAST-ER by  doxygen 1.5.3