00001 #ifndef FINDLEDSMODULE_H
00002 #define FINDLEDSMODULE_H
00003
00004 #include "../opencvext.h"
00005 #include "imagesource.h"
00006 #include <iostream>
00007 #include <list>
00008 #include "../microeva.h"
00009 #include "../microadam.h"
00010 #include "../image.h"
00011 #include "correlation.h"
00012 #include "hsvrange.h"
00013
00014 using namespace std;
00015
00016 namespace seemicro
00017 {
00018
00025 const uchar MAXMARKS = 100;
00026
00035 struct FindLEDSModule : public ImageSource
00036 {
00040 ImageSource& src;
00041
00045 Micro& micro;
00046 MicroEva *eva;
00047
00051 CorrelationModule &corr;
00052
00053 HSVRange& range;
00054
00055 myrect ROI;
00056
00057 int w, h;
00058
00063 mypoint markierungen[MAXMARKS];
00064
00068 int anzahl[MAXMARKS];
00069
00073 float abstand[MAXMARKS];
00074
00078 unsigned short int markiert;
00079
00083 float gamma[MAXMARKS];
00084
00088 float gamma0[MAXMARKS];
00089
00093 float beta[MAXMARKS];
00094
00101 char gemerkt[MAXMARKS], gewaehlt[MAXMARKS], armnummer[MAXMARKS];
00102
00103 FindLEDSModule(ImageSource& Asrc, Micro& Am, CorrelationModule& Ac,
00104 HSVRange& Ar) :
00105 src(Asrc), micro(Am), corr(Ac), range(Ar)
00106 {
00107 eva = dynamic_cast<MicroEva*>(µ);
00108 if(src.img->nChannels != 3)
00109 {
00110 cerr << "FindLEDSModule(): Eingabebild muß RGB-Bild sein!\n";
00111 throw bad_alloc();
00112 }
00113 img = cvCreateImage(cvSize(src.img->width, src.img->height), IPL_DEPTH_8U, 1);
00114 w = img->width;
00115 h = img->height;
00116 }
00117
00118 ~FindLEDSModule()
00119 {
00120 cvReleaseImage(&img);
00121 }
00122
00126 inline bool remarkable(const int x, const int y, const HSVRange& range)
00127 {
00128 int pix = getPixel8u_3(src.img, x, y);
00129 unsigned short pH, pS, pV;
00130 rgb2hsv(pix, &pH, &pS, &pV);
00131
00132 if(pH>range.hmax) return false;
00133 if(pH<range.hmin) return false;
00134 if(pS>range.smax) return false;
00135 if(pS<range.smin) return false;
00136 if(pV>range.vmax) return false;
00137 if(pV<range.vmin) return false;
00138 return true;
00139 }
00140
00145 inline void recursive_mark(const int x, const int y, const uchar m, const HSVRange& range)
00146 {
00147 putPixel8u_1(img, x, y, m);
00148 markierungen[m-1].p.x += x;
00149 markierungen[m-1].p.y += y;
00150 anzahl[m-1]++;
00151
00152 if(x+1<w && getPixel8u_1(img, x+1, y)==0 && remarkable(x+1, y, range)) recursive_mark(x+1, y, m, range);
00153 if(y+1<h)
00154 {
00155 if( getPixel8u_1(img, x , y+1)==0 && remarkable(x, y+1, range)) recursive_mark(x, y+1, m, range);
00156 if(x+1<w && getPixel8u_1(img, x+1, y+1)==0 && remarkable(x+1, y+1, range)) recursive_mark(x+1, y+1, m, range);
00157 if(x-1>=0 && getPixel8u_1(img, x-1, y+1)==0 && remarkable(x-1, y+1, range)) recursive_mark(x-1, y+1, m, range);
00158 }
00159 }
00160
00161 inline void FloodFill(IplImage *img, myrect& ROI, unsigned short int& markiert, const HSVRange& range)
00162 {
00163 cvZero(img);
00164 markiert = 0;
00165
00166 for(int x=ROI.r.x; x<ROI.r.x+ROI.r.width; x++)
00167 for(int y=ROI.r.y; y<ROI.r.y+ROI.r.height; y++)
00168 {
00169 if(!remarkable(x, y, range)) continue;
00170 unsigned short int m = getPixel8u_1(img, x, y);
00171 if(m!=0) continue;
00172
00173
00174 if(x+1<w) m = getPixel8u_1(img, x+1, y);
00175 if(m==0 && y+1<h)
00176 {
00177 m = getPixel8u_1(img, x , y+1);
00178 if(m==0 && x+1<w) m = getPixel8u_1(img, x+1, y+1);
00179 if(m==0 && x-1>=0) m = getPixel8u_1(img, x-1, y+1);
00180 }
00181
00182 if(m==0)
00183 {
00184
00185 if(markiert<MAXMARKS-1) markiert++;
00186 m = markiert;
00187 markierungen[m-1] = mypoint(0, 0);
00188 anzahl[m-1] = 0;
00189 }
00190 recursive_mark(x, y, m, range);
00191 }
00192
00193 if(DEBUGLEVEL>=3) cerr << "Vergebene Markierungen: " << markiert << endl;
00194
00195
00196 for(int i=0; i<markiert; i++)
00197 {
00198 markierungen[i].p.x /= anzahl[i];
00199 markierungen[i].p.y /= anzahl[i];
00200 if(DEBUGLEVEL>=3)
00201 cerr << "#" << i << " (" << markierungen[i].p.x << " " <<
00202 markierungen[i].p.y << ") " << anzahl[i] << " pix\n";
00203 }
00204 }
00205
00206 void FloodFillMarks2Colors(IplImage *out)
00207 {
00208 for(int x=0; x<img->width; x++)
00209 for(int y=0; y<img->height; y++)
00210 {
00211 uchar m = getPixel8u_1(img, x, y);
00212 int n = 0;
00213 switch(m)
00214 {
00215 case 0: break;
00216 case 1: n = CV_RGB(255, 0, 0);break;
00217 case 2: n = CV_RGB(0, 255, 0);break;
00218 case 3: n = CV_RGB(0, 0, 255);break;
00219 case 4: n = CV_RGB(255, 255, 0);break;
00220 case 5: n = CV_RGB(255, 0, 255);break;
00221 case 6: n = CV_RGB(0, 255, 255);break;
00222 case 7: n = CV_RGB(255, 0, 128);break;
00223 case 8: n = CV_RGB(255, 128, 0);break;
00224 case 9: n = CV_RGB(128, 0, 255);break;
00225 case 10: n = CV_RGB(0, 128, 255);break;
00226 default:
00227 {
00228 static int been_here=0;
00229 if(!been_here)
00230 {
00231 been_here++;
00232 cerr << "No more colors defined for marks>=" << int(m) << endl;
00233 }
00234 }
00235 }
00236 putPixel8u_3(out, x, y, n);
00237 }
00238 }
00239
00243 virtual void processFrame(myrect *AROI)
00244 {
00245 if(!paramChanged && !src.outputChanged &&
00246 !corr.outputChanged && !range.outputChanged) return;
00247 if(AROI) ROI = *AROI;
00248 else ROI = myrect(0, 0, w, h);
00249
00250 FloodFill(img, ROI, markiert, range);
00251
00252
00253
00254
00255
00256
00257 int i,j;
00258 for(i=0; i<markiert; i++)
00259 {
00260 mypoint& s1 = markierungen[i];
00261 bool zusammengelegt;
00262
00263
00264
00265
00266
00267 do {
00268 zusammengelegt=false;
00269 for(j=i+1; j<markiert; j++)
00270 {
00271 if(anzahl[j] == 0) continue;
00272 mypoint& s2 = markierungen[j];
00273 if(abs(s1-s2)<10)
00274 {
00275 if(DEBUGLEVEL>=3)
00276 cerr << "Lege #" << i << " und #" << j << " zusammen.\n";
00277
00278 int alle = anzahl[i] + anzahl[j];
00279 float gi = anzahl[i]/(float)alle;
00280 float gj = anzahl[j]/(float)alle;
00281
00282 markierungen[i].p.x = int(markierungen[i].p.x*gi + markierungen[j].p.x*gj);
00283 markierungen[i].p.y = int(markierungen[i].p.y*gi + markierungen[j].p.y*gj);
00284 anzahl[i] = alle;
00285
00286 anzahl[j] = 0;
00287
00288 zusammengelegt=true;
00289 break;
00290 }
00291 }
00292 } while(zusammengelegt==true);
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 int pixPerLED = int(sqr(micro.radius*0.07));
00308
00309 int MaxPixPerLED = int(pixPerLED*1.4);
00310 int MinPixPerLED = int(pixPerLED*0.1);
00311 if(DEBUGLEVEL>=3) cerr << "Pixel pro LED: ideal=" << pixPerLED
00312 << " min=" << MinPixPerLED
00313 << " max=" << MaxPixPerLED << endl;
00314
00315
00316 for(int i=0; i<markiert; i++)
00317 {
00318 if(anzahl[i] > MaxPixPerLED) anzahl[i] = 0;
00319 if(anzahl[i] < MinPixPerLED) anzahl[i] = 0;
00320 }
00321
00322
00323 if(!micro.mitteValid && DEBUGLEVEL>=1) cerr << "Radmitte unbekannt :(\n";
00324 if(!micro.radiusValid && DEBUGLEVEL>=1) cerr << "Radius unbekannt :(\n";
00325
00326 const float LED_MINABSTAND = 0.1;
00327 const float LED_MAXABSTAND = 0.8;
00328 for(int i=0; i<markiert; i++)
00329 {
00330 if(anzahl[i] == 0) continue;
00331 mypoint& s1 = markierungen[i];
00332 s1 = s1 - micro.mitte;
00333 abstand[i] = abs(s1)/micro.radius;
00334
00335
00336
00337 if(abstand[i] > LED_MAXABSTAND) anzahl[i] = 0;
00338 if(abstand[i] < LED_MINABSTAND) anzahl[i] = 0;
00339
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356 for(int i=0; i<markiert; i++)
00357 {
00358 if(anzahl[i] == 0) continue;
00359 gamma[i] = acos((markierungen[i].p.x) / (abstand[i]*micro.radius));
00360
00361 if(markierungen[i].p.y > 0)
00362 gamma[i] = 2*M_PI - gamma[i];
00363
00364
00365
00366
00367 beta[i] = 1-(abstand[i]-LED_MINABSTAND)/(LED_MAXABSTAND-LED_MINABSTAND);
00368
00369
00370
00371
00372
00373
00374 gamma0[i] = gamma[i] + beta[i]*20/180*M_PI;
00375
00376
00377 }
00378
00379 if(eva)
00380 {
00381
00382
00383
00384
00385
00386
00387 for(int z=0; z<markiert; z++) gewaehlt[z] = 0;
00388 float fehler1min = 1e6;
00389
00390 for(int y=0; y<markiert; y++)
00391 {
00392 if(anzahl[y] == 0) continue;
00393
00394
00395 for(int z=0; z<markiert; z++)
00396 {
00397 gemerkt[z] = 0;
00398 }
00399 gemerkt[y] = 1;
00400
00401 float fehler1temp = 0;
00402 for(int i=1; i<5; i++)
00403 {
00404
00405 float igamma0 = gamma0[y] + i*72./360.*2.*M_PI;
00406 if(igamma0 > 2*M_PI) igamma0 -= 2.*M_PI;
00407 float fehler2min = 50./360.*2.*M_PI;
00408
00409 int minx = -1;
00410 for(int x=0; x<markiert; x++)
00411 {
00412 if(anzahl[x] == 0) continue;
00413 if(gemerkt[x]) continue;
00414 float adiff = anglediff(igamma0, gamma0[x]);
00415 if(adiff<fehler2min)
00416 {
00417
00418
00419 fehler2min = adiff;
00420 minx = x;
00421 }
00422 }
00423 if(minx==-1)
00424
00425 fehler1temp += 100;
00426 else
00427 {
00428 fehler1temp += fehler2min;
00429 gemerkt[minx] = i+1;
00430 }
00431 }
00432 if(fehler1temp<fehler1min)
00433 {
00434 fehler1min = fehler1temp;
00435
00436 memcpy(gewaehlt, gemerkt, sizeof(gewaehlt));
00437 }
00438 }
00439
00440
00441
00442
00443
00444
00445
00446 float fehler3=10;
00447 int alphai = -1;
00448 for(int i=0; i<markiert; i++)
00449 {
00450 if(!gewaehlt[i]) continue;
00451 float adiff = anglediff(micro.alpha, gamma0[i]);
00452 if(fehler3 > adiff)
00453 {
00454 alphai = i;
00455 fehler3 = adiff;
00456 }
00457 }
00458 if(fehler3<10)
00459 {
00460 micro.alpha = gamma[alphai];
00461 micro.alphaValid = true;
00462 }
00463
00464 if(alphai==-1)
00465 {
00466 if(DEBUGLEVEL>=1)
00467 cerr << "Kein Schwerpunkt gefunden -> kein alpha.\n";
00468 }
00469 else
00470 {
00471
00472
00473
00474
00475
00476
00477
00478 char ga = gewaehlt[alphai];
00479 eva->beta[0] = beta[alphai];
00480 armnummer[alphai] = 1;
00481
00482 for(int i=0; i<markiert; i++)
00483 {
00484 char gi = gewaehlt[i];
00485 if(gi<1)
00486 {
00487 armnummer[i] = 0;
00488 continue;
00489 }
00490 if(gi==ga) continue;
00491 int an = 1+((gi+(5-ga)) % 5);
00492 eva->beta[an-1] = beta[i];
00493 armnummer[i] = an;
00494
00495 }
00496
00497 }
00498 }
00499 else
00500
00501
00502
00503 {
00504 MicroAdam *adam = dynamic_cast<MicroAdam*>(µ);
00505 if(adam)
00506 {
00507
00508
00509 int ledIndex=-1;
00510 for(int i=0; i<markiert; i++)
00511 {
00512
00513 if(anzahl[i] == 0) continue;
00514
00515 if(abstand[i]<0.55)
00516 {
00517 anzahl[i]=0; continue;
00518 }
00519 float d = anglediff(gamma[i], micro.alpha+adam->beta);
00520 if(d > 10./180.*M_PI) continue;
00521
00522
00523
00524 if(ledIndex!=-1)
00525 {
00526 ledIndex=-1;
00527 break;
00528 }
00529 ledIndex=i;
00530
00531 }
00532 if(ledIndex!=-1)
00533 {
00534 if(anglediff(gamma[ledIndex], micro.alpha+adam->beta)
00535 < 10./180.*M_PI)
00536 {
00537 if(DEBUGLEVEL>=2)
00538 cerr << "Switching alpha by 180°: gamma[]=" << gamma[ledIndex]
00539 << " alpha=" << micro.alpha << "\n";
00540 micro.alpha += M_PI;
00541 }
00542 }
00543 }
00544 }
00545
00546 if(DEBUGLEVEL>=3) cerr << "<-FindLEDS\n";
00547 paramChanged = false;
00548 range.outputChanged = false;
00549 outputChanged = true;
00550 }
00551
00552 virtual void processKeyFrame(void)
00553 {
00554 if(DEBUGLEVEL>=3) cerr << "FindLEDSModule::processKeyFrame()\n";
00555 processFrame(NULL);
00556 }
00557
00558 };
00559
00560 }
00561
00562 #endif // FINDLEDSMODULE_H
00563