SLProject  4.2.000
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
CVTrackedAruco.cpp
Go to the documentation of this file.
1 /**
2  * \file CVTrackedAruco.cpp
3  * \date Winter 2016
4  * \remarks Please use clangformat to format the code. See more code style on
5  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
6  * \authors Marcus Hudritsch, Michael Goettlicher, Marino von Wattenwyl
7  * \copyright http://opensource.org/licenses/GPL-3.0
8  */
9 
10 /*
11 The OpenCV library version 3.4 or above with extra module must be present.
12 If the application captures the live video stream with OpenCV you have
13 to define in addition the constant APP_USES_CVCAPTURE.
14 All classes that use OpenCV begin with CV.
15 See also the class docs for CVCapture, CVCalibration and CVTracked
16 for a good top down information.
17 */
18 #include <CVTrackedAruco.h>
19 #include <Utils.h>
20 #include <Profiler.h>
21 
22 //-----------------------------------------------------------------------------
23 CVTrackedAruco::CVTrackedAruco(int arucoID, string calibIniPath)
24  : _calibIniPath(calibIniPath),
25  _arucoID(arucoID)
26 {
27  SLbool paramsLoaded = _params.loadFromFile(_calibIniPath);
28 
29  if (!paramsLoaded)
30  Utils::exitMsg("SLProject",
31  "CVTrackedAruco::track: Failed to load Aruco parameters.",
32  __LINE__,
33  __FILE__);
34 }
35 //-----------------------------------------------------------------------------
36 //! Tracks the all Aruco markers in the given image for the first sceneview
38  CVMat imageBgr,
39  CVCalibration* calib)
40 {
41  if (!trackAll(imageGray, imageBgr, calib))
42  {
43  return false;
44  }
45 
46  if (!arucoIDs.empty())
47  {
48  // Find the marker with the matching id
49  for (size_t i = 0; i < arucoIDs.size(); ++i)
50  {
51  if (arucoIDs[i] == _arucoID)
52  {
54  return true;
55  }
56  }
57  }
58 
59  return false;
60 }
61 //-----------------------------------------------------------------------------
63  CVMat imageBgr,
64  CVCalibration* calib,
65  CVRect roi)
66 {
68 
69  assert(!imageGray.empty() && "ImageGray is empty");
70  assert(!imageBgr.empty() && "ImageBGR is empty");
71  assert(!calib->cameraMat().empty() && "Calibration is empty");
72 
73 #if CV_MAJOR_VERSION < 4 || CV_MINOR_VERSION < 7
74  if (_params.arucoParams.empty() || _params.dictionary.empty())
75  {
76  Utils::warnMsg("SLProject",
77  "CVTrackedAruco::track: Aruco paramters are empty.",
78  __LINE__,
79  __FILE__);
80  return false;
81  }
82 #endif
83 
84  ////////////
85  // Detect //
86  ////////////
87 
88  CVMat croppedImageGray = roi.empty() ? imageGray : imageGray(roi);
89 
90  float startMS = _timer.elapsedTimeInMilliSec();
91 
92  arucoIDs.clear();
93  objectViewMats.clear();
94  CVVVPoint2f corners, rejected;
95 
96 #if CV_MAJOR_VERSION < 4 || CV_MINOR_VERSION < 7
97  cv::aruco::detectMarkers(croppedImageGray,
99  corners,
100  arucoIDs,
102  rejected);
103 #else
104  cv::aruco::ArucoDetector detector(_params.dictionary,
106  detector.detectMarkers(croppedImageGray,
107  corners,
108  arucoIDs,
109  rejected);
110 #endif
111 
112  for (auto& corner : corners)
113  {
114  for (auto& j : corner)
115  {
116  j.x += (float)roi.x;
117  j.y += (float)roi.y;
118  }
119  }
120 
122 
123  if (!arucoIDs.empty())
124  {
125  if (_drawDetection)
126  cv::aruco::drawDetectedMarkers(imageBgr,
127  corners,
128  arucoIDs,
129  cv::Scalar(0, 0, 255));
130 
131  /////////////////////
132  // Pose Estimation //
133  /////////////////////
134 
135  startMS = _timer.elapsedTimeInMilliSec();
136 
137  // find the camera extrinsic parameters (rVec & tVec)
138  CVVPoint3d rVecs, tVecs;
139  cv::aruco::estimatePoseSingleMarkers(corners,
141  calib->cameraMat(),
142  calib->distortion(),
143  rVecs,
144  tVecs);
145 
147 
148  // Get the object view matrix for all aruco markers
149  for (size_t i = 0; i < arucoIDs.size(); ++i)
150  {
151  CVMatx44f ovm = createGLMatrix(cv::Mat(tVecs[i]), cv::Mat(rVecs[i]));
152  objectViewMats.push_back(ovm);
153 
154  if (_drawDetection)
155  {
156 #if CV_MAJOR_VERSION < 4 || CV_MINOR_VERSION < 6
157 #else
158  cv::drawFrameAxes(imageBgr,
159  calib->cameraMat(),
160  calib->distortion(),
161  cv::Mat(rVecs[i]),
162  cv::Mat(tVecs[i]),
163  0.01f);
164 #endif
165  }
166  }
167  }
168 
169  return true;
170 }
171 //-----------------------------------------------------------------------------
172 /*! CVTrackedAruco::drawArucoMarkerBoard draws and saves an aruco board
173 into an image.
174 @param dictionaryId integer id of the dictionary
175 @param numMarkersX NO. of markers in x-direction
176 @param numMarkersY NO. of markers in y-direction
177 @param markerEdgeM Length of one marker in meters
178 @param markerSepaM Separation between markers in meters
179 @param imgName Image filename inclusive format extension
180 @param dpi Dots per inch (default 256)
181 @param showImage Shows image in window (
182 default false)
183 */
185  int numMarkersX,
186  int numMarkersY,
187  float markerEdgeM,
188  float markerSepaM,
189  const string& imgName,
190  float dpi,
191  bool showImage)
192 {
193 #if CV_MAJOR_VERSION < 4 || CV_MINOR_VERSION < 7
194  cv::Ptr<cv::aruco::Dictionary> dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
195  cv::Ptr<cv::aruco::GridBoard> board = cv::aruco::GridBoard::create(numMarkersX,
196  numMarkersY,
197  markerEdgeM,
198  markerSepaM,
199  dictionary);
200  CVSize imageSize;
201  imageSize.width = (int)((markerEdgeM + markerSepaM) * 100.0f / 2.54f * dpi * (float)numMarkersX);
202  imageSize.height = (int)((markerEdgeM + markerSepaM) * 100.0f / 2.54f * dpi * (float)numMarkersY);
203 
204  imageSize.width -= (imageSize.width % 4);
205  imageSize.height -= (imageSize.height % 4);
206 
207  // show created board
208  CVMat boardImage;
209  board->draw(imageSize, boardImage, 0, 1);
210 
211  if (showImage)
212  {
213  imshow("board", boardImage);
214  cv::waitKey(0);
215  }
216 #else
217  cv::aruco::Dictionary dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::PredefinedDictionaryType(dictionaryId));
218  cv::aruco::GridBoard board = cv::aruco::GridBoard(cv::Size(numMarkersX, numMarkersY),
219  markerEdgeM,
220  markerSepaM,
221  dictionary);
222 
223  CVSize imageSize;
224  imageSize.width = (int)((markerEdgeM + markerSepaM) * 100.0f / 2.54f * dpi * (float)numMarkersX);
225  imageSize.height = (int)((markerEdgeM + markerSepaM) * 100.0f / 2.54f * dpi * (float)numMarkersY);
226 
227  imageSize.width -= (imageSize.width % 4);
228  imageSize.height -= (imageSize.height % 4);
229 
230  // show created board
231  CVMat boardImage;
232  cv::aruco::drawPlanarBoard(&board,
233  imageSize,
234  boardImage,
235  0,
236  1);
237 # ifndef __EMSCRIPTEN__
238  if (showImage)
239  {
240  imshow("board", boardImage);
241  cv::waitKey(0);
242  }
243 # endif
244 #endif
245 
246 #ifndef __EMSCRIPTEN__
247  imwrite(imgName, boardImage);
248 #endif
249 }
250 //-----------------------------------------------------------------------------
251 void CVTrackedAruco::drawArucoMarker(int dictionaryId,
252  int minMarkerId,
253  int maxMarkerId,
254  int markerSizePX)
255 {
256  assert(dictionaryId > 0);
257  assert(minMarkerId > 0);
258  assert(minMarkerId < maxMarkerId);
259 
260 #if CV_MAJOR_VERSION < 4 || CV_MINOR_VERSION < 7
261  cv::Ptr<cv::aruco::Dictionary> dict = getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
262  if (maxMarkerId > dict->bytesList.rows)
263  maxMarkerId = dict->bytesList.rows;
264 
265  CVMat markerImg;
266 
267  for (int i = minMarkerId; i < maxMarkerId; ++i)
268  {
269  cv::aruco::drawMarker(dict, i, markerSizePX, markerImg, 1);
270 # ifndef __EMSCRIPTEN__
271  imwrite(Utils::formatString("ArucoMarker_Dict%d_%dpx_Id%d.png",
272  dictionaryId,
273  markerSizePX,
274  i),
275  markerImg);
276 # endif
277  }
278 #else
279  cv::aruco::Dictionary dict = getPredefinedDictionary(cv::aruco::PredefinedDictionaryType(dictionaryId));
280  if (maxMarkerId > dict.bytesList.rows)
281  maxMarkerId = dict.bytesList.rows;
282 
283  CVMat markerImg;
284 
285  for (int i = minMarkerId; i < maxMarkerId; ++i)
286  {
287  cv::aruco::generateImageMarker(dict,
288  i,
289  markerSizePX,
290  markerImg,
291  1);
292 # ifndef __EMSCRIPTEN__
293  imwrite(Utils::formatString("ArucoMarker_Dict%d_%dpx_Id%d.png",
294  dictionaryId,
295  markerSizePX,
296  i),
297  markerImg);
298 # endif
299  }
300 #endif
301 }
302 //-----------------------------------------------------------------------------
static SLint dpi
Dot per inch resolution of screen.
Definition: AppGLFW.cpp:41
cv::Matx44f CVMatx44f
Definition: CVTypedefs.h:59
vector< cv::Point3d > CVVPoint3d
Definition: CVTypedefs.h:80
cv::Rect CVRect
Definition: CVTypedefs.h:39
cv::Size CVSize
Definition: CVTypedefs.h:55
cv::Mat CVMat
Definition: CVTypedefs.h:38
vector< vector< cv::Point2f > > CVVVPoint2f
Definition: CVTypedefs.h:96
#define PROFILE_FUNCTION()
Definition: Instrumentor.h:41
bool SLbool
Definition: SL.h:175
bool loadFromFile(string calibIniPath)
cv::Ptr< cv::aruco::DetectorParameters > arucoParams
detector parameter structure for aruco detection function
float edgeLength
marker edge length
cv::Ptr< cv::aruco::Dictionary > dictionary
predefined dictionary
Live video camera calibration class with OpenCV an OpenCV calibration.
Definition: CVCalibration.h:71
const CVMat & cameraMat() const
const CVMat & distortion() const
bool track(CVMat imageGray, CVMat imageBgr, CVCalibration *calib)
Tracks the all Aruco markers in the given image for the first sceneview.
static void drawArucoMarkerBoard(int dictionaryId, int numMarkersX, int numMarkersY, float markerEdgeLengthM, float markerSepaM, const string &imgName, float dpi=254.0f, bool showImage=false)
Helper function to draw and save an aruco marker board image.
CVArucoParams _params
Aruco parameters.
int _arucoID
Aruco Marker ID for this node.
static void drawArucoMarker(int dictionaryId, int minMarkerId, int maxMarkerId, int markerSizePX=200)
Helper function to draw and save an aruco marker set.
CVTrackedAruco(int arucoID, string calibIniPath)
bool trackAll(CVMat imageGray, CVMat imageBgr, CVCalibration *calib, CVRect roi=CVRect(0, 0, 0, 0))
vector< int > arucoIDs
detected Aruco marker IDs
CVVMatx44f objectViewMats
object view matrices for all found markers
CVMatx44f _objectViewMat
view transformation matrix
Definition: CVTracked.h:93
static AvgFloat detectTimesMS
Averaged time for video feature detection & description in ms.
Definition: CVTracked.h:83
bool _drawDetection
Flag if detection should be drawn into image.
Definition: CVTracked.h:92
static cv::Matx44f createGLMatrix(const CVMat &tVec, const CVMat &rVec)
Create an OpenGL 4x4 matrix from an OpenCV translation & rotation vector.
Definition: CVTracked.cpp:46
HighResTimer _timer
High resolution timer.
Definition: CVTracked.h:94
static AvgFloat poseTimesMS
Averaged time for video feature pose estimation in ms.
Definition: CVTracked.h:88
float elapsedTimeInMilliSec()
Definition: HighResTimer.h:38
void set(T value)
Sets the current value in the value array and builds the average.
Definition: Averaged.h:53
string formatString(string fmt_str,...)
Returns a formatted string as sprintf.
Definition: Utils.cpp:320
void warnMsg(const char *tag, const char *msg, const int line, const char *file)
Platform independent warn message output.
Definition: Utils.cpp:1145
void exitMsg(const char *tag, const char *msg, const int line, const char *file)
Terminates the application with a message. No leak checking.
Definition: Utils.cpp:1135