Fawkes API Fawkes Development Version
|
00001 /*************************************************************************** 00002 * gradient.h - Class defining a gradient (color) classifier 00003 * 00004 * Created: Tue Jun 10 11:48:00 2008 00005 * Copyright 2008 Christof Rath <christof.rath@gmail.com> 00006 * 00007 ****************************************************************************/ 00008 00009 /* This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. A runtime exception applies to 00013 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00021 */ 00022 00023 #include "gradient.h" 00024 #include <core/exceptions/software.h> 00025 00026 using std::list; 00027 using std::iterator; 00028 00029 using fawkes::point_t; 00030 00031 namespace firevision { 00032 #if 0 /* just to make Emacs auto-indent happy */ 00033 } 00034 #endif 00035 00036 /** @class GradientClassifier <classifiers/gradient.h> 00037 * Gradient classifier. 00038 * Uses the difference of the current and the last value. 00039 */ 00040 00041 /** Constructor. 00042 * @param scanlines list of scanline models (Does only work with ScanlineGrid) 00043 * @param q Qualifier for a single pixel (The qualifier gets deleted by this class) 00044 * @param threshold minimum rise required for classification 00045 * @param max_size of an object to be detected (if 0 value will be ignored) 00046 * @param use_rising_flank 00047 * if true the classification can start on a rising flank 00048 * @param use_falling_flank 00049 * if true the classification can start on a falling flank 00050 */ 00051 GradientClassifier::GradientClassifier(std::list<ScanlineGrid* >* scanlines, 00052 Qualifier* q, 00053 unsigned int threshold, unsigned int max_size, 00054 bool use_rising_flank, bool use_falling_flank) 00055 : Classifier("GradientClassifier") 00056 { 00057 if (!scanlines) 00058 throw fawkes::NullPointerException("GradientClassifier: scanlines may not be null!"); 00059 if (!q) 00060 throw fawkes::NullPointerException("GradientClassifier: the Qualifier may not be null!"); 00061 00062 _scanlines = scanlines; 00063 _q = q; 00064 00065 _max_size = 999999; //Infinite... 00066 set_threshold(threshold, max_size); 00067 set_edges(use_rising_flank, use_falling_flank); 00068 } 00069 00070 /** Destructor. 00071 */ 00072 GradientClassifier::~GradientClassifier() 00073 { 00074 if (_q) 00075 delete _q; 00076 } 00077 00078 /** Threshold setter. 00079 * @param threshold minimum rise required for classification 00080 * @param max_size of an object to be detected (if 0 value will not be set) 00081 */ 00082 void 00083 GradientClassifier::set_threshold(unsigned int threshold, unsigned int max_size) 00084 { 00085 _threshold = threshold; 00086 00087 if (max_size) 00088 _max_size = max_size; 00089 } 00090 00091 /** Edge setter. 00092 * @param use_rising_edge 00093 * if true the classification can start on a rising edge 00094 * @param use_falling_edge 00095 * if true the classification can start on a falling edge 00096 */ 00097 void 00098 GradientClassifier::set_edges(bool use_rising_edge, bool use_falling_edge) 00099 { 00100 _use_rising_edge = use_rising_edge; 00101 _use_falling_edge = use_falling_edge; 00102 } 00103 00104 /** Set source buffer. 00105 * @param yuv422_planar a YUV422 planar buffer with the source image to 00106 * classify. The classifier may NOT modify the image in any way. If that is 00107 * required the classifier shall make a copy of the image. 00108 * @param width width of buffer in pixels 00109 * @param height height of buffer in pixels 00110 */ 00111 void 00112 GradientClassifier::set_src_buffer(unsigned char *yuv422_planar, 00113 unsigned int width, unsigned int height) 00114 { 00115 Classifier::set_src_buffer(yuv422_planar, width, height); 00116 00117 _q->set_buffer(yuv422_planar, width, height); 00118 } 00119 00120 std::list< ROI > * 00121 GradientClassifier::classify() 00122 { 00123 if (_q->get_buffer() == NULL) 00124 { 00125 //cout << "GradientClassifier: ERROR, src buffer not set. NOT classifying." << endl; 00126 return new std::list< ROI >; 00127 } 00128 00129 list< ROI > *rv = new list< ROI >; 00130 int cur_val, cur_diff, direction = 0; 00131 point_t cur_pos, edge_start; 00132 cur_pos.x = cur_pos.y = edge_start.x = edge_start.y = 0; 00133 00134 unsigned int jumpSize = 0; 00135 00136 ROI current; 00137 00138 for (list<ScanlineGrid*>::iterator it = _scanlines->begin(); it != _scanlines->end(); it++) 00139 { 00140 ScanlineGrid* slm = (*it); 00141 slm->reset(); 00142 00143 _last_pos = *(*slm); 00144 _last_val = _q->get(_last_pos); 00145 00146 while(!slm->finished()) 00147 { 00148 cur_pos = *(++(*slm)); 00149 cur_val = _q->get(cur_pos); 00150 cur_diff = cur_val - _last_val; 00151 00152 if ((cur_pos.x < _last_pos.x || cur_pos.y < _last_pos.y) //new scan line 00153 || (current.pixel_step && ((cur_pos.x - current.start.x) > _max_size //area found is too big 00154 || (cur_pos.y - current.start.y) > _max_size))) 00155 { 00156 current.set_pixel_step(0); 00157 00158 edge_start.x = edge_start.y = direction = jumpSize = 0; 00159 } 00160 00161 int curDir = (cur_diff < 0 ? -1 : (cur_diff > 0 ? 1 : 0)); 00162 switch (curDir) 00163 { 00164 case -1: 00165 switch (direction) 00166 { 00167 case -1: //drop continues 00168 jumpSize -= cur_diff; 00169 break; 00170 case 0: //new drop 00171 jumpSize = -cur_diff; 00172 edge_start = cur_pos; 00173 break; 00174 case 1: 00175 if (jumpSize < _threshold)//spike reset ramp 00176 { 00177 jumpSize = -cur_diff; 00178 edge_start = cur_pos; 00179 } 00180 else // found edge! 00181 { 00182 if (current.pixel_step) //this is a line end 00183 { 00184 current.set_width(_last_pos.x - current.start.x); 00185 current.set_height(_last_pos.y - current.start.y); 00186 00187 rv->push_back(ROI(current)); 00188 00189 current.set_pixel_step(0); 00190 } 00191 else if (_use_falling_edge) 00192 { 00193 current.set_pixel_step(1); 00194 current.set_start(edge_start); 00195 } 00196 00197 edge_start = cur_pos; 00198 jumpSize = -cur_diff; 00199 } 00200 break; 00201 } 00202 direction = -1; 00203 break; 00204 00205 00206 case 0: 00207 switch (direction) 00208 { 00209 case -1: //ramp end 00210 case 1: //ramp end 00211 if (jumpSize >= _threshold) //found edge! 00212 { 00213 if (current.pixel_step) //this is a line end 00214 { 00215 current.set_width(_last_pos.x - current.start.x); 00216 current.set_height(_last_pos.y - current.start.y); 00217 00218 rv->push_back(ROI(current)); 00219 00220 current.set_pixel_step(0); 00221 } 00222 else 00223 { 00224 if ((_use_falling_edge && direction == 1) || (_use_rising_edge && direction == -1)) 00225 { 00226 current.set_pixel_step(1); 00227 current.set_start(edge_start); 00228 } 00229 } 00230 } 00231 break; 00232 00233 case 0: 00234 break; 00235 } 00236 direction = jumpSize = 0; 00237 edge_start.x = edge_start.y = 0; 00238 break; 00239 00240 00241 case 1: 00242 switch (direction) 00243 { 00244 case 1: //climb continues 00245 jumpSize += cur_diff; 00246 break; 00247 case 0: //new climb 00248 jumpSize = cur_diff; 00249 edge_start = cur_pos; 00250 break; 00251 case -1: 00252 if (jumpSize < _threshold)//spike reset ramp 00253 { 00254 jumpSize = cur_diff; 00255 edge_start = cur_pos; 00256 } 00257 else // found edge! 00258 { 00259 if (current.pixel_step) //this is a line end 00260 { 00261 current.set_width(_last_pos.x - current.start.x); 00262 current.set_height(_last_pos.y - current.start.y); 00263 00264 rv->push_back(ROI(current)); 00265 00266 current.set_pixel_step(0); 00267 } 00268 else if (_use_rising_edge) 00269 { 00270 current.set_pixel_step(1); 00271 current.set_start(edge_start); 00272 } 00273 00274 edge_start = cur_pos; 00275 jumpSize = cur_diff; 00276 } 00277 break; 00278 } 00279 direction = 1; 00280 break; 00281 } 00282 00283 00284 _last_val = cur_val; 00285 _last_pos = cur_pos; 00286 } 00287 } //END: For all scanline models 00288 00289 return rv; 00290 } 00291 00292 } // end namespace firevision