-
Notifications
You must be signed in to change notification settings - Fork 0
/
Marker.h
542 lines (446 loc) · 16.5 KB
/
Marker.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
/*
* This file is part of ALVAR, A Library for Virtual and Augmented Reality.
*
* Copyright 2007-2012 VTT Technical Research Centre of Finland
*
* Contact: VTT Augmented Reality Team <[email protected]>
* <http://www.vtt.fi/multimedia/alvar.html>
*
* ALVAR is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with ALVAR; if not, see
* <http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>.
*/
#ifndef MARKER_H
#define MARKER_H
/**
* \file Marker.h
*
* \brief This file implements a marker interface as well as ALVAR markers and
* ARToolKit markers.
*/
/*****************************************************************************
****************************** I N C L U D E ******************************
****************************************************************************/
#include "Alvar.h"
#include <iostream>
#include <algorithm>
#include "Util.h"
#include "Camera.h"
#include "Pose.h"
#include "Bitset.h"
#include <vector>
namespace alvar {
//#define VISUALIZE_MARKER_POINTS
/*****************************************************************************
*
*** class Marker
*
* * \brief Basic 2D \e Marker functionality.
*
* This class contains the basic \e Marker functionality for planar markers.
*
*****************************************************************************/
class ALVAR_EXPORT Marker
{
public:
static const int MARGIN_ERROR = 1;
static const int DECODE_ERROR = 2;
static const int TRACK_ERROR = 4;
/** \brief Default constructor
* \param _edge_length Length of the marker's edge in whatever units you are using (e.g. cm)
* \param _res The marker content resolution in pixels (this is actually
* \param _margin The marker margin resolution in pixels (The actual captured marker image has pixel resolution of _margin+_res+_margin)
*/
Marker(double _edge_length = 0, int _res = 0, double _margin = 0);
/** \brief Copy constructor */
Marker(const Marker& m);
/** \brief Destructor */
virtual ~Marker() = default;
Marker& operator=(const Marker& rhs) = delete;
/** \brief Compares the marker corners with the previous match.
*
* In some cases the tracking of the marker can be accepted solely based on this.
* Returns the marker orientation and an error value describing the pixel error
* relative to the marker diameter.
*/
void CompareCorners(std::vector<PointDouble>& _marker_corners_img, int* orientation, double* error);
/** \brief Compares the marker corners with the previous match.
*/
void CompareContent(std::vector<PointDouble>& _marker_corners_img, cv::Mat& gray, Camera& cam,
int* orientation) const;
/** \brief Updates the \e marker_content from the image using \e Homography
*/
virtual bool UpdateContent(std::vector<PointDouble>& _marker_corners_img, cv::Mat& gray, Camera& cam,
int frame_no = 0)
{
return (UpdateContentBasic(_marker_corners_img, gray, cam, frame_no));
}
/** \brief Updates the markers \e pose estimation
*/
void UpdatePose(std::vector<PointDouble>& _marker_corners_img, Camera& cam, int orientation,
int frame_no = 0, bool update_pose = true);
/** \brief Decodes the marker content. Please call \e UpdateContent before this.
* This virtual method is meant to be implemented by heirs.
*/
virtual bool DecodeContent(int& orientation);
/** \brief Returns the content as a matrix
*/
cv::Mat& GetContent()
{
return (marker_content);
}
/** \brief Saves the marker as an image
*/
void SaveMarkerImage(const char* filename, int save_res = 0) const;
/** \brief Draw the marker filling the ROI in the given image
*/
void ScaleMarkerToImage(cv::Mat& image) const;
/** \brief Visualize the marker
*/
void Visualize(cv::Mat& image, Camera& cam, cv::Scalar color = cv::Scalar(0, 0, 255)) const;
/** \brief Method for resizing the marker dimensions */
void SetMarkerSize(double _edge_length = 0, int _res = 0, double _margin = 0);
/** \brief Get edge length (to support different size markers */
double GetMarkerEdgeLength() const
{
return (edge_length);
}
/** \brief Get id for this marker
*
* This is used e.g. in MarkerDetector to associate a marker id with
* an appropriate edge length. This method should be overwritten
* to return a suitable identification number for each marker type.
*/
virtual unsigned long GetId() const
{
return (0);
}
virtual void SetId(unsigned long /* _id */)
{
return;
}
/**
* Returns the resolution (the number of square rows and columns) of the
* marker content area. The total number of content squares within the
* content area is resolution*resolution.
*/
int GetRes() const
{
return (res);
}
/**
* Returns the margin thickness, that is, the number of rows or columns of
* black squares surrounding the content area.
*/
double GetMargin() const
{
return (margin);
}
/** \brief Get marker detection error estimate
* \param errors Flags indicating what error elements are combined
* The marker detection error can consist of several elements:
* MARGIN_ERROR is updated in \e UpdateContent and it indicates erroneous values inside the marginal area.
* DECODE_ERROR is updated in \e DecodeContent and it indicates erroneous values inside the actual marker content area.
* TRACK_ERROR is updated in \e MarkerDetector.Detect and it indicates the amount of tracking error returned from \e CompareCorners
*/
double GetError(int errors = (MARGIN_ERROR | DECODE_ERROR)) const
{
int count = 0;
double error = 0;
if (errors & MARGIN_ERROR)
{
error += margin_error;
count++;
}
if (errors & DECODE_ERROR)
{
error += decode_error;
count++;
}
if (errors & TRACK_ERROR)
{
error += track_error;
count++;
}
return (error/count);
}
/** \brief Set the marker error estimate */
void SetError(int error_type, double value)
{
if (error_type == MARGIN_ERROR)
margin_error = value;
else if (error_type == DECODE_ERROR)
decode_error = value;
else if (error_type == TRACK_ERROR)
track_error = value;
return;
}
/** \brief Marker color points in marker coordinates */
std::vector<PointDouble> marker_points;
/** \brief Marker corners in marker coordinates */
std::vector<PointDouble> marker_corners;
/** \brief Marker corners in image coordinates */
std::vector<PointDouble> marker_corners_img;
/** \brief Samples to be used in figuring out min/max for thresholding */
std::vector<PointDouble> marker_margin_w;
/** \brief Samples to be used in figuring out min/max for thresholding */
std::vector<PointDouble> marker_margin_b;
#ifdef VISUALIZE_MARKER_POINTS
std::vector<PointDouble> marker_allpoints_img;
#endif
protected:
static const int HEADER_SIZE = 8;
/** \brief The current marker \e Pose
*/
Pose pose;
double margin_error;
double decode_error;
double track_error;
double edge_length;
int res;
double margin;
cv::Mat marker_content;
void VisualizeMarkerPose(cv::Mat& image, Camera& cam,
std::vector<cv::Point2d>& visualize2d_points,
cv::Scalar color = cv::Scalar(0, 0, 255)) const;
virtual void VisualizeMarkerContent(cv::Mat& image, Camera& cam,
cv::Point2d datatext_point, cv::Point2d content_point) const;
virtual void VisualizeMarkerError(cv::Mat& image, Camera& cam,
cv::Point2d errortext_point) const;
bool UpdateContentBasic(std::vector<PointDouble>& _marker_corners_img, cv::Mat& gray, Camera& cam,
int frame_no = 0);
private:
}; // end of class Marker
/*****************************************************************************
*
*** class MarkerArtoolkit
*
* \brief \e MarkerArtoolkit for using matrix markers similar with the ones used in ARToolkit.
*
*****************************************************************************/
class ALVAR_EXPORT MarkerArtoolkit : public Marker
{
public:
/** \brief Constructor */
MarkerArtoolkit(double _edge_length = 0, int _res = 0, double _margin = 0) :
Marker(_edge_length, (_res?_res : 3), (_margin?_margin : 1.5))
{
return;
}
MarkerArtoolkit(const MarkerArtoolkit& src) : Marker(src)
{
id = src.id;
return;
}
virtual ~MarkerArtoolkit() = default;
MarkerArtoolkit& operator=(const MarkerArtoolkit& rhs) = delete;
/** \brief Get ID for recognizing this marker */
unsigned long GetId() const
{
return (id);
}
void SetId(unsigned long _id)
{
id = _id;
}
/** \brief \e DecodeContent should be called after \e UpdateContent to fill \e content_type, \e decode_error and \e data */
bool DecodeContent(int& orientation) override;
/** \brief Updates the \e marker_content by "encoding" the given parameters */
void SetContent(unsigned long _id);
protected:
/** \brief \e MarkerArtoolkit supports only 'id' as data type */
unsigned long id;
int default_res()
{
std::cout << "MarkerArtoolkit::default_res" << std::endl;
return (3);
}
double default_margin()
{
return (1.5);
}
private:
}; // end of class MarkerArtoolkit
/**
* \brief \e MarkerData contains matrix of Hamming encoded data.
*/
/*****************************************************************************
*
*** class MarkerData
*
*****************************************************************************/
class ALVAR_EXPORT MarkerData : public Marker
{
public:
static const int MAX_MARKER_STRING_LEN = 2048;
enum MarkerContentType
{
MARKER_CONTENT_TYPE_NUMBER,
MARKER_CONTENT_TYPE_STRING,
MARKER_CONTENT_TYPE_FILE,
MARKER_CONTENT_TYPE_HTTP
};
unsigned char content_type;
/** \brief \e MarkerData content can be presented either as number (\e MARKER_CONTENT_TYPE_NUMBER) or string */
union
{
unsigned long id;
char str[MAX_MARKER_STRING_LEN];
} data;
/** \brief Default constructor
* \param _edge_length Length of the marker's edge in whatever units you are using (e.g. cm)
* \param _res The marker content resolution in pixels (this is actually
* \param _margin The marker margin resolution in pixels (The actual captured marker image has pixel resolution of _margin+_res+_margin)
*/
MarkerData(double _edge_length = 0, int _res = 0, double _margin = 0) :
Marker(_edge_length, _res, ((_margin >= 0.0) ? _margin : 2.0))
{
return;
}
MarkerData(const MarkerData& src) : Marker(src)
{
content_type = src.content_type;
data = src.data;
return;
}
virtual ~MarkerData() = default;
MarkerData& operator=(const MarkerData& rhs) = delete;
/** \brief Get ID for recognizing this marker */
unsigned long GetId() const
{
return (data.id);
}
/** \brief Set the ID */
void SetId(unsigned long _id)
{
data.id = _id;
return;
}
/** \brief Updates the \e marker_content from the image using \e Homography
* Compared to the basic implementation in \e Marker this will also detect the marker
* resolution automatically when the marker resolution is specified to be 0.
*/
virtual bool UpdateContent(std::vector<PointDouble>& _marker_corners_img, cv::Mat& gray, Camera& cam,
int frame_no = 0) override;
/** \brief \e DecodeContent should be called after \e UpdateContent to fill \e content_type, \e decode_error and \e data
*/
bool DecodeContent(int& orientation) override;
/** \brief Updates the \e marker_content by "encoding" the given parameters
*/
void SetContent(MarkerContentType content_type, unsigned long id, const char* str,
bool force_strong_hamming = false, bool verbose = false);
protected:
virtual void VisualizeMarkerContent(cv::Mat& image, Camera& cam, cv::Point2d datatext_point,
cv::Point2d content_point) const override;
void DecodeOrientation(int& error, int& total, int& orientation);
int DecodeCode(int orientation, BitsetExt& bs, int& erroneous, int& total, unsigned char& content_type);
void Read6bitStr(const BitsetExt& bs, char* s, size_t s_max_len);
void Add6bitStr(BitsetExt& bs, char *s);
int UsableDataBits(int marker_res, int hamming);
bool DetectResolution(std::vector<PointDouble>& _marker_corners_img, cv::Mat& gray, Camera& cam);
private:
}; // end of class MarkerData
#if 0
/*****************************************************************************
*
*** class MarkerIterator
*
* Iterator type for traversing templated Marker vector without the template.
*
*****************************************************************************/
class ALVAR_EXPORT MarkerIterator : public std::iterator<std::forward_iterator_tag, Marker*>
{
public:
public:
MarkerIterator()
{
return;
}
~MarkerIterator()
{
return;
}
virtual bool operator==(const MarkerIterator& other) = 0;
virtual bool operator!=(const MarkerIterator& other) = 0;
virtual MarkerIterator& operator++() = 0;
virtual const Marker* operator*() = 0;
virtual const Marker* operator->() = 0;
virtual MarkerIterator& reset() = 0;
void* _data;
private:
MarkerIterator(const MarkerIterator& src);
}; // end of class MarkerIterator
/*****************************************************************************
*
*** class MarkerIteratorImpl
*
* Iterator implementation for traversing templated Marker vector
* without the template.
* \param T T extends Marker
*
*****************************************************************************/
template<typename T>
class ALVAR_EXPORT MarkerIteratorImpl : public MarkerIterator
{
public:
MarkerIteratorImpl(typename std::vector<T>::const_iterator i) : _begin(i), _i(i)
{
_data = this;
return;
}
~MarkerIteratorImpl()
{
return;
}
// The assignment and relational operators are straightforward
MarkerIteratorImpl& operator=(const MarkerIteratorImpl& other)
{
_i = other._i;
return (*this);
}
bool operator==(const MarkerIterator& other)
{
MarkerIteratorImpl* pother = (MarkerIteratorImpl*)other._data;
return (_i == pother->_i);
}
bool operator!=(const MarkerIterator& other)
{
MarkerIteratorImpl* pother = (MarkerIteratorImpl*)other._data;
return (_i != pother->_i);
}
MarkerIterator& operator++()
{
_i++;
return (*this);
}
const Marker* operator*()
{
return (&(*_i));
}
const Marker* operator->()
{
return (&(*_i));
}
MarkerIterator& reset()
{
_i = _begin;
return (*this);
}
private:
typename std::vector<T>::const_iterator _begin;
typename std::vector<T>::const_iterator _i;
MarkerIteratorImpl(const MarkerIteratorImpl& src);
}; // end of class MarkerIteratorImpl
#endif
} // namespace alvar
#endif