Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
LEDDetector.cpp
1 #include "LEDDetector.hh"
2 #include <Base/Image/ImageConvert.hh>
3 
4 using namespace std;
5 using namespace BIAS;
6 
7 #define MASK_X 17 // filter size
8 #define RADIUS_SPOT_RANGE 70 // max. space between spots
9 #define MASK_WHATISMINBRIGHT 150 // gray values for thresholding
10 #define MASK_WAHTISMAXDARK 50 // gray values for thresholding
11 
12 LEDDetector::
13 LEDDetector()
14 {
15  lookup = NULL;
16  lookupsize = 0;
17 }
18 
19 LEDDetector::
20 ~LEDDetector()
21 {
22  if (lookup) delete[] lookup;
23 }
24 
25 void LEDDetector::
26 GetNeighbours(std::vector<std::vector<BIAS::Vector3<double> > > &neighbours)
27 {
28  neighbours = nextpixel;
29 }
30 
31 void LEDDetector::
32 GetAttributes (std::vector<double> &minX, std::vector<double> &maxX,
33  std::vector<double> &maxValues)
34 {
35  minX = minxcoords;
36  maxX = maxxcoords;
37  maxValues = maxvalues;
38 }
39 
40 int LEDDetector::Compute(const BIAS::Image<unsigned char> &image,
41  std::vector<BIAS::Vector3<double> > &results)
42 {
43  if (!results.empty()) {
44  resultpixel_old.clear();
45  for (unsigned int i = 0; i < results.size(); i++) {
46  resultpixel_old.push_back(results[i]);
47  }
48  }
49 
51  BIAS::ImageConvert::ToGrey(image, tmpImage);
52  BIAS::ImageConvert::BIAS2ipl(tmpImage, gray_threshold);
53  BIAS::ImageConvert::BIAS2ipl(tmpImage, gray_orig);
54 
55  // initialize data
56  width = gray_threshold->width;
57  height = gray_threshold->height;
58  if (lookupsize < width * height) {
59  delete[] lookup;
60  lookupsize = width * height;
61  lookup = new unsigned char[lookupsize];
62  }
63  memset(lookup, 0, width * height * sizeof(unsigned char));
64  minxcoords.clear();
65  maxxcoords.clear();
66  maxvalues.clear();
67 
68  CvScalar m = cvAvg(gray_orig, NULL);
69  mean = (double)m.val[0];
70  //mean = cvMean(gray_orig, 0);
71  cvThreshold(gray_orig, gray_threshold, 210, 255, CV_THRESH_BINARY);
72  step = gray_threshold->widthStep / sizeof(unsigned char);
73  data = (unsigned char *)gray_threshold->imageData;
74  resultpixel.clear();
75 
76  int res = 0;
77  if (!resultpixel_old.empty())
78  res = Recycle_();
79  if (res != 0 || resultpixel_old.empty())
80  TemplateMatching_();
81  results = resultpixel;
82 
83  // release data
84  tmpImage.Release();
85  cvReleaseImage(&gray_threshold);
86  cvReleaseImage(&gray_orig);
87 
88  return res;
89 }
90 
91 int LEDDetector::Recycle_()
92 {
93  bool foundatold = false;
94  bool foundnn = true;
95  for (unsigned int i = 0; i < resultpixel_old.size(); i++) {
96  if (foundnn) {
97  // if value in gray image is white and the loopup array is black
98  BIAS::Vector3<double> f = resultpixel_old[i];
99  int fx = (int)f[0], fy = (int)f[1];
100  if (data[fy*step + fx] > mean-10 && lookup[fy*width+fx] == 0) {
101  // find new neighbourhood
102  Search_(fx, fy);
103  } else {
104  // if not a spot anymore
105  foundatold = true;
106  // check the pixel of neighborhood to find a bright pixel
107  int a = -1, b = -1;
108  int res = CheckNeighboursIfWhite_(fx, fy, a, b);
109  if (res == 0 && a != -1 && b != -1) {
110  Search_(a, b);
111  } else {
112  foundatold = false;
113  }
114  if (res == -1) {
115  foundnn = false;
116  foundatold = false;
117  }
118  }
119  }
120  }
121  resultpixel_old.clear();
122  return (!foundatold && !foundnn) ? -1 : 0;
123 }
124 
125 int LEDDetector:: CheckNeighboursIfWhite_(int x, int y, int& a, int& b)
126 {
127  int h = 1;
128  bool found = false;
129  while (!found && h < 100) { // @todo use maxblobsize instead?
130  int res = CheckNeighboursIfWhite_inter_(x+h, y);
131  if (res == 0) {
132  found = true; a = x+h; b=y;
133  } else {
134  res = CheckNeighboursIfWhite_inter_(x+h, y-h);
135  if (res == 0) {
136  found = true; a = x+h; b=y-h;
137  } else {
138  res = CheckNeighboursIfWhite_inter_(x+h, y+h);
139  if (res == 0) {
140  found = true; a = x+h; b=y+h;
141  } else {
142  res = CheckNeighboursIfWhite_inter_(x, y+h);
143  if (res == 0) {
144  found = true; a = x; b = y+h;
145  } else {
146  res = CheckNeighboursIfWhite_inter_(x, y-h);
147  if (res == 0) {
148  found = true; a = x; b = y-h;
149  } else {
150  res = CheckNeighboursIfWhite_inter_(x-h, y+h);
151  if (res == 0) {
152  found = true; a=x-h;b=y+h;
153  } else {
154  res = CheckNeighboursIfWhite_inter_(x-h, y);
155  if (res == 0) {
156  found = true; a = x-h; b=y;
157  } else {
158  res = CheckNeighboursIfWhite_inter_(x-h, y-h);
159  if (res == 0) {
160  found = true; a = x-h; b = y-h;
161  }
162  }
163  }
164  }
165  }
166  }
167  }
168  }
169  h++;
170  }
171  return found ? 0 : -1;
172 }
173 
174 int LEDDetector::CheckNeighboursIfWhite_inter_(int x, int y)
175 {
176  if (x > 0 && y > 0 && x < (gray_threshold->width)-1 && y < (gray_threshold->height)-1)
177  if (data[y*step+x] > MASK_WHATISMINBRIGHT && lookup[y*width+x] == 0)
178  return 0;
179  return -1;
180 }
181 
182 void LEDDetector::Search_(int x, int y)
183 {
184  if (lookup[y*width+x] == 0) {
185  recursivedepth = 0;
186  minx = 2000;
187  maxx = 0;
188  maxvalue = 0;
189  count = 0;
190  pixelweightvaluex = 0;
191  pixelweightvaluey = 0;
192  valuesum = 0;
193  blobsize = 0;
194 
195  int res = CheckNeighbours_(x, y);
196  if (res == 0) {
197  minxcoords.push_back(minx);
198  maxxcoords.push_back(maxx);
199  maxvalues.push_back(maxvalue);
200 
202  double o = pixelweightvaluex / count; // = width
203  double p = pixelweightvaluey / count; // = height
204  double u = valuesum / count;
205  valuesum = 0;
206  o = o / u;
207  p = p / u;
208  erg[0] = p;
209  erg[1] = o;
210 
211  //double b, c;
212  //c = modf(muex, &b); muex=b; if (c > 0.5) muex++;
213 
214  int g = int(o);
215  double d = o - g;
216  if (d > 0.5) g++;
217  int h = int(p);
218  d = p - h;
219  if (d > 0.5) h++;
220  CvScalar w = cvGet2D(gray_orig, g, h);
221  erg[2] = (double)w.val[0];
222  CvScalar n;
223  n.val[0] = 255; n.val[1] = 0; n.val[2] = 0; n.val[3] = 0;
224  cvSet2D(gray_threshold, g, h, n);
225  lookup[y*width+x] = 255;
226  nextpixel.push_back(whitepixel);
227  whitepixel.clear();
228  resultpixel.push_back(erg);
229  whitepixel.clear();
230  }
231  }
232 }
233 
234 int LEDDetector::CheckNeighbours_(int x, int y)
235 {
236  recursivedepth++;
237  if (recursivedepth < 1000 && blobsize < 100) {
238  if (x > 0 && y > 0 && x < (gray_threshold->width)-1 && y < (gray_threshold->height)-1) {
239  if (data[y*step+x]> MASK_WAHTISMAXDARK && lookup[y*width+x] == 0) {
240  if (x < minx)
241  minx = x;
242  if (x > maxx)
243  maxx = x;
244  blobsize++;
245  lookup[y*width+x] = 127;
247  a[0] = x;
248  a[1] = y;
249  double value;
250  CvScalar s = cvGet2D(gray_orig, y, x);
251  value = s.val[0];
252  a[2]= value;
253  valuesum += value;
254  if (value > maxvalue)
255  maxvalue = value;
256 
257  // set size, request max. value, backup
258  whitepixel.push_back(a);
259  count++;
260  pixelweightvaluex+=value*y;
261  pixelweightvaluey+=value*x;
262 
263  CheckNeighbours_( x-1, y);
264  CheckNeighbours_( x+1, y);
265  CheckNeighbours_( x, y-1);
266  CheckNeighbours_( x, y+1);
267  }
268  }
269  return 0;
270  }
271  return -1;
272 }
273 
274 void LEDDetector::TemplateMatching_()
275 {
276  // no recycling possible or first run, search pixel by pixel in whole image
277  int y = gray_threshold->height;
278  int x = gray_threshold->width*gray_threshold->nChannels;
279  int s = (MASK_X-1) / 2;
280  for (int i = s; i < y-s; i+=2) {
281  for (int j = s; j < x-s; j+=2) {
282  blobs = 0;
283  bool repeat = true;
284  int inside = 0;
285  if (data[i*step+j] > MASK_WAHTISMAXDARK && lookup[i*width+j] == 0){
286  int xh = i-s;
287  int xd = i+s;
288  int yh = j-s;
289  int yd = j+s;
290  for (; xh < xd; xh++) {
291  // if not black outside
292  if (data[xh*step+yh] > MASK_WAHTISMAXDARK) {
293  repeat = false;
294  break;
295  }
296  }
297  if (repeat) {
298  for (; yh < yd; yh++) {
299  if (data[xh*step+yh] > MASK_WAHTISMAXDARK) {
300  repeat = false;
301  break;
302  }
303  }
304  if (repeat) {
305  xd = i - s;
306  if (repeat) {
307  for (; xh > xd; xh--) {
308  if (data[xh*step+yh] > MASK_WAHTISMAXDARK) {
309  repeat = false;
310  break;
311  }
312  }
313  yd = j-s;
314  if (repeat) {
315  for (; yh > yd; yh--) {
316  if (data[xh*step+yh] > MASK_WAHTISMAXDARK) {
317  repeat = false;
318  break;
319  }
320  }
321  if (repeat) {
322  // if white inside
323  for (int t = -3; t < 5; t++) {
324  for (int r = -3; r < 5; r++) {
325  if (data[(i+r)*step+(j+t)] > MASK_WAHTISMAXDARK) {
326  inside++;
327  }
328  }
329  }
330  }
331  }
332  }
333  }
334  }
335  }
336  if (repeat && inside > 3) {
337  // if not bright anymore search for neighbours
338  Search_(j,i);
339  lookup[i*width+j] = 255;
340  inside = 0;
341  }
342  }
343  }
344 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
void clear()
stl conform interface
Definition: Vector3.hh:564
static int BIAS2ipl(const Image< StorageType > &source, IplImage *&dest)
Returns a new, separate IplImage for use with OpenCV created rom the source BIAS Image.
static int ToGrey(const ImageBase &source, ImageBase &dest)
wrapper for the templated function ToGrey