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_element * | load_a_tree (istream &i, bool eq_branch) |
tree_element * | load_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 |
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:
debug.verify_detections
Veryify JIT or bytecode detected corners using tree_element::detect_corner
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:
debug.verify_detections
Veryify JIT or bytecode detected corners using tree_element::detect_cornerdebug.verify_scores
Veryify bytecode computed scores using tree_element::detect_corner
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.
i | The stream to parse | |
eq_branch | Is it an EQ branch? Check the invariant. |
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.
i | The stream to parse |
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.
offsets | Offsets to rotate. | |
angle | Angle to rotate by. | |
r | Whether to reflect. |
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:
offsets.min_radius
Minimum distance from (0,0) for offsetoffsets.max_radius
Maximum distance from (0,0) for offset 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 }
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().