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

Last change on this file since 9445 was 9439, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 12.3 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 boxx, const int boxy,
250 float &mx, float &my, unsigned int &sum) const
251{
252 unsigned int sumx=0;
253 unsigned int sumy=0;
254
255 sum=0;
256 for (int dx=x-boxx; dx<x+boxx+1; dx++)
257 for (int dy=y-boxy; dy<y+boxy+1; dy++)
258 {
259 const byte &m = fImg[dy*fW+dx];
260
261 sumx += m*dx;
262 sumy += m*dy;
263 sum += m;
264 }
265
266 mx = (float)sumx/sum;
267 my = (float)sumy/sum;
268
269 return (int)my*fW + (int)mx;
270}
271
272int FilterLed::GetMeanPosition(const int x, const int y, const int boxx, const int boxy) const
273{
274 float mx, my;
275 unsigned int sum;
276 return GetMeanPosition(x, y, boxx, boxy, mx, my, sum);
277}
278
279int FilterLed::GetMeanPositionBox(const int x, const int y,
280 const int boxx, const int boxy,
281 float &mx, float &my, unsigned int &sum) const
282{
283 //-------------------------------
284 // Improved algorithm:
285 // 1. Look for the largest five-pixel-cross signal inside the box
286 int x0 = TMath::Max(x-boxx+1, 0);
287 int y0 = TMath::Max(y-boxy+1, 0);
288
289 int x1 = TMath::Min(x+boxx+1-1, fW);
290 int y1 = TMath::Min(y+boxy+1-1, fH);
291
292 int maxx=0;
293 int maxy=0;
294
295 unsigned int max =0;
296 for (int dx=x0; dx<x1; dx++)
297 {
298 for (int dy=y0; dy<y1; dy++)
299 {
300 const unsigned int sumloc =
301 fImg[(dy+0)*fW + (dx-1)] +
302 fImg[(dy+0)*fW + (dx+1)] +
303 fImg[(dy+1)*fW + dx] +
304 fImg[(dy+0)*fW + dx] +
305 fImg[(dy-1)*fW + dx];
306
307 if(sumloc<=max)
308 continue;
309
310 maxx=dx;
311 maxy=dy;
312 max =sumloc;
313 }
314 }
315
316 // 2. Calculate mean position inside a circle around
317 // the highst cross-signal with radius of 6 pixels.
318 ClusterFinder find(fImg, fW, fH);
319 find.SetLimitingSize(9999);
320 find.SetRange(x0, y0, x1, y1);
321
322 const Float_t mag = find.FindClusterAt(maxx, maxy);
323
324 mx = find.GetSumX()/mag;
325 my = find.GetSumY()/mag;
326
327 sum = (int)(mag+0.5);
328
329 return (int)my*fW + (int)mx;
330}
331
332int FilterLed::GetMeanPositionBox(const int x, const int y,
333 const int boxx, const int boxy) const
334{
335 float mx, my;
336 unsigned int sum;
337 return GetMeanPositionBox(x, y, boxx, boxy, mx, my, sum);
338}
339
340void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc) const
341{
342 const Int_t first = leds.GetEntriesFast();
343
344 Execute(leds, xc, yc);
345
346 // Mark Stars in image
347 for (int i=first; i<leds.GetEntriesFast(); i++)
348 MarkPoint(leds(i));
349}
350
351
352void FilterLed::ExecuteAndMark(Leds &leds, int xc, int yc, double &bright) const
353{
354 const Int_t first = leds.GetEntriesFast();
355
356 Execute(leds, xc, yc, bright);
357
358 // Mark Stars in image
359 for (int i=first; i<leds.GetEntriesFast(); i++)
360 MarkPoint(leds(i));
361}
362
363void FilterLed::Execute(int xc, int yc) const
364{
365 Leds leds;
366 ExecuteAndMark(leds, xc, yc);
367}
368
369void FilterLed::Execute(Leds &leds, int xc, int yc) const
370{
371 double bright;
372 Execute(leds, xc, yc, bright);
373}
374
375void FilterLed::Execute(Leds &leds, int xc, int yc, double &bright) const
376{
377 const int x0 = TMath::Max(xc-fBoxX, 0);
378 const int y0 = TMath::Max(yc-fBoxY, 0);
379 const int x1 = TMath::Min(xc+fBoxX, fW);
380 const int y1 = TMath::Min(yc+fBoxY, fH);
381
382 const int wx = x1-x0;
383 const int hy = y1-y0;
384
385 double sum = 0;
386 double sq = 0;
387
388 for (int x=x0; x<x1; x++)
389 for (int y=y0; y<y1; y++)
390 {
391 byte &b = fImg[y*fW+x];
392
393 // Skip saturating pixels
394 if (b>0xf0)
395 continue;
396
397 sum += b;
398 sq += b*b;
399 }
400
401 sum /= wx*hy;
402 sq /= wx*hy;
403
404 bright=sum;
405
406
407 // 254 because b<=max and not b<max
408 const double sdev = TMath::Sqrt(sq-sum*sum);
409 const byte max = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
410
411 //
412 // clean image from noise
413 // (FIXME: A lookup table could accelerate things...
414 //
415 for (int x=x0; x<x1; x++)
416 for (int y=y0; y<y1; y++)
417 {
418 byte &b = fImg[y*fW+x];
419 if (b<=max)
420 b = 0;
421 }
422
423 ClusterFinder find(fImg, fW, fH);
424 find.FindCluster(leds, x0, y0, x1, y1);
425}
426
427void FilterLed::FindStar(Leds &leds, int xc, int yc, bool box) const
428{
429 // fBox: radius of the inner (signal) box
430 // Radius of the outer box is fBox*sqrt(2)
431
432 //
433 // Define inner box in which to search the signal
434 //
435 const int x0 = TMath::Max(xc-fBoxX, 0);
436 const int y0 = TMath::Max(yc-fBoxY, 0);
437 const int x1 = TMath::Min(xc+fBoxX, fW);
438 const int y1 = TMath::Min(yc+fBoxY, fH);
439
440 //
441 // Define outer box (excluding inner box) having almost
442 // the same number of pixels in which the background
443 // is calculated
444 //
445 const double sqrt2 = sqrt(2.);
446
447 const int xa = TMath::Max(xc-TMath::Nint(fBoxX*sqrt2), 0);
448 const int ya = TMath::Max(yc-TMath::Nint(fBoxY*sqrt2), 0);
449 const int xb = TMath::Min(xc+TMath::Nint(fBoxX*sqrt2), fW);
450 const int yb = TMath::Min(yc+TMath::Nint(fBoxY*sqrt2), fH);
451
452 //
453 // Calculate average and sdev for a square
454 // excluding the inner part were we expect
455 // the signal to be.
456 //
457 double sum = 0;
458 double sq = 0;
459
460 int n=0;
461 for (int x=xa; x<xb; x++)
462 for (int y=ya; y<yb; y++)
463 {
464 if (x>=x0 && x<x1 && y>=y0 && y<y1)
465 continue;
466
467 byte &b = fImg[y*fW+x];
468
469 sum += b;
470 sq += b*b;
471 n++;
472 }
473
474 sum /= n;
475 sq /= n;
476
477 // 254 because b<=max and not b<max
478 const double sdev = sqrt(sq-sum*sum);
479 const byte max = sum+fCut*sdev>254 ? 254 : (byte)(sum+fCut*sdev);
480
481 //
482 // clean image from noise
483 // (FIXME: A lookup table could accelerate things...
484 //
485 n=0;
486 for (int x=x0; x<x1; x++)
487 for (int y=y0; y<y1; y++)
488 {
489 byte &b = fImg[y*fW+x];
490 if (b<=max)
491 b = 0;
492 else
493 n++;
494 }
495
496 //
497 // Mark the background region
498 //
499 for (int x=xa; x<xb; x+=2)
500 {
501 fImg[ya*fW+x]=0xf0;
502 fImg[yb*fW+x]=0xf0;
503 }
504 for (int y=ya; y<yb; y+=2)
505 {
506 fImg[y*fW+xa]=0xf0;
507 fImg[y*fW+xb]=0xf0;
508 }
509
510 //
511 // Check if any pixel found...
512 //
513 if (n<5)
514 return;
515
516 //
517 // Get the mean position of the star
518 //
519 float mx, my;
520 unsigned int mag;
521 int pos = box ? GetMeanPositionBox(xc, yc, fBoxX-1, fBoxY-1, mx, my, mag)
522 : GetMeanPosition(xc, yc, fBoxX-1, fBoxY-1, mx, my, mag);
523
524 if (pos<0 || pos>=fW*fH || fImg[pos]<sum+fCut*sdev)
525 return;
526
527 // cout << "Mean=" << sum << " SDev=" << sdev << " : ";
528 // cout << "Sum/n = " << sum << "/" << n << " = " << (n==0?0:mag/n) << endl;
529
530 leds.Add(mx, my, 0, 0, -2.5*log10((float)mag)+13.7);
531}
532
533void FilterLed::Stretch() const
534{
535 byte min, max;
536 GetMinMax(25, &min, &max);
537
538 if (min==max || max-min>230) // 255/230=1.1
539 return;
540
541 const float scale = 255./(max-min);
542
543 byte *b = fImg;
544 const byte *e = fImg+fW*fH;
545
546 while (b<e)
547 {
548 if (*b<min)
549 {
550 *b++=0;
551 continue;
552 }
553 if (*b>max)
554 {
555 *b++=255;
556 continue;
557 }
558 *b = (byte)((*b-min)*scale);
559 b++;
560 }
561}
Note: See TracBrowser for help on using the repository browser.