LARS
LARS (Light Augmented Reality System) is an open-source framework for light-based interaction and real-time tracking in multi-robot experiments. Inspired by ARK, LARS extends the augmented reality paradigm to robotic collectives by projecting dynamic visual cues and environments onto the arena, enabling new experimental possibilities for collective robotics research, education, and outreach. LARS features integrated tracking, light projection, and modular experiment control with a user-friendly Qt GUI.
Loading...
Searching...
No Matches
robottracker.h
1
7
8#ifndef ROBOTTRACKER_H
9#define ROBOTTRACKER_H
10#include <ios>
11#include <vector>
12
13#define USE_CUDA true
14using namespace std;
15
16// OpenCV 3 :
17#include <opencv2/highgui.hpp>
18#include <opencv2/video.hpp>
19#include <opencv2/imgproc.hpp>
20#include <opencv2/videostab.hpp>
21#include <opencv2/features2d.hpp>
22//#include <opencv2/stitching.hpp>
23#include <opencv2/opencv.hpp>
24#include <opencv2/core/core.hpp>
25#include <opencv2/imgcodecs.hpp>
26#include <opencv2/videoio.hpp>
27#include <opencv2/core/ocl.hpp>
28#include <opencv2/cudaarithm.hpp>
29#include <opencv2/cudaimgproc.hpp>
30#include <opencv2/cudafilters.hpp>
31#include <opencv2/cudafeatures2d.hpp>
32#include <opencv2/cudawarping.hpp>
33
34#ifdef USE_CUDA
35#define MAT_TYPE cuda::GpuMat
36#define CV_NS cv::cuda::
37#else
38#define MAT_TYPE UMat
39#define CV_NS cv::
40#endif
41
42// allow easy addressing of OpenCV functions
43using namespace cv;
44
45// Qt base include
46#include <QObject>
47#include <QPoint>
48#include <QPixmap>
49
50// for thread buffer communication
51#include <QSemaphore>
52#include <QTimer>
53#include <QElapsedTimer>
54#include <QTime>
55//#include <QColor>
56#include <QDebug>
57
58#include "Kilobot/kilobot.h"
59
60// buffers and semaphores
61struct srcBuffer {
62 MAT_TYPE full_warped_image;
63};
64
65#define BUFF_SIZE 2
66
67#define IM_WIDTH 1920 //960 // 2304
68#define IM_HEIGHT 1200 // 600 // 1536
69
70//#define IDENTIFY_TIMEOUT 10
71#define IDENTIFY_TIMEOUT 1
72
73enum srcDataType {
74 IMAGES,
75 VIDEO,
76 CAMERA
77};
78
79enum trackerType {
80 NO_TRACK,
81 CIRCLES_NAIVE,
82 CIRCLES_LOCAL,
83 MY_HAPPY_OTHER_TRACKER,
84 MORFI_TRACKER
85};
86
87struct indexPair {
88 int a;
89 int b;
90};
91
92struct kiloLight {
93 lightColour col;
94 Point pos;
95};
96
97enum experimentType {
98 IDENTIFY,
99 ID_ASSIGNMENT,
100 CALIBRATION,
101 USER_EXP,
102 VRK_EXP,
103 M_EXP
104};
105
106// DRAWABLES:
107struct drawnCircle {
108 Point pos;
109 int r;
110 QColor col;
111 int thickness;
112 std::string text;
113 bool transparent;
114};
115
116struct drawnLine {
117 std::vector<Point> pos;
118 QColor col;
119 int thickness;
120 std::string text;
121 bool transparent;
122};
123
124class acquireThread;
125//class KilobotExperiment;
126
133class KilobotTracker : public QObject
134{
135 Q_OBJECT
136
137public:
138 explicit KilobotTracker(QPoint smallImageSize = QPoint(300,300), QObject *parent = 0);
139 ~KilobotTracker();
140
141
142// KilobotExperiment * expt; // Mohsen: do we need EXPERIMENT here?
143
144 int dummyVar2000 = 2000; // MOHSEN! << just to check what is this value!
145
146 //Default tracking parameters and identification parameters
147#ifdef FOR_KILOBOT
148// int kbMinSize = 5;//3;
149// int kbMaxSize = 16;//22;
150// int houghAcc = 19; // 27;
151// int cannyThresh = 61; //40;
152
153// int kbMinSize = 10;//8;//10;//3;
154// int kbMaxSize = 17;//12;//18;//22;
155// int houghAcc = 9;//13;//12; // 27;
156// int cannyThresh = 119;//90;//112; //40;
157
158 // Kilobots
159 int kbMinSize = 12;
160 int kbMaxSize = 17;
161// int kbBigMinSize = 25;
162// int kbBigMaxSize = 40;
163 int houghAcc = 12;//13;//12; // 27;
164 int cannyThresh = 129;//90;//112; //40;
165
166// // THYMIOS
167// int kbMinSize = 18;
168// int kbMaxSize = 29;
169// int houghAcc = 25;//13;//12; // 27;
170// int cannyThresh = 131;//90;//112; //40;
171
172 int kbLEDMinSize = kbMinSize/7;//3;
173 int kbLEDMaxSize = kbMinSize*10/7;//22; << !!
174 int LEDhoughAcc = houghAcc; // 27;
175 int LEDcannyThresh = cannyThresh; //40;
176
177
178#else
179 // THYMIOS on Floor
180// int kbMinSize = 33;
181// int kbMaxSize = 44;
182// int houghAcc = 23;//13;//12; // 27;
183// int cannyThresh = 131;//90;//112; //40;
184
185// int kbLEDMinSize = kbMinSize/7;//3;
186// int kbLEDMaxSize = kbMinSize*10/7;//22; << !!
187// int LEDhoughAcc = houghAcc; // 27;
188// int LEDcannyThresh = cannyThresh; //40;
189
190
191 // THYMIOS on Floor/ half Resolution
192 int kbMinSize = 14;
193 int kbMaxSize = 26;
194 int houghAcc = 23;//13;//12; // 27;
195 int cannyThresh = 115;//90;//112; //40;
196
197// int kbLEDMinSize = kbMinSize/7;//3;
198// int kbLEDMaxSize = kbMinSize*10/7;//22; << !!
199
200 int kbLEDMinSize = kbMinSize; // For Thymios
201 int kbLEDMaxSize = kbMaxSize; // For Thymios
202 int LEDhoughAcc = houghAcc; // 27;
203 int LEDcannyThresh = cannyThresh; //40;
204
205#endif
206
207 int maxIDtoCheck = 100;
208 uint manualID;
209
210
211 float morfiTrack_maxDisplacement = 12.0;
212 float EFWL = 2.0; // Expansion Factor for search When Lost
213 float smooth_fact = 0.5; // for updating positions of kilobots
214
215 // camera parameters
216 int height_x_adj = 10;
217 int height_y_adj = 10;
218
219 //Default color threshold detection parameters
220 float redLThreshold = 1.0; // 0.75; //0.6
221 float redHThreshold = 0.0;
222 float greenLThreshold = 1.0; // 0.56;
223 float greenHThreshold = 0.0; // 0.75;
224 float blueLThreshold = 0.65;
225 float blueHThreshold = 0.0;
226
227 QList<Vec3f> detectedCircles;
228
229 bool debugBool = false;//true;//false;
230 bool drawDebugBool = false; //true;
231
232
233signals:
238 void errorMessage(QString);
239
240 void setStitchedImage(QPixmap);
241
242 void capturedImage(cv::Mat);
243
244 void identifyKilo(uint8_t);
245
246 void broadcastMessage(kilobot_broadcast);
247
248 void clearMsgQueue();
249
250 void startExperiment(bool);
251
252 void stopExperiment();
253
254 void toggleExpButton(int);
255
256 void activateExpButtons(int);
257
258 void setRuntimeIdentificationLock(bool);
259
260 void kiloList(QVector<Kilobot *>);
261
262 void circlesToDrawSig(QVector < drawnCircle >);
263
264
265public slots:
271 void LOOPstartstop(int stage);
272
278
284
285
286 // MOHSEN
287 bool RUNcapture();
288
294
300
301
302 // MOHSEN
303
304 void updateCropPoints(QRect cropRect);
305
306 QSize getImageSize();
307
308// void drawOverlayPub(Mat &);
309
310// void getCircles(QVector < drawnCircle >);
311
312
313
314 // drawing slots
315 void drawCircle(QPointF pos, float r, QColor col, int thickness = 2, std::string text ="", bool transparent = false) {
316 int r_int = r;
317 this->circsToDraw.push_back(drawnCircle {Point(pos.x(),pos.y()), r_int, col, thickness, text, transparent});
318 }
319
320 void drawLine(std::vector<cv::Point> pos, QColor col, int thickness = 2, std::string text ="", bool transparent = false) {
321 this->linesToDraw.push_back(drawnLine {pos, col, thickness, text, transparent});
322 }
323
324 void clearDrawings() {
325 this->circsToDraw.clear();
326 this->linesToDraw.clear();
327 }
328
329 void drawCircleOnRecordedImage(QPointF pos, float r, QColor col, int thickness = 2, std::string text = "") {
330 int r_int = r;
331 this->circsToDrawFinal.push_back(drawnCircle {Point(pos.x(),pos.y()), r_int, col, thickness, text});
332 }
333
334 void clearDrawingsOnRecordedImage() {
335 this->circsToDrawFinal.clear();
336 }
337
338 void saveImage(QString file) {
339 if (!finalImageCol.empty()) {
340 // before saving I draw what I need to draw on the FinalImage
341 for (int i = 0; i < this->circsToDrawFinal.size(); ++i) {
342 cv::circle(finalImageCol,this->circsToDrawFinal[i].pos, this->circsToDrawFinal[i].r,
343 Scalar(this->circsToDrawFinal[i].col.blue(),this->circsToDrawFinal[i].col.green(),this->circsToDrawFinal[i].col.red(),0.5),
344 this->circsToDrawFinal[i].thickness);
345 }
346 cv::imwrite(file.toStdString(),finalImageCol);
347 }
348 }
349
350 void saveVideoFrames(QString file, unsigned int numofframes) {
351 savecamerasframes = true;
352 savecamerasframesdir=file;
353 numberofframes=numofframes;
354 }
355
356 // accessors - docs not required??
357 void setSourceType(bool val) {if (val) this->srcType = CAMERA; else this->srcType = VIDEO;}
358
359 void setKbMin(int val){this->kbMinSize = val;}
360 void setKbMax(int val) {this->kbMaxSize = val;}
361
362// void setKbBigMin(int val){this->kbBigMinSize = val;}
363// void setKbBigMax(int val) {this->kbBigMaxSize = val;}
364
365 void setCannyThresh(int val) {this->cannyThresh = val;}
366 void setHoughAcc(int val) {this->houghAcc = val;}
367
368 void setKbLMin(int val){this->kbLEDMinSize = val;}
369 void setKbLMax(int val) {this->kbLEDMaxSize = val;}
370 void setLEDCannyThresh(int val) {this->LEDcannyThresh = val;}
371 void setLEDHoughAcc(int val) {this->LEDhoughAcc = val;}
372
373
374 void setLowRLED(int val){this->redLThreshold = (double) val/100.0;}// qDebug() << "value: " << this->redLThreshold;}
375 void setLowGLED(int val) {this->greenLThreshold = (double) val/100.0;}
376 void setLowBLED(int val) {this->blueLThreshold = (double) val/100.0;}
377 void setHiRLED(int val){this->redHThreshold = (double) val/100.0;}
378 void setHiGLED(int val) {this->greenHThreshold = (double) val/100.0;}
379 void setHiBLED(int val) {this->blueHThreshold = (double) val/100.0;}
380
381
382 void setHeightXSlider(int val) {this->height_x_adj = val;}
383 void setHeightYSlider(int val) {this->height_y_adj = val;}
384
385 void manuallyassignID(QPoint position);
386
392 void setVideoDir(QString dir) {this->videoPath = dir;}
393
394 void updateKilobotStates();
395
396 void getInitialKilobotStates();
397
398 void setTrackingType(int t_type) {this->t_type = t_type;}
399 void updateExperimentBroadcastingState(bool BroadcastingState)
400 {
401 experimentIsBroadcasting=BroadcastingState;
402 }
403
410 void showIds(bool toggle) {this->showIDs = toggle;}
411 void detectred(bool toggle) {this->m_detectred = toggle;}
412 void detectgreen(bool toggle) {this->m_detectgreen = toggle;}
413 void detectblue(bool toggle) {this->m_detectblue = toggle;}
414 void manualIDassignment(bool toggle) {this->m_assignIDmanually = toggle;}
415 void enableRuntimeIdentification(bool toggle) {this->m_runtimeIDenabled = toggle;}
416
417
418 void maxIDtoTry(QString maxIdStr) {this->maxIDtoCheck = maxIdStr.toInt();}
419 void setManualID(QString manID) {this->manualID = manID.toUInt();}
420 void setFlipangle(double angle);
421
427
428private:
429
430 // PRIVATE METHODS
431
432
437 void trackKilobots();
438
443 void SETUPstitcher();
444
449 void showMat(Mat &);
450
458
459#ifdef USE_CUDA
460 kiloLight getKiloBotLight(cuda::GpuMat channels[3], Point centreOfBox, int index);
461 kiloLight getKiloBotLightAdaptive(cuda::GpuMat channels[3], Point centreOfBox, int index);
462 void getKiloBotLights(Mat &display);
463#else
464 kiloLight getKiloBotLight(Mat channels[3], Point centreOfBox, int index);
465 kiloLight getKiloBotLightAdaptive(Mat channels[3], Point centreOfBox, int index);
466#endif
467
476 Rect getKiloBotBoundingBox(int index, float scale);
477
482 void THREADSlaunch();
483
484 void THREADSstop();
485
486 void identifyKilobot(int);
487 void identifyKilobot(int,bool);
488
489 void runtimeIdentify();
490
491 void drawOverlay(Mat &);
492
493 void getDetectedCircles();
494
495
496 // INTERNAL VARIABLES
497// int t_type = POS | ADAPTIVE_LED | ROT;
498 int t_type = POS | LED | ROT;
499
500 bool experimentIsBroadcasting=false;
501
502 Mat finalImageCol;
503
504#ifdef USE_CUDA
505 cuda::GpuMat finalImageB;
506 cuda::GpuMat finalImageG;
507 cuda::GpuMat finalImageR;
508 cuda::GpuMat fullImages[3];
509
510 // MOHSEN
511 cuda::GpuMat fullImagesHSV[3];
512 cuda::GpuMat grayImage, finalImageH, finalImageS, finalImageV;
513 // make thread safe
514 cuda::Stream stream;
515// cv::Mat finalCPUImage;
516#else
517 Mat finalImage;
518 Mat fullImages[3];
519#endif
520
521 MAT_TYPE warpedImages;
522 MAT_TYPE warpedMasks;
523 Point corners;
524 Size sizes;
525
526 vector < Mat > Ks;
527 vector < Mat > Rs;
528 Point2f arenaCorners[4];
529 bool haveCalibration = false;
530 QTimer tick;
531
532 acquireThread * threads = NULL;
533
534 int time = 0;
539 QPoint smallImageSize;
540
541// Ptr<detail::ExposureCompensator> compensator;
542// Ptr<detail::Blender> blender;
543
544 QElapsedTimer timer;
545
546 bool loadFirstIm = false;
547
548 srcDataType srcType = CAMERA;
549 QString videoPath;
550
551 trackerType trackType = MORFI_TRACKER; // MORFI_TRACKER; // MY_HAPPY_OTHER_TRACKER; // CIRCLES_LOCAL;// CIRCLES_NAIVE;
552
553 QVector < Kilobot * > kilos;
554
555 QVector < float > kiloHeadings;
556
557 QVector < QPointF > kiloOldPos;
558
559 QVector < QVector < int > > exclusionTestsIndices;
560
561 float last_time = 0.0f;
562
563 Size fullSize;
564 Point fullCorner;
565
566 int currentID = 0;
567 uint found = IDENTIFY_TIMEOUT;
568 QVector < uint > foundIDs;
569 QVector < int > assignedCircles;
570
571 experimentType expType = VRK_EXP; // M_EXP;// USER_EXP; // VRK_EXP;
572
573 Mat testAdap;
574
575 QVector < drawnCircle > circsToDraw;
576 QVector < drawnLine > linesToDraw;
577 QVector < drawnCircle > circsToDrawFinal;
578
579// QList<Vec3f> detectedCircles;
580
581#ifdef USE_CUDA
582 Ptr<cuda::HoughCirclesDetector> hough;
583 bool detectHeter = true;
584 Ptr<cuda::HoughCirclesDetector> houghLarger;
585 // RGB Hough
586 Ptr<cuda::HoughCirclesDetector> hough2;
587 cuda::GpuMat kbLocs;
588
589 Ptr<cuda::CLAHE> clahe;
590 Mat element = cv::getStructuringElement(MORPH_ELLIPSE,Size(7,7));
591 Ptr<cuda::Filter> dilateFilter;
592#endif
593
594 bool showIDs = true;
595 int flipangle = 0;
596 bool m_detectred=true;
597 bool m_detectgreen=true;
598 bool m_detectblue=true;
599 bool m_assignIDmanually=false;
600 bool m_runtimeIDenabled=true;
601
602 QVector <int> lost_count;
603
604 int m_runtimeIdentificationTimer = 0;
605 bool m_ongoingRuntimeIdentification = false;
606 QVector <int> pendingRuntimeIdentification;
607 QElapsedTimer runtimeIDtimer;
608
609 //video saving
610 bool savecamerasframes=false;
611 unsigned int numberofframes;
612 QString savecamerasframesdir;
613
614
615};
616
617#endif // ROBOTTRACKER_H
The KilobotTracker class.
Definition kilobottracker_copy.h:163
void SETUPloadCalibration()
loadCalibration Load the calibration matrices from an OpenCV FileStorage format
void showIds(bool toggle)
showIds
Definition robottracker.h:410
void errorMessage(QString)
errorMessage Qt signal to update the UI message QLabel
void LOOPiterate()
iterateTracker Use the existing feature matches to stitch the images and track the kilobots
void LOOPstartstop(int stage)
startLoop This slot is the target of the timeout on the QTimer tick, and fetches warped images from t...
void RefreshDisplayedImage()
RefreshDisplayedImage Refresh the displayed image on the GUI.
void setVideoDir(QString dir)
setVideoDir
Definition robottracker.h:392
void identifyKilobots()
identifyKilobots Find out what IDs the Kilobots have
void SETUPfindKilobots()
findKilobots Find the locations of Kilobots in the stitched image
The acquireThread class This thread acquires input data from a source, applies the local warps to the...
Definition kilobottracker_copy.cpp:42
Definition voronoii.cpp:9
Definition kilobottracker_copy.h:136
Definition kilobottracker_copy.h:145
Definition kilobottracker_copy.h:114
Definition kilobottracker_copy.h:119
Definition kilobot.h:31
Definition kilobottracker_copy.h:89