00001 /* 00002 00003 This file is part of the FAST-ER machine learning system. 00004 Copyright (C) 2008 Edward Rosten and Los Alamos National Laboratory 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License along 00017 with this program; if not, write to the Free Software Foundation, Inc., 00018 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00019 */ 00020 #ifndef FASTER_BYTECODE_H 00021 #define FASTER_BYTECODE_H 00022 00023 #include <vector> 00024 #include <climits> 00025 #include <cstdlib> 00026 #include <iostream> 00027 #include <cvd/byte.h> 00028 #include <cvd/image.h> 00029 #include <tag/stdpp.h> 00030 00031 /// This struct contains a byte code compiled version of the detector. 00032 /// 00033 /// 00034 /// @ingroup gFastTree 00035 struct block_bytecode 00036 { 00037 00038 /// This is a bytecode element for the bytecode-compiled 00039 /// detector. The bytecode consists of a number of fixed length 00040 /// blocks representing a 3 way branch. Special values of 00041 /// of a block indicate the result that a pixel is a corner or 00042 /// non-corner. 00043 /// 00044 /// Specifically, if <code>lt == 0</code>, then this is a leaf and \c gt holds the class. 00045 /// The root node is always stored as the first bytecode instruction. 00046 00047 /// @ingroup gFastTree 00048 struct fast_detector_bit 00049 { 00050 int offset; ///< Memory offset from centre pixel to examine. This means that the fast 00051 ///detector must be created for an image of a known width. 00052 00053 //Root node is 0. If lt == 0, then this is a leaf. 00054 //gt holds the class. 00055 00056 int lt; ///<Position in bytecode to branch to if offset pixel is much darker than the centre pixel. If this 00057 ///is zero, then gt stores the result. 00058 int gt; ///<Position in bytecode to branch to if offset pixel is much brighter than the centre pixel. If lt==0 00059 ///is a result block, then this stores the result, 0 for a non corner, 1 for a corner. 00060 int eq; ///<Position in bytecode to branch to otherwise. 00061 }; 00062 00063 00064 std::vector<fast_detector_bit> d; ///<This contains the compiled bytecode. 00065 00066 ///Detects a corner at a given pointer, without the book keeping required to compute the score. 00067 ///This is quite a lot faster than @ref detect. 00068 /// 00069 ///@param imp Pointer at which to detect corner 00070 ///@param b FAST barrier 00071 ///@return is a corner or not 00072 inline bool detect_no_score(const CVD::byte* imp, int b) const 00073 { 00074 int n=0; 00075 int cb = *imp + b; 00076 int c_b = *imp - b; 00077 int p; 00078 00079 while(d[n].lt) 00080 { 00081 p = imp[d[n].offset]; 00082 00083 if(p > cb) 00084 n = d[n].gt; 00085 else if(p < c_b) 00086 n = d[n].lt; 00087 else 00088 n = d[n].eq; 00089 } 00090 00091 return d[n].gt; 00092 } 00093 00094 ///Detects a corner at a given pointer, with book-keeping required for score computation 00095 /// 00096 ///@param imp Pointer at which to detect corner 00097 ///@param b FAST barrier 00098 ///@return 0 for non-corner, minimum increment required to make detector go down different branch, if it is a corner. 00099 inline int detect(const CVD::byte* imp, int b) const 00100 { 00101 int n=0; 00102 int m = INT_MAX; 00103 int cb = *imp + b; 00104 int c_b = *imp - b; 00105 int p; 00106 00107 while(d[n].lt) 00108 { 00109 p = imp[d[n].offset]; 00110 00111 if(p > cb) 00112 { 00113 if(p-cb < m) 00114 m = p-cb; 00115 00116 n = d[n].gt; 00117 } 00118 else if(p < c_b) 00119 { 00120 if(c_b - p < m) 00121 m = c_b - p; 00122 00123 n = d[n].lt; 00124 } 00125 else 00126 n = d[n].eq; 00127 } 00128 00129 if(d[n].gt) 00130 return m; 00131 else 00132 return 0; 00133 } 00134 00135 ///Serialize the detector to an ostream. The serialized detector a number of lines 00136 ///of the form: 00137 ///@code 00138 ///Block N [X Y] G E L 00139 ///@endcode 00140 ///or: 00141 ///@code 00142 ///Block N corner 00143 ///@endcode 00144 ///or: 00145 ///@code 00146 ///Block N non_corner 00147 ///@endcode 00148 ///The first block type represents the code: 00149 ///@code 00150 ///if Image[current_pixel + (x, y)] > Image[current_pixel] + threshold 00151 /// goto block G 00152 ///elseif Image[current_pixel + (x, y)] < Image[current_pixel] -threshold 00153 /// goto block L 00154 ///else 00155 /// goto block E 00156 ///endif 00157 ///@endcode 00158 ///@param o ostream for output 00159 ///@param width width the detector was created at, required to back out the offsets correctly. 00160 void print(std::ostream& o, int width) const 00161 { 00162 using tag::operator<<; 00163 for(unsigned int i=0; i < d.size(); i++) 00164 { 00165 if(d[i].lt == 0) 00166 o << tag::print << "Block" << i << (d[i].gt?"corner":"non_corner"); 00167 else 00168 { 00169 int a = abs(d[i].offset) + width / 2; 00170 if(d[i].offset < 0) 00171 a = -a; 00172 int y = a / width; 00173 00174 int x = d[i].offset - y * width; 00175 o << tag::print << "Block" << i << CVD::ImageRef(x , y) << d[i].gt << d[i].eq << d[i].lt; 00176 } 00177 } 00178 } 00179 00180 void detect(const CVD::Image<CVD::byte>& im, std::vector<int>& corners, int threshold, int xmin, int xmax, int ymin, int ymax); 00181 }; 00182 00183 #endif