JeVoisBase  1.20
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
ArUco.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
20 #include <jevois/Core/Module.H>
21 #include <opencv2/calib3d.hpp> // for projectPoints()
22 #include <opencv2/imgproc/imgproc.hpp>
23 
24 #include <Eigen/Geometry> // for AngleAxis and Quaternion
25 
26 // ##############################################################################################################
28 { }
29 
30 // ##############################################################################################################
32 {
33  // Defer reading camera parameters to first processed frame, so we know the resolution:
35 
36  // Init detector parameters:
39  cv::aruco::DetectorParameters dparams;
40 
41  switch (aruco::dictionary::get())
42  {
43  case aruco::Dict::ATAG_16h5:
44  case aruco::Dict::ATAG_25h9:
45  case aruco::Dict::ATAG_36h10:
46  case aruco::Dict::ATAG_36h11:
47  dparams.cornerRefinementMethod = cv::aruco::CORNER_REFINE_APRILTAG;
48  break;
49 
50  default:
51  dparams.cornerRefinementMethod = cv::aruco::CORNER_REFINE_SUBPIX;
52  }
53 
54  // Read detector parameters if any:
55  std::string const dpf = aruco::detparams::get();
56  if (dpf.empty() == false)
57  {
58  cv::FileStorage fs(dpf, cv::FileStorage::READ);
59  if (fs.isOpened())
60  {
61  if (dparams.readDetectorParameters(fs.root()) == false)
62  LERROR("Error reading ArUco detector parameters from file [" << dpf <<"] -- IGNORED");
63  }
64  else LERROR("Failed to read ArUco detector parameters from file [" << dpf << "] -- IGNORED");
65  }
66 
67  // Instantiate the dictionary:
68  cv::aruco::Dictionary dico;
69  switch (aruco::dictionary::get())
70  {
71  case aruco::Dict::Original: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_ARUCO_ORIGINAL);break;
72  case aruco::Dict::D4X4_50: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50); break;
73  case aruco::Dict::D4X4_100: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_100); break;
74  case aruco::Dict::D4X4_250: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_250); break;
75  case aruco::Dict::D4X4_1000: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_1000); break;
76  case aruco::Dict::D5X5_50: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_5X5_50); break;
77  case aruco::Dict::D5X5_100: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_5X5_100); break;
78  case aruco::Dict::D5X5_250: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_5X5_250); break;
79  case aruco::Dict::D5X5_1000: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_5X5_1000); break;
80  case aruco::Dict::D6X6_50: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_50); break;
81  case aruco::Dict::D6X6_100: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_100); break;
82  case aruco::Dict::D6X6_250: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250); break;
83  case aruco::Dict::D6X6_1000: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_1000); break;
84  case aruco::Dict::D7X7_50: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_7X7_50); break;
85  case aruco::Dict::D7X7_100: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_7X7_100); break;
86  case aruco::Dict::D7X7_250: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_7X7_250); break;
87  case aruco::Dict::D7X7_1000: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_7X7_1000); break;
88  case aruco::Dict::ATAG_16h5: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_APRILTAG_16h5); break;
89  case aruco::Dict::ATAG_25h9: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_APRILTAG_25h9); break;
90  case aruco::Dict::ATAG_36h10: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_APRILTAG_36h10); break;
91  case aruco::Dict::ATAG_36h11: dico = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_APRILTAG_36h11); break;
92  }
93 
94  // Instantiate the detector (we use default refinement parameters):
95  itsDetector = cv::Ptr<cv::aruco::ArucoDetector>(new cv::aruco::ArucoDetector(dico, dparams));
96 }
97 
98 // ##############################################################################################################
100 {
101  itsDetector.release();
102  itsCamMatrix = cv::Mat();
103  itsDistCoeffs = cv::Mat();
107 }
108 
109 // ##############################################################################################################
110 void ArUco::detectMarkers(cv::InputArray image, cv::OutputArray ids, cv::OutputArrayOfArrays corners)
111 {
112  if (itsCamMatrix.empty())
113  {
114  std::string const cpf = std::string(JEVOIS_SHARE_PATH) + "/camera/" + aruco::camparams::get() +
115  std::to_string(image.cols()) + 'x' + std::to_string(image.rows()) + ".yaml";
116 
117  cv::FileStorage fs(cpf, cv::FileStorage::READ);
118  if (fs.isOpened())
119  {
120  fs["camera_matrix"] >> itsCamMatrix;
121  fs["distortion_coefficients"] >> itsDistCoeffs;
122  LINFO("Loaded camera calibration from " << cpf);
123  }
124  else
125  {
126  LERROR("Failed to read camera parameters from file [" << cpf << "] -- IGNORED");
127  itsCamMatrix = cv::Mat::eye(3, 3, CV_64F);
128  itsDistCoeffs = cv::Mat::zeros(5, 1, CV_64F);
129  }
130  }
131 
132  itsDetector->detectMarkers(image, corners, ids);
133 }
134 
135 // ##############################################################################################################
136 void ArUco::estimatePoseSingleMarkers(cv::InputArrayOfArrays corners, cv::OutputArray rvecs, cv::OutputArray tvecs)
137 {
138  cv::aruco::estimatePoseSingleMarkers(corners, markerlen::get(), itsCamMatrix, itsDistCoeffs, rvecs, tvecs);
139 }
140 
141 // ##############################################################################################################
142 void ArUco::sendSerial(jevois::StdModule * mod, std::vector<int> ids, std::vector<std::vector<cv::Point2f> > corners,
143  unsigned int w, unsigned int h, std::vector<cv::Vec3d> const & rvecs,
144  std::vector<cv::Vec3d> const & tvecs)
145 {
146  if (rvecs.empty() == false)
147  {
148  float const siz = markerlen::get();
149 
150  // If we have rvecs and tvecs, we are doing 3D pose estimation, so send a 3D message:
151  for (size_t i = 0; i < corners.size(); ++i)
152  {
153  cv::Vec3d const & rv = rvecs[i];
154  cv::Vec3d const & tv = tvecs[i];
155 
156  // Compute quaternion:
157  float theta = std::sqrt(rv[0] * rv[0] + rv[1] * rv[1] + rv[2] * rv[2]);
158  Eigen::Vector3f axis(rv[0], rv[1], rv[2]);
159  Eigen::Quaternion<float> q(Eigen::AngleAxis<float>(theta, axis));
160 
161  mod->sendSerialStd3D(tv[0], tv[1], tv[2], // position
162  siz, siz, 1.0F, // size
163  q.w(), q.x(), q.y(), q.z(), // pose
164  "U" + std::to_string(ids[i])); // decoded ID with "U" prefix for ArUco
165  }
166  }
167  else
168  {
169  // Send one 2D message per marker:
170  for (size_t i = 0; i < corners.size(); ++i)
171  {
172  std::vector<cv::Point2f> const & currentMarker = corners[i];
173  mod->sendSerialContour2D(w, h, currentMarker, "U" + std::to_string(ids[i]));
174  }
175  }
176 }
177 
178 // ##############################################################################################################
179 void ArUco::drawDetections(jevois::RawImage & outimg, int txtx, int txty, std::vector<int> ids,
180  std::vector<std::vector<cv::Point2f> > corners, std::vector<cv::Vec3d> const & rvecs,
181  std::vector<cv::Vec3d> const & tvecs)
182 {
183  // This code is like drawDetectedMarkers() in cv::aruco, but for YUYV output image:
184  int nMarkers = int(corners.size());
185  for (int i = 0; i < nMarkers; ++i)
186  {
187  std::vector<cv::Point2f> const & currentMarker = corners[i];
188 
189  // draw marker sides and prepare serial out string:
190  for (int j = 0; j < 4; ++j)
191  {
192  cv::Point2f const & p0 = currentMarker[j];
193  cv::Point2f const & p1 = currentMarker[ (j+1) % 4 ];
194  jevois::rawimage::drawLine(outimg, int(p0.x + 0.5F), int(p0.y + 0.5F),
195  int(p1.x + 0.5F), int(p1.y + 0.5F), 1, jevois::yuyv::LightGreen);
196  }
197 
198  // draw first corner mark
199  jevois::rawimage::drawDisk(outimg, int(currentMarker[0].x + 0.5F), int(currentMarker[0].y + 0.5F),
200  3, jevois::yuyv::LightGreen);
201 
202  // draw ID
203  if (ids.empty() == false)
204  {
205  cv::Point2f cent(0.0F, 0.0F); for (int p = 0; p < 4; ++p) cent += currentMarker[p] * 0.25F;
206  jevois::rawimage::writeText(outimg, std::string("id=") + std::to_string(ids[i]),
207  int(cent.x + 0.5F), int(cent.y + 0.5F) - 5, jevois::yuyv::LightGreen);
208  }
209  }
210 
211  // This code is like drawAxis() in cv::aruco, but for YUYV output image:
212  if (dopose::get() && ids.empty() == false)
213  {
214  float const length = markerlen::get() * 0.4F;
215 
216  for (size_t i = 0; i < ids.size(); ++i)
217  {
218  // Project axis points:
219  std::vector<cv::Point3f> axisPoints;
220  axisPoints.push_back(cv::Point3f(0.0F, 0.0F, 0.0F));
221  axisPoints.push_back(cv::Point3f(length, 0.0F, 0.0F));
222  axisPoints.push_back(cv::Point3f(0.0F, length, 0.0F));
223  axisPoints.push_back(cv::Point3f(0.0F, 0.0F, length));
224 
225  std::vector<cv::Point2f> imagePoints;
226  cv::projectPoints(axisPoints, rvecs[i], tvecs[i], itsCamMatrix, itsDistCoeffs, imagePoints);
227 
228  // Draw axis lines
229  jevois::rawimage::drawLine(outimg, int(imagePoints[0].x + 0.5F), int(imagePoints[0].y + 0.5F),
230  int(imagePoints[1].x + 0.5F), int(imagePoints[1].y + 0.5F),
231  2, jevois::yuyv::MedPurple);
232  jevois::rawimage::drawLine(outimg, int(imagePoints[0].x + 0.5F), int(imagePoints[0].y + 0.5F),
233  int(imagePoints[2].x + 0.5F), int(imagePoints[2].y + 0.5F),
234  2, jevois::yuyv::MedGreen);
235  jevois::rawimage::drawLine(outimg, int(imagePoints[0].x + 0.5F), int(imagePoints[0].y + 0.5F),
236  int(imagePoints[3].x + 0.5F), int(imagePoints[3].y + 0.5F),
237  2, jevois::yuyv::MedGrey);
238 
239  // Also draw a cube if requested:
240  if (showcube::get())
241  {
242  float const len = markerlen::get() * 0.5F;
243 
244  std::vector<cv::Point3f> cubePoints;
245  cubePoints.push_back(cv::Point3f(-len, -len, 0.0F));
246  cubePoints.push_back(cv::Point3f(len, -len, 0.0F));
247  cubePoints.push_back(cv::Point3f(len, len, 0.0F));
248  cubePoints.push_back(cv::Point3f(-len, len, 0.0F));
249  cubePoints.push_back(cv::Point3f(-len, -len, len * 2.0F));
250  cubePoints.push_back(cv::Point3f(len, -len, len * 2.0F));
251  cubePoints.push_back(cv::Point3f(len, len, len * 2.0F));
252  cubePoints.push_back(cv::Point3f(-len, len, len * 2.0F));
253 
254  std::vector<cv::Point2f> cuf;
255  cv::projectPoints(cubePoints, rvecs[i], tvecs[i], itsCamMatrix, itsDistCoeffs, cuf);
256 
257  // Round all the coordinates:
258  std::vector<cv::Point> cu;
259  for (auto const & p : cuf) cu.push_back(cv::Point(int(p.x + 0.5F), int(p.y + 0.5F)));
260 
261  // Draw cube lines:
262  jevois::rawimage::drawLine(outimg, cu[0].x, cu[0].y, cu[1].x, cu[1].y, 2, jevois::yuyv::LightGreen);
263  jevois::rawimage::drawLine(outimg, cu[1].x, cu[1].y, cu[2].x, cu[2].y, 2, jevois::yuyv::LightGreen);
264  jevois::rawimage::drawLine(outimg, cu[2].x, cu[2].y, cu[3].x, cu[3].y, 2, jevois::yuyv::LightGreen);
265  jevois::rawimage::drawLine(outimg, cu[3].x, cu[3].y, cu[0].x, cu[0].y, 2, jevois::yuyv::LightGreen);
266  jevois::rawimage::drawLine(outimg, cu[4].x, cu[4].y, cu[5].x, cu[5].y, 2, jevois::yuyv::LightGreen);
267  jevois::rawimage::drawLine(outimg, cu[5].x, cu[5].y, cu[6].x, cu[6].y, 2, jevois::yuyv::LightGreen);
268  jevois::rawimage::drawLine(outimg, cu[6].x, cu[6].y, cu[7].x, cu[7].y, 2, jevois::yuyv::LightGreen);
269  jevois::rawimage::drawLine(outimg, cu[7].x, cu[7].y, cu[4].x, cu[4].y, 2, jevois::yuyv::LightGreen);
270  jevois::rawimage::drawLine(outimg, cu[0].x, cu[0].y, cu[4].x, cu[4].y, 2, jevois::yuyv::LightGreen);
271  jevois::rawimage::drawLine(outimg, cu[1].x, cu[1].y, cu[5].x, cu[5].y, 2, jevois::yuyv::LightGreen);
272  jevois::rawimage::drawLine(outimg, cu[2].x, cu[2].y, cu[6].x, cu[6].y, 2, jevois::yuyv::LightGreen);
273  jevois::rawimage::drawLine(outimg, cu[3].x, cu[3].y, cu[7].x, cu[7].y, 2, jevois::yuyv::LightGreen);
274  }
275 
276  }
277  }
278 
279  if (txtx >=0 && txty >= 0)
280  jevois::rawimage::writeText(outimg, "Detected " + std::to_string(ids.size()) + " ArUco markers.",
281  txtx, txty, jevois::yuyv::White);
282 }
283 
284 #ifdef JEVOIS_PRO
285 // ##############################################################################################################
286 void ArUco::drawDetections(jevois::GUIhelper & helper, std::vector<int> ids,
287  std::vector<std::vector<cv::Point2f> > corners, std::vector<cv::Vec3d> const & rvecs,
288  std::vector<cv::Vec3d> const & tvecs)
289 {
290  ImU32 const col = ImColor(128, 255, 128, 255); // light green for lines
291 
292  // This code is like drawDetectedMarkers() in cv::aruco, but for ImGui:
293  int nMarkers = int(corners.size());
294  for (int i = 0; i < nMarkers; ++i)
295  {
296  std::vector<cv::Point2f> const & currentMarker = corners[i];
297 
298  // draw marker sides and prepare serial out string:
299  helper.drawPoly(currentMarker, col, true);
300 
301  // draw first corner mark
302  helper.drawCircle(currentMarker[0].x, currentMarker[0].y, 3.0F, col, true);
303 
304  // draw ID
305  if (ids.empty() == false)
306  {
307  cv::Point2f cent(0.0F, 0.0F); for (int p = 0; p < 4; ++p) cent += currentMarker[p] * 0.25F;
308  helper.drawText(cent.x, cent.y - 10, ("id=" + std::to_string(ids[i])).c_str(), col);
309  }
310  }
311 
312  // This code is like drawAxis() in cv::aruco, but for ImGui:
313  if (dopose::get() && ids.empty() == false)
314  {
315  float const length = markerlen::get() * 0.4F;
316 
317  for (size_t i = 0; i < ids.size(); ++i)
318  {
319  // Project axis points:
320  std::vector<cv::Point3f> axisPoints;
321  axisPoints.push_back(cv::Point3f(0.0F, 0.0F, 0.0F));
322  axisPoints.push_back(cv::Point3f(length, 0.0F, 0.0F));
323  axisPoints.push_back(cv::Point3f(0.0F, length, 0.0F));
324  axisPoints.push_back(cv::Point3f(0.0F, 0.0F, length));
325 
326  std::vector<cv::Point2f> imagePoints;
327  cv::projectPoints(axisPoints, rvecs[i], tvecs[i], itsCamMatrix, itsDistCoeffs, imagePoints);
328 
329  // Draw axis lines
330  helper.drawLine(imagePoints[0].x, imagePoints[0].y, imagePoints[1].x, imagePoints[1].y, 0xff0000ff);
331  helper.drawLine(imagePoints[0].x, imagePoints[0].y, imagePoints[2].x, imagePoints[2].y, 0xff00ff00);
332  helper.drawLine(imagePoints[0].x, imagePoints[0].y, imagePoints[3].x, imagePoints[3].y, 0xffff0000);
333 
334  // Also draw a cube if requested:
335  if (showcube::get())
336  {
337  float const len = markerlen::get() * 0.5F;
338 
339  std::vector<cv::Point3f> cubePoints;
340  cubePoints.push_back(cv::Point3f(-len, -len, 0.0F));
341  cubePoints.push_back(cv::Point3f(len, -len, 0.0F));
342  cubePoints.push_back(cv::Point3f(len, len, 0.0F));
343  cubePoints.push_back(cv::Point3f(-len, len, 0.0F));
344  cubePoints.push_back(cv::Point3f(-len, -len, len * 2.0F));
345  cubePoints.push_back(cv::Point3f(len, -len, len * 2.0F));
346  cubePoints.push_back(cv::Point3f(len, len, len * 2.0F));
347  cubePoints.push_back(cv::Point3f(-len, len, len * 2.0F));
348 
349  std::vector<cv::Point2f> cuf;
350  cv::projectPoints(cubePoints, rvecs[i], tvecs[i], itsCamMatrix, itsDistCoeffs, cuf);
351 
352  auto drawface =
353  [&](int a, int b, int c, int d)
354  {
355  std::vector<cv::Point2f> p { cuf[a], cuf[b], cuf[c], cuf[d] };
356  helper.drawPoly(p, col, true);
357  };
358 
359  // Draw cube lines and faces. For faces, vertices must be in clockwise order:
360  drawface(0, 1, 2, 3);
361  drawface(0, 1, 5, 4);
362  drawface(1, 2, 6, 5);
363  drawface(2, 3, 7, 6);
364  drawface(3, 0, 4, 7);
365  drawface(4, 5, 6, 7);
366  }
367  }
368  }
369 
370  helper.itext("Detected " + std::to_string(ids.size()) + " ArUco markers.");
371 }
372 
373 #endif
jevois::GUIhelper
ArUco::detectMarkers
void detectMarkers(cv::InputArray image, cv::OutputArray ids, cv::OutputArrayOfArrays corners)
Detect markers.
Definition: ArUco.C:110
jevois::rawimage::drawDisk
void drawDisk(RawImage &img, int x, int y, unsigned int rad, unsigned int col)
jevois::StdModule::sendSerialContour2D
void sendSerialContour2D(unsigned int camw, unsigned int camh, std::vector< cv::Point_< T > > points, std::string const &id="", std::string const &extra="")
jevois::GUIhelper::drawCircle
void drawCircle(float x, float y, float r, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
demo.int
int
Definition: demo.py:37
quantize-inc.q
q
Definition: quantize-inc.py:95
jevois::GUIhelper::itext
void itext(char const *txt, ImU32 const &col=IM_COL32_BLACK_TRANS, int line=-1)
Module.H
ArUco::postUninit
void postUninit() override
Un-initialize, nuke allocated resources.
Definition: ArUco.C:99
jevois::RawImage
LERROR
#define LERROR(msg)
demo.image
image
Definition: demo.py:84
jevois::GUIhelper::drawLine
void drawLine(float x1, float y1, float x2, float y2, ImU32 col=IM_COL32(128, 255, 128, 255))
ArUco::estimatePoseSingleMarkers
void estimatePoseSingleMarkers(cv::InputArrayOfArrays corners, cv::OutputArray rvecs, cv::OutputArray tvecs)
Estimate pose of individual markers.
Definition: ArUco.C:136
jevois::rawimage::writeText
void writeText(RawImage &img, std::string const &txt, int x, int y, unsigned int col, Font font=Font6x10)
F
float F
jevois::GUIhelper::drawPoly
void drawPoly(std::vector< cv::Point > const &pts, ImU32 col=IM_COL32(128, 255, 128, 255), bool filled=true)
ArUco::~ArUco
virtual ~ArUco()
Destructor.
Definition: ArUco.C:27
ArUco::itsDistCoeffs
cv::Mat itsDistCoeffs
Our current distortion coefficients.
Definition: ArUco.H:184
jevois::GUIhelper::drawText
void drawText(float x, float y, char const *txt, ImU32 col=IM_COL32(128, 255, 128, 255))
ArUco::itsDetector
cv::Ptr< cv::aruco::ArucoDetector > itsDetector
Definition: ArUco.H:187
RawImageOps.H
ArUco::drawDetections
void drawDetections(jevois::RawImage &outimg, int txtx, int txty, std::vector< int > ids, std::vector< std::vector< cv::Point2f > > corners, std::vector< cv::Vec3d > const &rvecs, std::vector< cv::Vec3d > const &tvecs)
Draw any markers previously detected by detectMarkers()
Definition: ArUco.C:179
to_string
std::string to_string(T const &val)
unFreeze
void unFreeze()
ArUco.H
h
int h
jevois::StdModule::sendSerialStd3D
void sendSerialStd3D(float x, float y, float z, float w=0.0F, float h=0.0F, float d=0.0F, float q1=0.0F, float q2=0.0F, float q3=0.0f, float q4=0.0F, std::string const &id="", std::string const &extra="")
ArUco::itsCamMatrix
cv::Mat itsCamMatrix
Our current camera matrix.
Definition: ArUco.H:181
freeze
void freeze()
ArUco::postInit
void postInit() override
Initialize, create the detector and read the config files.
Definition: ArUco.C:31
jevois::StdModule
jevois::rawimage::drawLine
void drawLine(RawImage &img, int x1, int y1, int x2, int y2, unsigned int thick, unsigned int col)
LINFO
#define LINFO(msg)
ArUco::sendSerial
void sendSerial(jevois::StdModule *mod, std::vector< int > ids, std::vector< std::vector< cv::Point2f > > corners, unsigned int w, unsigned int h, std::vector< cv::Vec3d > const &rvecs, std::vector< cv::Vec3d > const &tvecs)
Send serial messages about detections.
Definition: ArUco.C:142
demo.w
w
Definition: demo.py:85