source: trunk/MagicSoft/Cosy/videodev/FilterLed.cc@ 9076

Last change on this file since 9076 was 8869, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 12.2 KB
Line 
1#include "FilterLed.h"
2
3#include <memory.h> // memset
4#include <iostream> // cout
5
6#include "Led.h"
7#include "Leds.h"
8#include "Ring.h"
9
10#include "MGMap.h"
11
12ClassImp(FilterLed);
13
14using namespace std;
15
16class ClusterFinder
17{
18private:
19 byte *fImg;
20
21 UInt_t fW;
22 UInt_t fH;
23
24 Int_t fX0;
25 Int_t fX1;
26
27 Int_t fY0;
28 Int_t fY1;
29
30 UInt_t fLimitingSize;
31
32 UInt_t fCount;
33 Float_t fSumX;
34 Float_t fSumY;
35
36 Float_t FindCluster(Int_t x, Int_t y)
37 {
38 // if edge is touched stop finding cluster
39 if (x<fX0 || x>=fX1 || y<fY0 || y>=fY1)
40 return -1;
41
42 if (fCount>fLimitingSize)
43 return -2;
44
45 // get the value
46 Float_t val = fImg[y*fW+x];
47
48 // if its empty we have found the border of the cluster
49 if (val==0)
50 return 0;
51
52 // mark the point as processed
53 fImg[y*fW+x] = 0;
54
55 fSumX += x*val; // sumx
56 fSumY += y*val; // sumy
57 fCount++;
58
59 Float_t rc[4];
60 rc[0] = FindCluster(x+1, y );
61 rc[1] = FindCluster(x, y+1);
62 rc[2] = FindCluster(x-1, y );
63 rc[3] = FindCluster(x, y-1);
64
65 for (int i=0; i<4; i++)
66 {
67 if (rc[i]<0) // check if edge is touched
68 return rc[i];
69
70 val += rc[i];
71 }
72
73 return val;
74 }
75
76public:
77 ClusterFinder(byte *img, UInt_t w, UInt_t h) : fImg(0), fLimitingSize(999)
78 {
79 fW = w;
80 fH = h;
81
82 fX0 = 0;
83 fY0 = 0;
84 fX1 = fW;
85 fY1 = fH;
86
87 fImg = new byte[fW*fH];
88
89 memcpy(fImg, img, fW*fH);
90 }
91
92 ~ClusterFinder()
93 {
94 delete [] fImg;
95 }
96 Double_t GetSumX() const { return fSumX; }
97 Double_t GetSumY() const { return fSumY; }
98
99 UInt_t GetCount() const { return fCount; }
100
101 void SetLimitingSize(UInt_t lim) { fLimitingSize=lim; }
102
103 Float_t FindClusterAt(Int_t x, Int_t y)
104 {
105 fCount = 0;
106 fSumX = 0;
107 fSumY = 0;
108
109 return FindCluster(x, y);
110 }
111
112 void SetRange(Int_t x0=0, Int_t y0=0, Int_t x1=0, Int_t y1=0)
113 {
114 fX0 = x0;
115 fY0 = y0;
116 fX1 = x1==0?fW:x1;
117 fY1 = y1==0?fH:y1;
118 }
119
120 void FindCluster(Leds &leds, Int_t x0=0, Int_t y0=0, Int_t x1=0, Int_t y1=0)
121 {
122 fX0 = x0;
123 fY0 = y0;
124 fX1 = x1==0?fW:x1;
125 fY1 = y1==0?fH:y1;
126
127 for (Int_t x=fX0; x<fX1; x++)
128 for (Int_t y=fY0; y<fY1; y++)
129 {
130 const byte &b = fImg[y*fW+x];
131 if (b==0)
132 continue;
133
134 const Float_t mag = FindClusterAt(x, y);
135 if (fCount>999)
136 {
137 cout << "ERROR - Spot with Size>999 detected..." << endl;
138 return;
139 }
140
141 if (mag>0 && fCount>6)
142 leds.Add(fSumX/mag, fSumY/mag, 0, 0, mag);
143 }
144 leds.Compress();
145 }
146};
147
148
149void FilterLed::DrawBox(const int x1, const int y1,
150 const int x2, const int y2,
151 const int col) const
152{
153 MGMap::DrawBox(fImg, 768, 576, x1, y1, x2, y2, col);
154}
155
156void FilterLed::MarkPoint(Float_t px, Float_t py, Float_t mag) const
157{
158 const int x = (int)(px+.5);
159 const int y = (int)(py+.5);
160 const int m = (int)(mag);
161
162 DrawBox(x-8, y, x-5, y, m);
163 DrawBox(x, y+5, x, y+8, m);
164 DrawBox(x+5, y, x+8, y, m);
165 DrawBox(x, y-8, x, y-5, m);
166}
167
168void FilterLed::MarkPoint(const Led &led) const
169{
170 /*
171 Int_t M = (int)(log(led.GetMag())*20);
172
173 cout << led.GetMag() << endl;
174
175 if (M>0xff)
176 M=0xff;
177 if (M<0xc0)
178 M=0xc0;
179 */
180
181 const int x = (int)(led.GetX()+.5);
182 const int y = (int)(led.GetY()+.5);
183
184 MarkPoint(x, y, 0xff);
185}
186
187void FilterLed::DrawCircle(float cx, float cy, float r, byte col) const
188{
189 MGMap::DrawCircle(fImg, 768, 576, cx, cy, r, col);
190}
191
192void FilterLed::DrawHexagon(float cx, float cy, float r, byte col) const
193{
194 MGMap::DrawHexagon(fImg, 768, 576, cx, cy, r, col);
195}
196
197void FilterLed::DrawCircle(const Ring &l, byte col) const
198{
199 DrawCircle(l.GetX(), l.GetY(), l.GetR(), col);
200}
201
202void FilterLed::DrawCircle(const Ring &l, double r, byte col) const
203{
204 DrawCircle(l.GetX(), l.GetY(), r, col);
205}
206
207void FilterLed::DrawHexagon(const Ring &l, double r, byte col) const
208{
209 DrawHexagon(l.GetX(), l.GetY(), r, col);
210}
211
212void FilterLed::GetMinMax(const int offset, byte *min, byte *max) const
213{
214 *min = fImg[0];
215 *max = fImg[0];
216
217 byte *s = (byte*)fImg;
218 const byte *e0 = s+fW*fH;
219
220 //
221 // calculate mean value (speed optimized)
222 //
223 while (s<e0)
224 {
225 const byte *e = s+fH-offset;
226 s += offset;
227
228 while (s<e)
229 {
230 if (*s>*max)
231 {
232 *max = *s;
233 if (*max-*min==255)
234 return;
235 }
236 if (*s<*min)
237 {
238 *min = *s;
239 if (*max-*min==255)
240 return;
241 }
242 s++;
243 }
244 s+=offset;
245 }
246}
247
248int FilterLed::GetMeanPosition(const int x, const int y,
249 const int box, float &mx, float &my, unsigned int &sum) const
250{
251 unsigned int sumx=0;
252 unsigned int sumy=0;
253
254 sum=0;
255 for (int dx=x-box; dx<x+box+1; dx++)
256 for (int dy=y-box; dy<y+box+1; dy++)
257 {
258 const byte &m = fImg[dy*fW+dx];
259
260 sumx += m*dx;
261 sumy += m*dy;
262 sum += m;
263 }
264
265 mx = (float)sumx/sum;
266 my = (float)sumy/sum;
267
268 return (int)my*fW + (int)mx;
269}
270
271int FilterLed::GetMeanPosition(const int x, const int y, const int box) const
272{
273 float mx, my;
274 unsigned int sum;
275 return GetMeanPosition(x, y, box, mx, my, sum);
276}
277
278int FilterLed::GetMeanPositionBox(const int x, const int y,
279 const int box, float &mx,
280 float &my, unsigned int &sum) const
281{
282 //-------------------------------
283 // Improved algorithm:
284 // 1. Look for the largest five-pixel-cross signal inside the box
285 int x0 = TMath::Max(x-box+1, 0);
286 int y0 = TMath::Max(y-box+1, 0);
287
288 int x1 = TMath::Min(x+box+1-1, fW);
289 int y1 = TMath::Min(y+box+1-1, fH);
290
291 int maxx=0;
292 int maxy=0;
293
294 unsigned int max =0;
295 for (int dx=x0; dx<x1; dx++)
296 {
297 for (int dy=y0; dy<y1; dy++)
298 {
299 const unsigned int sumloc =
300 fImg[(dy+0)*fW + (dx-1)] +
301 fImg[(dy+0)*fW + (dx+1)] +
302 fImg[(dy+1)*fW + dx] +
303 fImg[(dy+0)*fW + dx] +
304 fImg[(dy-1)*fW + dx];
305
306 if(sumloc<=max)
307 continue;
308
309 maxx=dx;
310 maxy=dy;
311 max =sumloc;
312 }
313 }
314
315 // 2. Calculate mean position inside a circle around
316 // the highst cross-signal with radius of 6 pixels.
317 ClusterFinder find(fImg, fW, fH);
318 find.SetLimitingSize(9999);
319 find.SetRange(x0, y0, x1, y1);
320
321 const Float_t mag = find.FindClusterAt(maxx, maxy);
322
323 mx = find.GetSumX()/mag;
324 my = find.GetSumY()/mag;
325
326 sum = (int)(mag+0.5);
327
328 return (int)my*fW + (int)mx;
329}
330
331int FilterLed::GetMeanPositionBox(const int x, const int y,
332 const int box) const
333{
334 float mx, my;
335 unsigned int sum;
336 return GetMeanPositionBox(x, y, box, mx, my, sum);
337}
338
339void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc) const
340{
341 const Int_t first = leds.GetEntriesFast();
342
343 Execute(leds, xc, yc);
344
345 // Mark Stars in image
346 for (int i=first; i<leds.GetEntriesFast(); i++)
347 MarkPoint(leds(i));
348}
349
350
351void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc, double &bright) const
352{
353 const Int_t first = leds.GetEntriesFast();
354
355 Execute(leds, xc, yc, bright);
356
357 // Mark Stars in image
358 for (int i=first; i<leds.GetEntriesFast(); i++)
359 MarkPoint(leds(i));
360}
361
362void FilterLed::Execute(int xc, int yc) const
363{
364 Leds leds;
365 ExecuteAndMark(leds, xc, yc);
366}
367
368void FilterLed::Execute(Leds &leds, int xc, int yc) const
369{
370 double bright;
371 Execute(leds, xc, yc, bright);
372}
373
374void FilterLed::Execute(Leds &leds, int xc, int yc, double &bright) const
375{
376 const int x0 = TMath::Max(xc-fBox, 0);
377 const int y0 = TMath::Max(yc-fBox, 0);
378 const int x1 = TMath::Min(xc+fBox, fW);
379 const int y1 = TMath::Min(yc+fBox, fH);
380
381 const int wx = x1-x0;
382 const int hy = y1-y0;
383
384 double sum = 0;
385 double sq = 0;
386
387 for (int x=x0; x<x1; x++)
388 for (int y=y0; y<y1; y++)
389 {
390 byte &b = fImg[y*fW+x];
391
392 // Skip saturating pixels
393 if (b>0xf0)
394 continue;
395
396 sum += b;
397 sq += b*b;
398 }
399
400 sum /= wx*hy;
401 sq /= wx*hy;
402
403 bright=sum;
404
405
406 // 254 because b<=max and not b<max
407 const double sdev = TMath::Sqrt(sq-sum*sum);
408 const byte max = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
409
410 //
411 // clean image from noise
412 // (FIXME: A lookup table could accelerate things...
413 //
414 for (int x=x0; x<x1; x++)
415 for (int y=y0; y<y1; y++)
416 {
417 byte &b = fImg[y*fW+x];
418 if (b<=max)
419 b = 0;
420 }
421
422 ClusterFinder find(fImg, fW, fH);
423 find.FindCluster(leds, x0, y0, x1, y1);
424}
425
426void FilterLed::FindStar(Leds &leds, int xc, int yc, bool box) const
427{
428 // fBox: radius of the inner (signal) box
429 // Radius of the outer box is fBox*sqrt(2)
430
431 //
432 // Define inner box in which to search the signal
433 //
434 const int x0 = TMath::Max(xc-fBox, 0);
435 const int y0 = TMath::Max(yc-fBox, 0);
436 const int x1 = TMath::Min(xc+fBox, fW);
437 const int y1 = TMath::Min(yc+fBox, fH);
438
439 //
440 // Define outer box (excluding inner box) having almost
441 // the same number of pixels in which the background
442 // is calculated
443 //
444 const double sqrt2 = sqrt(2.);
445
446 const int xa = TMath::Max(xc-(int)rint(fBox*sqrt2), 0);
447 const int ya = TMath::Max(yc-(int)rint(fBox*sqrt2), 0);
448 const int xb = TMath::Min(xc+(int)rint(fBox*sqrt2), fW);
449 const int yb = TMath::Min(yc+(int)rint(fBox*sqrt2), fH);
450
451 //
452 // Calculate average and sdev for a square
453 // excluding the inner part were we expect
454 // the signal to be.
455 //
456 double sum = 0;
457 double sq = 0;
458
459 int n=0;
460 for (int x=xa; x<xb; x++)
461 for (int y=ya; y<yb; y++)
462 {
463 if (x>=x0 && x<x1 && y>=y0 && y<y1)
464 continue;
465
466 byte &b = fImg[y*fW+x];
467
468 sum += b;
469 sq += b*b;
470 n++;
471 }
472
473 sum /= n;
474 sq /= n;
475
476 // 254 because b<=max and not b<max
477 const double sdev = sqrt(sq-sum*sum);
478 const byte max = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
479
480 //
481 // clean image from noise
482 // (FIXME: A lookup table could accelerate things...
483 //
484 n=0;
485 for (int x=x0; x<x1; x++)
486 for (int y=y0; y<y1; y++)
487 {
488 byte &b = fImg[y*fW+x];
489 if (b<=max)
490 b = 0;
491 else
492 n++;
493 }
494
495 //
496 // Mark the background region
497 //
498 for (int x=xa; x<xb; x+=2)
499 {
500 fImg[ya*fW+x]=0xf0;
501 fImg[yb*fW+x]=0xf0;
502 }
503 for (int y=ya; y<yb; y+=2)
504 {
505 fImg[y*fW+xa]=0xf0;
506 fImg[y*fW+xb]=0xf0;
507 }
508
509 //
510 // Check if any pixel found...
511 //
512 if (n<5)
513 return;
514
515 //
516 // Get the mean position of the star
517 //
518 float mx, my;
519 unsigned int mag;
520 int pos = box ? GetMeanPositionBox(xc, yc, fBox-1, mx, my, mag) : GetMeanPosition(xc, yc, fBox-1, mx, my, mag);
521
522 if (pos<0 || pos>=fW*fH || fImg[pos]<sum+fCut*sdev)
523 return;
524
525 // cout << "Mean=" << sum << " SDev=" << sdev << " : ";
526 // cout << "Sum/n = " << sum << "/" << n << " = " << (n==0?0:mag/n) << endl;
527
528 leds.Add(mx, my, 0, 0, -2.5*log10((float)mag)+13.7);
529}
530
531void FilterLed::Stretch() const
532{
533 byte min, max;
534 GetMinMax(25, &min, &max);
535
536 if (min==max || max-min>230) // 255/230=1.1
537 return;
538
539 const float scale = 255./(max-min);
540
541 byte *b = fImg;
542 const byte *e = fImg+fW*fH;
543
544 while (b<e)
545 {
546 if (*b<min)
547 {
548 *b++=0;
549 continue;
550 }
551 if (*b>max)
552 {
553 *b++=255;
554 continue;
555 }
556 *b = (byte)((*b-min)*scale);
557 b++;
558 }
559}
Note: See TracBrowser for help on using the repository browser.