Fawkes API Fawkes Development Version
simple.cpp
1
2/***************************************************************************
3 * simple.cpp - Implementation of a SimpleColorClassifier
4 *
5 * Created: Thu May 16 00:00:00 2005
6 * Copyright 2005-2007 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exceptions/software.h>
25#include <fvclassifiers/simple.h>
26#include <fvmodels/color/colormodel.h>
27#include <fvmodels/scanlines/scanlinemodel.h>
28#include <fvutils/color/color_object_map.h>
29#include <fvutils/color/colorspaces.h>
30#include <fvutils/color/yuv.h>
31
32#include <cstdlib>
33
34namespace firevision {
35
36/** @class SimpleColorClassifier <fvclassifiers/simple.h>
37 * Simple classifier.
38 */
39
40/** Constructor.
41 * @param scanline_model scanline model
42 * @param color_model color model
43 * @param min_num_points minimum number of points in ROI to be considered
44 * @param box_extent basic extent of a new ROI
45 * @param upward set to true if you have an upward scanline model, this means that
46 * points are traversed from the bottom to the top. In this case the ROIs are initially
47 * extended towards the top instead of the bottom.
48 * @param neighbourhood_min_match minimum number of object pixels to grow neighbourhood
49 * @param grow_by grow region by that many pixels
50 * @param color color to look for
51 */
53 ColorModel * color_model,
54 unsigned int min_num_points,
55 unsigned int box_extent,
56 bool upward,
57 unsigned int neighbourhood_min_match,
58 unsigned int grow_by,
59 color_t color)
60: Classifier("SimpleColorClassifier"), color(color)
61{
62 if (scanline_model == NULL) {
63 throw fawkes::NullPointerException("SimpleColorClassifier: scanline_model "
64 "may not be NULL");
65 }
66 if (color_model == NULL) {
67 throw fawkes::NullPointerException("SimpleColorClassifier: color_model "
68 "may not be NULL");
69 }
70
71 modified = false;
72 this->scanline_model = scanline_model;
73 this->color_model = color_model;
74 this->min_num_points = min_num_points;
75 this->box_extent = box_extent;
76 this->upward = upward;
77 this->grow_by = grow_by;
78 this->neighbourhood_min_match = neighbourhood_min_match;
79}
80
81unsigned int
82SimpleColorClassifier::consider_neighbourhood(unsigned int x, unsigned int y, color_t what)
83{
84 color_t c;
85 unsigned int num_what = 0;
86
87 unsigned char yp = 0, up = 0, vp = 0;
88 int start_x = -2, start_y = -2;
89 int end_x = 2, end_y = 2;
90
91 if (x < (unsigned int)abs(start_x)) {
92 start_x = 0;
93 }
94 if (y < (unsigned int)abs(start_y)) {
95 start_y = 0;
96 }
97
98 if (x > _width - end_x) {
99 end_x = 0;
100 }
101 if (y == _height - end_y) {
102 end_y = 0;
103 }
104
105 for (int dx = start_x; dx <= end_x; dx += 2) {
106 for (int dy = start_y; dy <= end_y; ++dy) {
107 if ((dx == 0) && (dy == 0)) {
108 continue;
109 }
110
111 // cout << "x=" << x << " dx=" << dx << " +=" << x+dx
112 // << " y=" << y << " dy=" << dy << " +2=" << y+dy << endl;
113
114 YUV422_PLANAR_YUV(_src, _width, _height, x + dx, y + dy, yp, up, vp);
115 c = color_model->determine(yp, up, vp);
116
117 if (c == what) {
118 ++num_what;
119 }
120 }
121 }
122
123 return num_what;
124}
125
126std::list<ROI> *
128{
129 if (_src == NULL) {
130 //cout << "SimpleColorClassifier: ERROR, src buffer not set. NOT classifying." << endl;
131 return new std::list<ROI>;
132 }
133
134 std::list<ROI> * rv = new std::list<ROI>();
135 std::list<ROI>::iterator roi_it, roi_it2;
136 color_t c;
137
138 unsigned int x = 0, y = 0;
139 unsigned char yp = 0, up = 0, vp = 0;
140 unsigned int num_what = 0;
141
142 ROI r;
143
144 scanline_model->reset();
145 while (!scanline_model->finished()) {
146 x = (*scanline_model)->x;
147 y = (*scanline_model)->y;
148
149 YUV422_PLANAR_YUV(_src, _width, _height, x, y, yp, up, vp);
150
151 c = color_model->determine(yp, up, vp);
152
153 if (color == c) {
154 // Yeah, found a ball, make it big and name it a ROI
155 // Note that this may throw out a couple of ROIs for just one ball,
156 // as the name suggests this one is really ABSOLUTELY simple and not
157 // useful for anything else than quick testing
158
159 if (neighbourhood_min_match) {
160 num_what = consider_neighbourhood((*scanline_model)->x, (*scanline_model)->y, c);
161 }
162 if (num_what >= neighbourhood_min_match) {
163 bool ok = false;
164
165 for (roi_it = rv->begin(); roi_it != rv->end(); ++roi_it) {
166 if ((*roi_it).contains(x, y)) {
167 // everything is fine, this point is already in another ROI
168 ok = true;
169 break;
170 }
171 }
172 if (!ok) {
173 for (roi_it = rv->begin(); roi_it != rv->end(); ++roi_it) {
174 if ((*roi_it).neighbours(x, y, scanline_model->get_margin())) {
175 // ROI is neighbour of this point, extend region
176 (*roi_it).extend(x, y);
177 ok = true;
178 break;
179 }
180 }
181 }
182
183 if (!ok) {
184 if (upward) {
185 if (x < box_extent) {
186 x = 0;
187 } else {
188 x -= box_extent;
189 }
190 if (y < box_extent) {
191 y = 0;
192 } else {
193 y -= box_extent;
194 }
195 }
196 r.start.x = x;
197 r.start.y = y;
198
199 unsigned int to_x = (*scanline_model)->x + box_extent;
200 unsigned int to_y = (*scanline_model)->y + box_extent;
201 if (to_x > _width)
202 to_x = _width;
203 if (to_y > _height)
204 to_y = _height;
205 r.width = to_x - r.start.x;
206 r.height = to_y - r.start.y;
207 r.hint = c;
208 r.color = c;
209
210 r.line_step = _width;
211 r.pixel_step = 1;
212
215
216 if ((r.start.x + r.width) > _width) {
217 r.width -= (r.start.x + r.width) - _width;
218 }
219 if ((r.start.y + r.height) > _height) {
220 r.height -= (r.start.y + r.height) - _height;
221 }
222
223 rv->push_back(r);
224 }
225 } // End if enough neighbours
226 } // end if is orange
227
228 ++(*scanline_model);
229 }
230
231 // Grow regions
232 if (grow_by > 0) {
233 for (roi_it = rv->begin(); roi_it != rv->end(); ++roi_it) {
234 (*roi_it).grow(grow_by);
235 }
236 }
237
238 // Merge neighbouring regions
239 for (roi_it = rv->begin(); roi_it != rv->end(); ++roi_it) {
240 roi_it2 = roi_it;
241 ++roi_it2;
242
243 while (roi_it2 != rv->end()) {
244 if ((roi_it != roi_it2) && roi_it->neighbours(&(*roi_it2), scanline_model->get_margin())) {
245 *roi_it += *roi_it2;
246 rv->erase(roi_it2);
247 roi_it2 = rv->begin(); //restart
248 } else {
249 ++roi_it2;
250 }
251 }
252 }
253
254 // Throw away all ROIs that have not enough classified points
255 for (roi_it = rv->begin(); roi_it != rv->end(); ++roi_it) {
256 while ((roi_it != rv->end()) && ((*roi_it).num_hint_points < min_num_points)) {
257 roi_it = rv->erase(roi_it);
258 }
259 }
260
261 // sort ROIs by number of hint points, descending (and thus call reverse)
262 rv->sort();
263 rv->reverse();
264
265 return rv;
266}
267
268/** Get mass point of primary color.
269 * @param roi ROI to consider
270 * @param massPoint contains mass point upon return
271 */
272void
274{
275 unsigned int nrOfOrangePixels;
276 nrOfOrangePixels = 0;
277 massPoint->x = 0;
278 massPoint->y = 0;
279
280 // for accessing ROI pixels
281 unsigned int h = 0;
282 unsigned int w = 0;
283 // planes
284 unsigned char *yp = _src + (roi->start.y * roi->line_step) + (roi->start.x * roi->pixel_step);
285 unsigned char *up =
286 YUV422_PLANAR_U_PLANE(_src, roi->image_width, roi->image_height)
287 + ((roi->start.y * roi->line_step) / 2 + (roi->start.x * roi->pixel_step) / 2);
288 unsigned char *vp =
289 YUV422_PLANAR_V_PLANE(_src, roi->image_width, roi->image_height)
290 + ((roi->start.y * roi->line_step) / 2 + (roi->start.x * roi->pixel_step) / 2);
291 // line starts
292 unsigned char *lyp = yp;
293 unsigned char *lup = up;
294 unsigned char *lvp = vp;
295
296 color_t dcolor;
297
298 // consider each ROI pixel
299 for (h = 0; h < roi->height; ++h) {
300 for (w = 0; w < roi->width; w += 2) {
301 // classify its color
302 dcolor = color_model->determine(*yp++, *up++, *vp++);
303 yp++;
304 // ball pixel?
305 if (color == dcolor) {
306 // take into account its coordinates
307 massPoint->x += w;
308 massPoint->y += h;
309 nrOfOrangePixels++;
310 }
311 }
312 // next line
313 lyp += roi->line_step;
314 lup += roi->line_step / 2;
315 lvp += roi->line_step / 2;
316 yp = lyp;
317 up = lup;
318 vp = lvp;
319 }
320
321 // to obtain mass point, divide by number of pixels that were added up
322 massPoint->x = (unsigned int)(float(massPoint->x) / float(nrOfOrangePixels));
323 massPoint->y = (unsigned int)(float(massPoint->y) / float(nrOfOrangePixels));
324
325 /* shift mass point
326 such that it is relative to image
327 (not relative to ROI) */
328 massPoint->x += roi->start.x;
329 massPoint->y += roi->start.y;
330}
331
332} // end namespace firevision
A NULL pointer was supplied where not allowed.
Definition: software.h:32
Classifier to extract regions of interest.
Definition: classifier.h:36
unsigned int _height
Height in pixels of _src buffer.
Definition: classifier.h:53
unsigned char * _src
Source buffer, encoded as YUV422_PLANAR.
Definition: classifier.h:49
unsigned int _width
Width in pixels of _src buffer.
Definition: classifier.h:51
Color model interface.
Definition: colormodel.h:32
virtual color_t determine(unsigned int y, unsigned int u, unsigned int v) const =0
Determine classification of YUV pixel.
Region of interest.
Definition: roi.h:55
unsigned int height
ROI height.
Definition: roi.h:119
fawkes::upoint_t start
ROI start.
Definition: roi.h:115
unsigned int line_step
line step
Definition: roi.h:125
unsigned int width
ROI width.
Definition: roi.h:117
unsigned int hint
ROI hint.
Definition: roi.h:129
unsigned int image_width
width of image that contains this ROI
Definition: roi.h:121
color_t color
ROI primary color.
Definition: roi.h:132
unsigned int pixel_step
pixel step
Definition: roi.h:127
unsigned int image_height
height of image that contains this ROI
Definition: roi.h:123
Scanline model interface.
Definition: scanlinemodel.h:53
virtual void get_mass_point_of_color(ROI *roi, fawkes::upoint_t *massPoint)
Get mass point of primary color.
Definition: simple.cpp:273
virtual std::list< ROI > * classify()
Classify image.
Definition: simple.cpp:127
SimpleColorClassifier(ScanlineModel *scanline_model, ColorModel *color_model, unsigned int min_num_points=6, unsigned int box_extent=50, bool upward=false, unsigned int neighbourhood_min_match=8, unsigned int grow_by=10, color_t color=C_ORANGE)
Constructor.
Definition: simple.cpp:52
Point with cartesian coordinates as unsigned integers.
Definition: types.h:35
unsigned int x
x coordinate
Definition: types.h:36
unsigned int y
y coordinate
Definition: types.h:37