draw.cpp
Go to the documentation of this file.
1 // This code is basically taken from https://github.com/opencv/opencv_contrib/blob/master/modules/aruco/src/aruco.cpp
2 // with some improvements and fixes
3 
4 #include "draw.h"
5 #include <math.h>
6 
7 using namespace cv;
8 using namespace cv::aruco;
9 
10 static void _cvProjectPoints2( const CvMat* object_points, const CvMat* rotation_vector,
11  const CvMat* translation_vector, const CvMat* camera_matrix,
12  const CvMat* distortion_coeffs, CvMat* image_points,
13  CvMat* dpdrot CV_DEFAULT(NULL), CvMat* dpdt CV_DEFAULT(NULL),
14  CvMat* dpdf CV_DEFAULT(NULL), CvMat* dpdc CV_DEFAULT(NULL),
15  CvMat* dpddist CV_DEFAULT(NULL),
16  double aspect_ratio CV_DEFAULT(0));
17 
18 static void _projectPoints( InputArray objectPoints,
19  InputArray rvec, InputArray tvec,
20  InputArray cameraMatrix, InputArray distCoeffs,
21  OutputArray imagePoints,
22  OutputArray jacobian = noArray(),
23  double aspectRatio = 0 );
24 
25 
26 void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize,
27  int borderBits, bool drawAxis) {
28 
29  CV_Assert(outSize.area() > 0);
30  CV_Assert(marginSize >= 0);
31 
32  _img.create(outSize, drawAxis ? CV_8UC3 : CV_8UC1);
33  Mat out = _img.getMat();
34  out.setTo(Scalar::all(255));
35  out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize);
36 
37  // calculate max and min values in XY plane
38  CV_Assert(_board->objPoints.size() > 0);
39  float minX, maxX, minY, maxY;
40  minX = maxX = _board->objPoints[0][0].x;
41  minY = maxY = _board->objPoints[0][0].y;
42 
43  for(unsigned int i = 0; i < _board->objPoints.size(); i++) {
44  for(int j = 0; j < 4; j++) {
45  minX = min(minX, _board->objPoints[i][j].x);
46  maxX = max(maxX, _board->objPoints[i][j].x);
47  minY = min(minY, _board->objPoints[i][j].y);
48  maxY = max(maxY, _board->objPoints[i][j].y);
49  }
50  }
51 
52  float sizeX = maxX - minX;
53  float sizeY = maxY - minY;
54 
55  // proportion transformations
56  float xReduction = sizeX / float(out.cols);
57  float yReduction = sizeY / float(out.rows);
58 
59  // determine the zone where the markers are placed
60  if(xReduction > yReduction) {
61  int nRows = int(sizeY / xReduction);
62  int rowsMargins = (out.rows - nRows) / 2;
63  out.adjustROI(-rowsMargins, -rowsMargins, 0, 0);
64  } else {
65  int nCols = int(sizeX / yReduction);
66  int colsMargins = (out.cols - nCols) / 2;
67  out.adjustROI(0, 0, -colsMargins, -colsMargins);
68  }
69 
70  // now paint each marker
71  Dictionary &dictionary = *(_board->dictionary);
72  Mat marker;
73  Point2f outCorners[3];
74  Point2f inCorners[3];
75  for(unsigned int m = 0; m < _board->objPoints.size(); m++) {
76  // transform corners to markerZone coordinates
77  for(int j = 0; j < 3; j++) {
78  Point2f pf = Point2f(_board->objPoints[m][j].x, _board->objPoints[m][j].y);
79  // move top left to 0, 0
80  pf -= Point2f(minX, minY);
81  pf.x = pf.x / sizeX * float(out.cols);
82  pf.y = (1.0f - pf.y / sizeY) * float(out.rows);
83  outCorners[j] = pf;
84  }
85 
86  // get marker
87  Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order
88  // dst_sz.width = dst_sz.height = std::min(dst_sz.width, dst_sz.height); //marker should be square
89  double diag = std::round(std::hypot(dst_sz.width, dst_sz.height));
90  int side = std::round(diag / std::sqrt(2));
91  side = std::max(side, 10);
92 
93  dictionary.drawMarker(_board->ids[m], side, marker, borderBits);
94  if (drawAxis) {
95  cvtColor(marker, marker, COLOR_GRAY2RGB);
96  }
97 
98  // interpolate tiny marker to marker position in markerZone
99  inCorners[0] = Point2f(-0.5f, -0.5f);
100  inCorners[1] = Point2f(marker.cols - 0.5f, -0.5f);
101  inCorners[2] = Point2f(marker.cols - 0.5f, marker.rows - 0.5f);
102 
103  // remove perspective
104  Mat transformation = getAffineTransform(inCorners, outCorners);
105  warpAffine(marker, out, transformation, out.size(), INTER_LINEAR,
106  BORDER_TRANSPARENT);
107  }
108 
109  // draw axis
110  if (drawAxis) {
111  Size wholeSize; Point ofs;
112  out.locateROI(wholeSize, ofs);
113  auto out_copy = _img.getMat();
114 
115  cv::Point center(ofs.x - minX / sizeX * float(out.cols), ofs.y + out.rows + minY / sizeY * float(out.rows));
116 
117  int axis_points[3][2] = {{300, 0}, {0, -300}, {-150, 150}};
118  Point axis_names[3] = {Point(270, 50), Point(25, -270), Point(-160, 115)};
119  Scalar colors[] = {Scalar(255, 0, 0), Scalar(0, 255, 0), Scalar(0, 0, 255)};
120  String names[] = {"X", "Y", "Z"};
121 
122  int r_half = 14;
123  int height = 55;
124 
125  for(int poly = 2; poly >= 0; poly--){
126  double alpha = atan2(0 - axis_points[poly][0], 0 - axis_points[poly][1]);
127  float x_delta = r_half * cos(alpha);
128  float y_delta = r_half * sin(alpha);
129 
130  Point polygon_vertices[1][3];
131  polygon_vertices[0][0] = center + Point(axis_points[poly][0] + x_delta, axis_points[poly][1] - y_delta);
132  polygon_vertices[0][1] = center + Point(axis_points[poly][0] - x_delta, axis_points[poly][1] + y_delta);
133  polygon_vertices[0][2] = center + Point(axis_points[poly][0] - sin(alpha) * height, axis_points[poly][1] - cos(alpha) * height);
134 
135  const Point* ppt[1] = {polygon_vertices[0]};
136  int npt[] = {3};
137 
138  fillPoly(out_copy, ppt, npt, 1, colors[poly]);
139  putText(out_copy, names[poly], center + axis_names[poly], FONT_HERSHEY_SIMPLEX, 1.2, colors[poly], 7);
140  line(out_copy, center, center + Point(axis_points[poly][0], axis_points[poly][1]), colors[poly], 10);
141  }
142  }
143 }
144 
145 /* Draw a (potentially partially visible) line. */
146 static void linePartial(InputOutputArray image, Point3f p1, Point3f p2, const Scalar& color,
147  int thickness = 1, int lineType = LINE_8, int shift = 0)
148 {
149  // If both points are behind the screen, don't draw anything
150  if (p1.z <= 0 && p2.z <= 0) {
151  return;
152  }
153  Point2f p1p{p1.x, p1.y};
154  Point2f p2p{p2.x, p2.y};
155  // If points are on the different sides of the plane, compute intersection point
156  if (p1.z * p2.z < 0) {
157  // Compute intersection point with the screen
158  // We denote alpha as such:
159  // xi = (1 - alpha) * x1 + alpha * x2
160  // yi = (1 - alpha) * y1 + alpha * y2
161  // zi = (1 - alpha) * z1 + alpha * z2 = 0
162  // Thus, alpha can be expressed as
163  // alpha = z1 / (z1 - z2)
164  float alpha = p1.z / (p1.z - p2.z);
165  Point2f pi{(1 - alpha) * p1.x + alpha * p2.x, (1 - alpha) * p1.y + alpha * p2.y};
166  // Now, if z1 is negative, we draw the line from (xi, yi) to (x2, y2), else we draw from (x1, y1) to (xi, yi)
167  if (p1.z < 0) {
168  p1p = pi;
169  } else {
170  p2p = pi;
171  }
172  }
173  line(image, p1p, p2p, color, thickness, lineType, shift);
174 }
175 
176 void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs,
177  InputArray _rvec, InputArray _tvec, float length) {
178 
179  CV_Assert(_image.getMat().total() != 0 &&
180  (_image.getMat().channels() == 1 || _image.getMat().channels() == 3));
181  CV_Assert(length > 0);
182 
183  // project axis points
184  std::vector<Point3f> axisPoints;
185  axisPoints.push_back(Point3f(0, 0, 0));
186  axisPoints.push_back(Point3f(length, 0, 0));
187  axisPoints.push_back(Point3f(0, length, 0));
188  axisPoints.push_back(Point3f(0, 0, length));
189  std::vector<Point3f> imagePointsZ;
190  _projectPoints(axisPoints, _rvec, _tvec, _cameraMatrix, _distCoeffs, imagePointsZ);
191 
192  // draw axis lines
193  linePartial(_image, imagePointsZ[0], imagePointsZ[1], Scalar(0, 0, 255), 3);
194  linePartial(_image, imagePointsZ[0], imagePointsZ[2], Scalar(0, 255, 0), 3);
195  linePartial(_image, imagePointsZ[0], imagePointsZ[3], Scalar(255, 0, 0), 3);
196 }
197 
198 static CvMat _cvMat(const cv::Mat& m)
199 {
200  CvMat self;
201  CV_DbgAssert(m.dims <= 2);
202  self = cvMat(m.rows, m.dims == 1 ? 1 : m.cols, m.type(), m.data);
203  self.step = (int)m.step[0];
204  self.type = (self.type & ~cv::Mat::CONTINUOUS_FLAG) | (m.flags & cv::Mat::CONTINUOUS_FLAG);
205  return self;
206 }
207 
208 static void _projectPoints( InputArray _opoints,
209  InputArray _rvec,
210  InputArray _tvec,
211  InputArray _cameraMatrix,
212  InputArray _distCoeffs,
213  OutputArray _ipoints,
214  OutputArray _jacobian,
215  double aspectRatio )
216 {
217  Mat opoints = _opoints.getMat();
218  int npoints = opoints.checkVector(3), depth = opoints.depth();
219  CV_Assert(npoints >= 0 && (depth == CV_32F || depth == CV_64F));
220 
221  CvMat dpdrot, dpdt, dpdf, dpdc, dpddist;
222  CvMat *pdpdrot = 0, *pdpdt = 0, *pdpdf = 0, *pdpdc = 0, *pdpddist = 0;
223 
224  CV_Assert(_ipoints.needed());
225 
226  _ipoints.create(npoints, 1, CV_MAKETYPE(depth, 3), -1, true);
227  Mat imagePoints = _ipoints.getMat();
228  CvMat c_imagePoints = _cvMat(imagePoints);
229  CvMat c_objectPoints = _cvMat(opoints);
230  Mat cameraMatrix = _cameraMatrix.getMat();
231 
232  Mat rvec = _rvec.getMat(), tvec = _tvec.getMat();
233  CvMat c_cameraMatrix = _cvMat(cameraMatrix);
234  CvMat c_rvec = _cvMat(rvec), c_tvec = _cvMat(tvec);
235 
236  double dc0buf[5] = {0};
237  Mat dc0(5, 1, CV_64F, dc0buf);
238  Mat distCoeffs = _distCoeffs.getMat();
239  if (distCoeffs.empty())
240  distCoeffs = dc0;
241  CvMat c_distCoeffs = _cvMat(distCoeffs);
242  int ndistCoeffs = distCoeffs.rows + distCoeffs.cols - 1;
243 
244  Mat jacobian;
245  if (_jacobian.needed())
246  {
247  _jacobian.create(npoints * 2, 3 + 3 + 2 + 2 + ndistCoeffs, CV_64F);
248  jacobian = _jacobian.getMat();
249  pdpdrot = &(dpdrot = _cvMat(jacobian.colRange(0, 3)));
250  pdpdt = &(dpdt = _cvMat(jacobian.colRange(3, 6)));
251  pdpdf = &(dpdf = _cvMat(jacobian.colRange(6, 8)));
252  pdpdc = &(dpdc = _cvMat(jacobian.colRange(8, 10)));
253  pdpddist = &(dpddist = _cvMat(jacobian.colRange(10, 10 + ndistCoeffs)));
254  }
255 
256  _cvProjectPoints2(&c_objectPoints, &c_rvec, &c_tvec, &c_cameraMatrix, &c_distCoeffs,
257  &c_imagePoints, pdpdrot, pdpdt, pdpdf, pdpdc, pdpddist, aspectRatio);
258 }
259 
260 namespace _detail
261 {
262  template <typename FLOAT>
264  FLOAT tauY,
265  Matx<FLOAT, 3, 3>* matTilt = 0,
266  Matx<FLOAT, 3, 3>* dMatTiltdTauX = 0,
267  Matx<FLOAT, 3, 3>* dMatTiltdTauY = 0,
268  Matx<FLOAT, 3, 3>* invMatTilt = 0)
269  {
270  FLOAT cTauX = cos(tauX);
271  FLOAT sTauX = sin(tauX);
272  FLOAT cTauY = cos(tauY);
273  FLOAT sTauY = sin(tauY);
274  Matx<FLOAT, 3, 3> matRotX = Matx<FLOAT, 3, 3>(1,0,0,0,cTauX,sTauX,0,-sTauX,cTauX);
275  Matx<FLOAT, 3, 3> matRotY = Matx<FLOAT, 3, 3>(cTauY,0,-sTauY,0,1,0,sTauY,0,cTauY);
276  Matx<FLOAT, 3, 3> matRotXY = matRotY * matRotX;
277  Matx<FLOAT, 3, 3> matProjZ = Matx<FLOAT, 3, 3>(matRotXY(2,2),0,-matRotXY(0,2),0,matRotXY(2,2),-matRotXY(1,2),0,0,1);
278  if (matTilt)
279  {
280  // Matrix for trapezoidal distortion of tilted image sensor
281  *matTilt = matProjZ * matRotXY;
282  }
283  if (dMatTiltdTauX)
284  {
285  // Derivative with respect to tauX
286  Matx<FLOAT, 3, 3> dMatRotXYdTauX = matRotY * Matx<FLOAT, 3, 3>(0,0,0,0,-sTauX,cTauX,0,-cTauX,-sTauX);
287  Matx<FLOAT, 3, 3> dMatProjZdTauX = Matx<FLOAT, 3, 3>(dMatRotXYdTauX(2,2),0,-dMatRotXYdTauX(0,2),
288  0,dMatRotXYdTauX(2,2),-dMatRotXYdTauX(1,2),0,0,0);
289  *dMatTiltdTauX = (matProjZ * dMatRotXYdTauX) + (dMatProjZdTauX * matRotXY);
290  }
291  if (dMatTiltdTauY)
292  {
293  // Derivative with respect to tauY
294  Matx<FLOAT, 3, 3> dMatRotXYdTauY = Matx<FLOAT, 3, 3>(-sTauY,0,-cTauY,0,0,0,cTauY,0,-sTauY) * matRotX;
295  Matx<FLOAT, 3, 3> dMatProjZdTauY = Matx<FLOAT, 3, 3>(dMatRotXYdTauY(2,2),0,-dMatRotXYdTauY(0,2),
296  0,dMatRotXYdTauY(2,2),-dMatRotXYdTauY(1,2),0,0,0);
297  *dMatTiltdTauY = (matProjZ * dMatRotXYdTauY) + (dMatProjZdTauY * matRotXY);
298  }
299  if (invMatTilt)
300  {
301  FLOAT inv = 1./matRotXY(2,2);
302  Matx<FLOAT, 3, 3> invMatProjZ = Matx<FLOAT, 3, 3>(inv,0,inv*matRotXY(0,2),0,inv,inv*matRotXY(1,2),0,0,1);
303  *invMatTilt = matRotXY.t()*invMatProjZ;
304  }
305  }
306 }
307 
308 static const char* cvDistCoeffErr = "Distortion coefficients must be 1x4, 4x1, 1x5, 5x1, 1x8, 8x1, 1x12, 12x1, 1x14 or 14x1 floating-point vector";
309 
310 static void _cvProjectPoints2Internal( const CvMat* objectPoints,
311  const CvMat* r_vec,
312  const CvMat* t_vec,
313  const CvMat* A,
314  const CvMat* distCoeffs,
315  CvMat* imagePoints, CvMat* dpdr CV_DEFAULT(NULL),
316  CvMat* dpdt CV_DEFAULT(NULL), CvMat* dpdf CV_DEFAULT(NULL),
317  CvMat* dpdc CV_DEFAULT(NULL), CvMat* dpdk CV_DEFAULT(NULL),
318  CvMat* dpdo CV_DEFAULT(NULL),
319  double aspectRatio CV_DEFAULT(0) )
320 {
321  Ptr<CvMat> matM, _m;
322  Ptr<CvMat> _dpdr, _dpdt, _dpdc, _dpdf, _dpdk;
323  Ptr<CvMat> _dpdo;
324 
325  int i, j, count;
326  int calc_derivatives;
327  const CvPoint3D64f* M;
328  CvPoint3D64f* m;
329  double r[3], R[9], dRdr[27], t[3], a[9], k[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, fx, fy, cx, cy;
330  Matx33d matTilt = Matx33d::eye();
331  Matx33d dMatTiltdTauX(0,0,0,0,0,0,0,-1,0);
332  Matx33d dMatTiltdTauY(0,0,0,0,0,0,1,0,0);
333  CvMat _r, _t, _a = cvMat( 3, 3, CV_64F, a ), _k;
334  CvMat matR = cvMat( 3, 3, CV_64F, R ), _dRdr = cvMat( 3, 9, CV_64F, dRdr );
335  double *dpdr_p = 0, *dpdt_p = 0, *dpdk_p = 0, *dpdf_p = 0, *dpdc_p = 0;
336  double* dpdo_p = 0;
337  int dpdr_step = 0, dpdt_step = 0, dpdk_step = 0, dpdf_step = 0, dpdc_step = 0;
338  int dpdo_step = 0;
339  bool fixedAspectRatio = aspectRatio > FLT_EPSILON;
340 
341  if( !CV_IS_MAT(objectPoints) || !CV_IS_MAT(r_vec) ||
342  !CV_IS_MAT(t_vec) || !CV_IS_MAT(A) || !CV_IS_MAT(imagePoints) )
344  CV_Error( CV_StsBadArg, "One of required arguments is not a valid matrix" );
345 
346  int total = objectPoints->rows * objectPoints->cols * CV_MAT_CN(objectPoints->type);
347  if(total % 3 != 0)
348  {
349  //we have stopped support of homogeneous coordinates because it cause ambiguity in interpretation of the input data
350  CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
351  }
352  count = total / 3;
353 
354  if( CV_IS_CONT_MAT(objectPoints->type) &&
355  (CV_MAT_DEPTH(objectPoints->type) == CV_32F || CV_MAT_DEPTH(objectPoints->type) == CV_64F)&&
356  ((objectPoints->rows == 1 && CV_MAT_CN(objectPoints->type) == 3) ||
357  (objectPoints->rows == count && CV_MAT_CN(objectPoints->type)*objectPoints->cols == 3) ||
358  (objectPoints->rows == 3 && CV_MAT_CN(objectPoints->type) == 1 && objectPoints->cols == count)))
359  {
360  matM.reset(cvCreateMat( objectPoints->rows, objectPoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(objectPoints->type)) ));
361  cvConvert(objectPoints, matM);
362  }
363  else
364  {
365 // matM = cvCreateMat( 1, count, CV_64FC3 );
366 // cvConvertPointsHomogeneous( objectPoints, matM );
367  CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
368  }
369 
370  if( CV_IS_CONT_MAT(imagePoints->type) &&
371  (CV_MAT_DEPTH(imagePoints->type) == CV_32F || CV_MAT_DEPTH(imagePoints->type) == CV_64F) &&
372  ((imagePoints->rows == 1 && CV_MAT_CN(imagePoints->type) == 3) ||
373  (imagePoints->rows == count && CV_MAT_CN(imagePoints->type)*imagePoints->cols == 3) ||
374  (imagePoints->rows == 3 && CV_MAT_CN(imagePoints->type) == 1 && imagePoints->cols == count)))
375  {
376  _m.reset(cvCreateMat( imagePoints->rows, imagePoints->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(imagePoints->type)) ));
377  cvConvert(imagePoints, _m);
378  }
379  else
380  {
381 // _m = cvCreateMat( 1, count, CV_64FC2 );
382  CV_Error( CV_StsBadArg, "Homogeneous coordinates are not supported" );
383  }
384 
385  M = (CvPoint3D64f*)matM->data.db;
386  m = (CvPoint3D64f*)_m->data.db;
387 
388  if( (CV_MAT_DEPTH(r_vec->type) != CV_64F && CV_MAT_DEPTH(r_vec->type) != CV_32F) ||
389  (((r_vec->rows != 1 && r_vec->cols != 1) ||
390  r_vec->rows*r_vec->cols*CV_MAT_CN(r_vec->type) != 3) &&
391  ((r_vec->rows != 3 && r_vec->cols != 3) || CV_MAT_CN(r_vec->type) != 1)))
392  CV_Error( CV_StsBadArg, "Rotation must be represented by 1x3 or 3x1 "
393  "floating-point rotation vector, or 3x3 rotation matrix" );
394 
395  if( r_vec->rows == 3 && r_vec->cols == 3 )
396  {
397  _r = cvMat( 3, 1, CV_64FC1, r );
398  cvRodrigues2( r_vec, &_r );
399  cvRodrigues2( &_r, &matR, &_dRdr );
400  cvCopy( r_vec, &matR );
401  }
402  else
403  {
404  _r = cvMat( r_vec->rows, r_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(r_vec->type)), r );
405  cvConvert( r_vec, &_r );
406  cvRodrigues2( &_r, &matR, &_dRdr );
407  }
408 
409  if( (CV_MAT_DEPTH(t_vec->type) != CV_64F && CV_MAT_DEPTH(t_vec->type) != CV_32F) ||
410  (t_vec->rows != 1 && t_vec->cols != 1) ||
411  t_vec->rows*t_vec->cols*CV_MAT_CN(t_vec->type) != 3 )
412  CV_Error( CV_StsBadArg,
413  "Translation vector must be 1x3 or 3x1 floating-point vector" );
414 
415  _t = cvMat( t_vec->rows, t_vec->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(t_vec->type)), t );
416  cvConvert( t_vec, &_t );
417 
418  if( (CV_MAT_TYPE(A->type) != CV_64FC1 && CV_MAT_TYPE(A->type) != CV_32FC1) ||
419  A->rows != 3 || A->cols != 3 )
420  CV_Error( CV_StsBadArg, "Instrinsic parameters must be 3x3 floating-point matrix" );
421 
422  cvConvert( A, &_a );
423  fx = a[0]; fy = a[4];
424  cx = a[2]; cy = a[5];
425 
426  if( fixedAspectRatio )
427  fx = fy*aspectRatio;
428 
429  if( distCoeffs )
430  {
431  if( !CV_IS_MAT(distCoeffs) ||
432  (CV_MAT_DEPTH(distCoeffs->type) != CV_64F &&
433  CV_MAT_DEPTH(distCoeffs->type) != CV_32F) ||
434  (distCoeffs->rows != 1 && distCoeffs->cols != 1) ||
435  (distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 4 &&
436  distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 5 &&
437  distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 8 &&
438  distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 12 &&
439  distCoeffs->rows*distCoeffs->cols*CV_MAT_CN(distCoeffs->type) != 14) )
440  CV_Error( CV_StsBadArg, cvDistCoeffErr );
441 
442  _k = cvMat( distCoeffs->rows, distCoeffs->cols,
443  CV_MAKETYPE(CV_64F,CV_MAT_CN(distCoeffs->type)), k );
444  cvConvert( distCoeffs, &_k );
445  if(k[12] != 0 || k[13] != 0)
446  {
448  &matTilt, &dMatTiltdTauX, &dMatTiltdTauY);
449  }
450  }
451 
452  if( dpdr )
453  {
454  if( !CV_IS_MAT(dpdr) ||
455  (CV_MAT_TYPE(dpdr->type) != CV_32FC1 &&
456  CV_MAT_TYPE(dpdr->type) != CV_64FC1) ||
457  dpdr->rows != count*2 || dpdr->cols != 3 )
458  CV_Error( CV_StsBadArg, "dp/drot must be 2Nx3 floating-point matrix" );
459 
460  if( CV_MAT_TYPE(dpdr->type) == CV_64FC1 )
461  {
462  _dpdr.reset(cvCloneMat(dpdr));
463  }
464  else
465  _dpdr.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));
466  dpdr_p = _dpdr->data.db;
467  dpdr_step = _dpdr->step/sizeof(dpdr_p[0]);
468  }
469 
470  if( dpdt )
471  {
472  if( !CV_IS_MAT(dpdt) ||
473  (CV_MAT_TYPE(dpdt->type) != CV_32FC1 &&
474  CV_MAT_TYPE(dpdt->type) != CV_64FC1) ||
475  dpdt->rows != count*2 || dpdt->cols != 3 )
476  CV_Error( CV_StsBadArg, "dp/dT must be 2Nx3 floating-point matrix" );
477 
478  if( CV_MAT_TYPE(dpdt->type) == CV_64FC1 )
479  {
480  _dpdt.reset(cvCloneMat(dpdt));
481  }
482  else
483  _dpdt.reset(cvCreateMat( 2*count, 3, CV_64FC1 ));
484  dpdt_p = _dpdt->data.db;
485  dpdt_step = _dpdt->step/sizeof(dpdt_p[0]);
486  }
487 
488  if( dpdf )
489  {
490  if( !CV_IS_MAT(dpdf) ||
491  (CV_MAT_TYPE(dpdf->type) != CV_32FC1 && CV_MAT_TYPE(dpdf->type) != CV_64FC1) ||
492  dpdf->rows != count*2 || dpdf->cols != 2 )
493  CV_Error( CV_StsBadArg, "dp/df must be 2Nx2 floating-point matrix" );
494 
495  if( CV_MAT_TYPE(dpdf->type) == CV_64FC1 )
496  {
497  _dpdf.reset(cvCloneMat(dpdf));
498  }
499  else
500  _dpdf.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));
501  dpdf_p = _dpdf->data.db;
502  dpdf_step = _dpdf->step/sizeof(dpdf_p[0]);
503  }
504 
505  if( dpdc )
506  {
507  if( !CV_IS_MAT(dpdc) ||
508  (CV_MAT_TYPE(dpdc->type) != CV_32FC1 && CV_MAT_TYPE(dpdc->type) != CV_64FC1) ||
509  dpdc->rows != count*2 || dpdc->cols != 2 )
510  CV_Error( CV_StsBadArg, "dp/dc must be 2Nx2 floating-point matrix" );
511 
512  if( CV_MAT_TYPE(dpdc->type) == CV_64FC1 )
513  {
514  _dpdc.reset(cvCloneMat(dpdc));
515  }
516  else
517  _dpdc.reset(cvCreateMat( 2*count, 2, CV_64FC1 ));
518  dpdc_p = _dpdc->data.db;
519  dpdc_step = _dpdc->step/sizeof(dpdc_p[0]);
520  }
521 
522  if( dpdk )
523  {
524  if( !CV_IS_MAT(dpdk) ||
525  (CV_MAT_TYPE(dpdk->type) != CV_32FC1 && CV_MAT_TYPE(dpdk->type) != CV_64FC1) ||
526  dpdk->rows != count*2 || (dpdk->cols != 14 && dpdk->cols != 12 && dpdk->cols != 8 && dpdk->cols != 5 && dpdk->cols != 4 && dpdk->cols != 2) )
527  CV_Error( CV_StsBadArg, "dp/df must be 2Nx14, 2Nx12, 2Nx8, 2Nx5, 2Nx4 or 2Nx2 floating-point matrix" );
528 
529  if( !distCoeffs )
530  CV_Error( CV_StsNullPtr, "distCoeffs is NULL while dpdk is not" );
531 
532  if( CV_MAT_TYPE(dpdk->type) == CV_64FC1 )
533  {
534  _dpdk.reset(cvCloneMat(dpdk));
535  }
536  else
537  _dpdk.reset(cvCreateMat( dpdk->rows, dpdk->cols, CV_64FC1 ));
538  dpdk_p = _dpdk->data.db;
539  dpdk_step = _dpdk->step/sizeof(dpdk_p[0]);
540  }
541 
542  if( dpdo )
543  {
544  if( !CV_IS_MAT( dpdo ) || ( CV_MAT_TYPE( dpdo->type ) != CV_32FC1
545  && CV_MAT_TYPE( dpdo->type ) != CV_64FC1 )
546  || dpdo->rows != count * 2 || dpdo->cols != count * 3 )
547  CV_Error( CV_StsBadArg, "dp/do must be 2Nx3N floating-point matrix" );
548 
549  if( CV_MAT_TYPE( dpdo->type ) == CV_64FC1 )
550  {
551  _dpdo.reset( cvCloneMat( dpdo ) );
552  }
553  else
554  _dpdo.reset( cvCreateMat( 2 * count, 3 * count, CV_64FC1 ) );
555  cvZero(_dpdo);
556  dpdo_p = _dpdo->data.db;
557  dpdo_step = _dpdo->step / sizeof( dpdo_p[0] );
558  }
559 
560  calc_derivatives = dpdr || dpdt || dpdf || dpdc || dpdk || dpdo;
561 
562  for( i = 0; i < count; i++ )
563  {
564  double X = M[i].x, Y = M[i].y, Z = M[i].z;
565  double x = R[0]*X + R[1]*Y + R[2]*Z + t[0];
566  double y = R[3]*X + R[4]*Y + R[5]*Z + t[1];
567  double z = R[6]*X + R[7]*Y + R[8]*Z + t[2];
568  double r2, r4, r6, a1, a2, a3, cdist, icdist2;
569  double xd, yd, xd0, yd0, invProj;
570  Vec3d vecTilt;
571  Vec3d dVecTilt;
572  Matx22d dMatTilt;
573  Vec2d dXdYd;
574 
575  double z0 = z;
576  z = z ? 1./z : 1;
577  x *= z; y *= z;
578 
579  r2 = x*x + y*y;
580  r4 = r2*r2;
581  r6 = r4*r2;
582  a1 = 2*x*y;
583  a2 = r2 + 2*x*x;
584  a3 = r2 + 2*y*y;
585  cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;
586  icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6);
587  xd0 = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;
588  yd0 = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;
589 
590  // additional distortion by projecting onto a tilt plane
591  vecTilt = matTilt*Vec3d(xd0, yd0, 1);
592  invProj = vecTilt(2) ? 1./vecTilt(2) : 1;
593  xd = invProj * vecTilt(0);
594  yd = invProj * vecTilt(1);
595 
596  m[i].x = xd*fx + cx;
597  m[i].y = yd*fy + cy;
598  m[i].z = z; // Just put the projected Z coordinate here, we mainly care about the sign
599 
600  if( calc_derivatives )
601  {
602  if( dpdc_p )
603  {
604  dpdc_p[0] = 1; dpdc_p[1] = 0; // dp_xdc_x; dp_xdc_y
605  dpdc_p[dpdc_step] = 0;
606  dpdc_p[dpdc_step+1] = 1;
607  dpdc_p += dpdc_step*2;
608  }
609 
610  if( dpdf_p )
611  {
612  if( fixedAspectRatio )
613  {
614  dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio; // dp_xdf_x; dp_xdf_y
615  dpdf_p[dpdf_step] = 0;
616  dpdf_p[dpdf_step+1] = yd;
617  }
618  else
619  {
620  dpdf_p[0] = xd; dpdf_p[1] = 0;
621  dpdf_p[dpdf_step] = 0;
622  dpdf_p[dpdf_step+1] = yd;
623  }
624  dpdf_p += dpdf_step*2;
625  }
626  for (int row = 0; row < 2; ++row)
627  for (int col = 0; col < 2; ++col)
628  dMatTilt(row,col) = matTilt(row,col)*vecTilt(2)
629  - matTilt(2,col)*vecTilt(row);
630  double invProjSquare = (invProj*invProj);
631  dMatTilt *= invProjSquare;
632  if( dpdk_p )
633  {
634  dXdYd = dMatTilt*Vec2d(x*icdist2*r2, y*icdist2*r2);
635  dpdk_p[0] = fx*dXdYd(0);
636  dpdk_p[dpdk_step] = fy*dXdYd(1);
637  dXdYd = dMatTilt*Vec2d(x*icdist2*r4, y*icdist2*r4);
638  dpdk_p[1] = fx*dXdYd(0);
639  dpdk_p[dpdk_step+1] = fy*dXdYd(1);
640  if( _dpdk->cols > 2 )
641  {
642  dXdYd = dMatTilt*Vec2d(a1, a3);
643  dpdk_p[2] = fx*dXdYd(0);
644  dpdk_p[dpdk_step+2] = fy*dXdYd(1);
645  dXdYd = dMatTilt*Vec2d(a2, a1);
646  dpdk_p[3] = fx*dXdYd(0);
647  dpdk_p[dpdk_step+3] = fy*dXdYd(1);
648  if( _dpdk->cols > 4 )
649  {
650  dXdYd = dMatTilt*Vec2d(x*icdist2*r6, y*icdist2*r6);
651  dpdk_p[4] = fx*dXdYd(0);
652  dpdk_p[dpdk_step+4] = fy*dXdYd(1);
653 
654  if( _dpdk->cols > 5 )
655  {
656  dXdYd = dMatTilt*Vec2d(
657  x*cdist*(-icdist2)*icdist2*r2, y*cdist*(-icdist2)*icdist2*r2);
658  dpdk_p[5] = fx*dXdYd(0);
659  dpdk_p[dpdk_step+5] = fy*dXdYd(1);
660  dXdYd = dMatTilt*Vec2d(
661  x*cdist*(-icdist2)*icdist2*r4, y*cdist*(-icdist2)*icdist2*r4);
662  dpdk_p[6] = fx*dXdYd(0);
663  dpdk_p[dpdk_step+6] = fy*dXdYd(1);
664  dXdYd = dMatTilt*Vec2d(
665  x*cdist*(-icdist2)*icdist2*r6, y*cdist*(-icdist2)*icdist2*r6);
666  dpdk_p[7] = fx*dXdYd(0);
667  dpdk_p[dpdk_step+7] = fy*dXdYd(1);
668  if( _dpdk->cols > 8 )
669  {
670  dXdYd = dMatTilt*Vec2d(r2, 0);
671  dpdk_p[8] = fx*dXdYd(0); //s1
672  dpdk_p[dpdk_step+8] = fy*dXdYd(1); //s1
673  dXdYd = dMatTilt*Vec2d(r4, 0);
674  dpdk_p[9] = fx*dXdYd(0); //s2
675  dpdk_p[dpdk_step+9] = fy*dXdYd(1); //s2
676  dXdYd = dMatTilt*Vec2d(0, r2);
677  dpdk_p[10] = fx*dXdYd(0);//s3
678  dpdk_p[dpdk_step+10] = fy*dXdYd(1); //s3
679  dXdYd = dMatTilt*Vec2d(0, r4);
680  dpdk_p[11] = fx*dXdYd(0);//s4
681  dpdk_p[dpdk_step+11] = fy*dXdYd(1); //s4
682  if( _dpdk->cols > 12 )
683  {
684  dVecTilt = dMatTiltdTauX * Vec3d(xd0, yd0, 1);
685  dpdk_p[12] = fx * invProjSquare * (
686  dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));
687  dpdk_p[dpdk_step+12] = fy*invProjSquare * (
688  dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));
689  dVecTilt = dMatTiltdTauY * Vec3d(xd0, yd0, 1);
690  dpdk_p[13] = fx * invProjSquare * (
691  dVecTilt(0) * vecTilt(2) - dVecTilt(2) * vecTilt(0));
692  dpdk_p[dpdk_step+13] = fy * invProjSquare * (
693  dVecTilt(1) * vecTilt(2) - dVecTilt(2) * vecTilt(1));
694  }
695  }
696  }
697  }
698  }
699  dpdk_p += dpdk_step*2;
700  }
701 
702  if( dpdt_p )
703  {
704  double dxdt[] = { z, 0, -x*z }, dydt[] = { 0, z, -y*z };
705  for( j = 0; j < 3; j++ )
706  {
707  double dr2dt = 2*x*dxdt[j] + 2*y*dydt[j];
708  double dcdist_dt = k[0]*dr2dt + 2*k[1]*r2*dr2dt + 3*k[4]*r4*dr2dt;
709  double dicdist2_dt = -icdist2*icdist2*(k[5]*dr2dt + 2*k[6]*r2*dr2dt + 3*k[7]*r4*dr2dt);
710  double da1dt = 2*(x*dydt[j] + y*dxdt[j]);
711  double dmxdt = (dxdt[j]*cdist*icdist2 + x*dcdist_dt*icdist2 + x*cdist*dicdist2_dt +
712  k[2]*da1dt + k[3]*(dr2dt + 4*x*dxdt[j]) + k[8]*dr2dt + 2*r2*k[9]*dr2dt);
713  double dmydt = (dydt[j]*cdist*icdist2 + y*dcdist_dt*icdist2 + y*cdist*dicdist2_dt +
714  k[2]*(dr2dt + 4*y*dydt[j]) + k[3]*da1dt + k[10]*dr2dt + 2*r2*k[11]*dr2dt);
715  dXdYd = dMatTilt*Vec2d(dmxdt, dmydt);
716  dpdt_p[j] = fx*dXdYd(0);
717  dpdt_p[dpdt_step+j] = fy*dXdYd(1);
718  }
719  dpdt_p += dpdt_step*2;
720  }
721 
722  if( dpdr_p )
723  {
724  double dx0dr[] =
725  {
726  X*dRdr[0] + Y*dRdr[1] + Z*dRdr[2],
727  X*dRdr[9] + Y*dRdr[10] + Z*dRdr[11],
728  X*dRdr[18] + Y*dRdr[19] + Z*dRdr[20]
729  };
730  double dy0dr[] =
731  {
732  X*dRdr[3] + Y*dRdr[4] + Z*dRdr[5],
733  X*dRdr[12] + Y*dRdr[13] + Z*dRdr[14],
734  X*dRdr[21] + Y*dRdr[22] + Z*dRdr[23]
735  };
736  double dz0dr[] =
737  {
738  X*dRdr[6] + Y*dRdr[7] + Z*dRdr[8],
739  X*dRdr[15] + Y*dRdr[16] + Z*dRdr[17],
740  X*dRdr[24] + Y*dRdr[25] + Z*dRdr[26]
741  };
742  for( j = 0; j < 3; j++ )
743  {
744  double dxdr = z*(dx0dr[j] - x*dz0dr[j]);
745  double dydr = z*(dy0dr[j] - y*dz0dr[j]);
746  double dr2dr = 2*x*dxdr + 2*y*dydr;
747  double dcdist_dr = (k[0] + 2*k[1]*r2 + 3*k[4]*r4)*dr2dr;
748  double dicdist2_dr = -icdist2*icdist2*(k[5] + 2*k[6]*r2 + 3*k[7]*r4)*dr2dr;
749  double da1dr = 2*(x*dydr + y*dxdr);
750  double dmxdr = (dxdr*cdist*icdist2 + x*dcdist_dr*icdist2 + x*cdist*dicdist2_dr +
751  k[2]*da1dr + k[3]*(dr2dr + 4*x*dxdr) + (k[8] + 2*r2*k[9])*dr2dr);
752  double dmydr = (dydr*cdist*icdist2 + y*dcdist_dr*icdist2 + y*cdist*dicdist2_dr +
753  k[2]*(dr2dr + 4*y*dydr) + k[3]*da1dr + (k[10] + 2*r2*k[11])*dr2dr);
754  dXdYd = dMatTilt*Vec2d(dmxdr, dmydr);
755  dpdr_p[j] = fx*dXdYd(0);
756  dpdr_p[dpdr_step+j] = fy*dXdYd(1);
757  }
758  dpdr_p += dpdr_step*2;
759  }
760 
761  if( dpdo_p )
762  {
763  double dxdo[] = { z * ( R[0] - x * z * z0 * R[6] ),
764  z * ( R[1] - x * z * z0 * R[7] ),
765  z * ( R[2] - x * z * z0 * R[8] ) };
766  double dydo[] = { z * ( R[3] - y * z * z0 * R[6] ),
767  z * ( R[4] - y * z * z0 * R[7] ),
768  z * ( R[5] - y * z * z0 * R[8] ) };
769  for( j = 0; j < 3; j++ )
770  {
771  double dr2do = 2 * x * dxdo[j] + 2 * y * dydo[j];
772  double dr4do = 2 * r2 * dr2do;
773  double dr6do = 3 * r4 * dr2do;
774  double da1do = 2 * y * dxdo[j] + 2 * x * dydo[j];
775  double da2do = dr2do + 4 * x * dxdo[j];
776  double da3do = dr2do + 4 * y * dydo[j];
777  double dcdist_do
778  = k[0] * dr2do + k[1] * dr4do + k[4] * dr6do;
779  double dicdist2_do = -icdist2 * icdist2
780  * ( k[5] * dr2do + k[6] * dr4do + k[7] * dr6do );
781  double dxd0_do = cdist * icdist2 * dxdo[j]
782  + x * icdist2 * dcdist_do + x * cdist * dicdist2_do
783  + k[2] * da1do + k[3] * da2do + k[8] * dr2do
784  + k[9] * dr4do;
785  double dyd0_do = cdist * icdist2 * dydo[j]
786  + y * icdist2 * dcdist_do + y * cdist * dicdist2_do
787  + k[2] * da3do + k[3] * da1do + k[10] * dr2do
788  + k[11] * dr4do;
789  dXdYd = dMatTilt * Vec2d( dxd0_do, dyd0_do );
790  dpdo_p[i * 3 + j] = fx * dXdYd( 0 );
791  dpdo_p[dpdo_step + i * 3 + j] = fy * dXdYd( 1 );
792  }
793  dpdo_p += dpdo_step * 2;
794  }
795  }
796  }
797 
798  if( _m != imagePoints )
799  cvConvert( _m, imagePoints );
800 
801  if( _dpdr != dpdr )
802  cvConvert( _dpdr, dpdr );
803 
804  if( _dpdt != dpdt )
805  cvConvert( _dpdt, dpdt );
806 
807  if( _dpdf != dpdf )
808  cvConvert( _dpdf, dpdf );
809 
810  if( _dpdc != dpdc )
811  cvConvert( _dpdc, dpdc );
812 
813  if( _dpdk != dpdk )
814  cvConvert( _dpdk, dpdk );
815 
816  if( _dpdo != dpdo )
817  cvConvert( _dpdo, dpdo );
818 }
819 
820 static void _cvProjectPoints2( const CvMat* objectPoints,
821  const CvMat* r_vec,
822  const CvMat* t_vec,
823  const CvMat* A,
824  const CvMat* distCoeffs,
825  CvMat* imagePoints, CvMat* dpdr,
826  CvMat* dpdt, CvMat* dpdf,
827  CvMat* dpdc, CvMat* dpdk,
828  double aspectRatio )
829 {
830  _cvProjectPoints2Internal( objectPoints, r_vec, t_vec, A, distCoeffs, imagePoints, dpdr, dpdt,
831  dpdf, dpdc, dpdk, NULL, aspectRatio );
832 }
static const char * cvDistCoeffErr
Definition: draw.cpp:308
f
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray cameraMatrix
Definition: charuco.hpp:245
CV_WRAP void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits=1) const
Draw a canonical marker image.
Definition: dictionary.cpp:166
Definition: charuco.hpp:47
InputArrayOfArrays const Ptr< CharucoBoard > Size InputOutputArray InputOutputArray distCoeffs
Definition: charuco.hpp:245
tf::Vector3 Point
length
Definition: genmap.py:42
geometry_msgs::TransformStamped t
CV_PROP Ptr< Dictionary > dictionary
the dictionary of markers employed for this board
Definition: aruco.hpp:289
static void _projectPoints(InputArray objectPoints, InputArray rvec, InputArray tvec, InputArray cameraMatrix, InputArray distCoeffs, OutputArray imagePoints, OutputArray jacobian=noArray(), double aspectRatio=0)
Definition: draw.cpp:208
static CvMat _cvMat(const cv::Mat &m)
Definition: draw.cpp:198
void _drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _distCoeffs, InputArray _rvec, InputArray _tvec, float length)
Definition: draw.cpp:176
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
Board of markers.
Definition: aruco.hpp:272
double min(double a, double b)
CV_PROP std::vector< std::vector< Point3f > > objPoints
Definition: aruco.hpp:286
static void linePartial(InputOutputArray image, Point3f p1, Point3f p2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
Definition: draw.cpp:146
void computeTiltProjectionMatrix(FLOAT tauX, FLOAT tauY, Matx< FLOAT, 3, 3 > *matTilt=0, Matx< FLOAT, 3, 3 > *dMatTiltdTauX=0, Matx< FLOAT, 3, 3 > *dMatTiltdTauY=0, Matx< FLOAT, 3, 3 > *invMatTilt=0)
Definition: draw.cpp:263
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
void _drawPlanarBoard(Board *_board, Size outSize, OutputArray _img, int marginSize, int borderBits, bool drawAxis)
Definition: draw.cpp:26
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
CV_PROP std::vector< int > ids
Definition: aruco.hpp:293
static void _cvProjectPoints2Internal(const CvMat *objectPoints, const CvMat *r_vec, const CvMat *t_vec, const CvMat *A, const CvMat *distCoeffs, CvMat *imagePoints, CvMat *dpdr CV_DEFAULT(NULL), CvMat *dpdt CV_DEFAULT(NULL), CvMat *dpdf CV_DEFAULT(NULL), CvMat *dpdc CV_DEFAULT(NULL), CvMat *dpdk CV_DEFAULT(NULL), CvMat *dpdo CV_DEFAULT(NULL), double aspectRatio CV_DEFAULT(0))
Definition: draw.cpp:310
static void _cvProjectPoints2(const CvMat *object_points, const CvMat *rotation_vector, const CvMat *translation_vector, const CvMat *camera_matrix, const CvMat *distortion_coeffs, CvMat *image_points, CvMat *dpdrot CV_DEFAULT(NULL), CvMat *dpdt CV_DEFAULT(NULL), CvMat *dpdf CV_DEFAULT(NULL), CvMat *dpdc CV_DEFAULT(NULL), CvMat *dpddist CV_DEFAULT(NULL), double aspect_ratio CV_DEFAULT(0))
double max(double a, double b)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Dictionary/Set of markers. It contains the inner codification.
Definition: dictionary.hpp:61
CV_EXPORTS_W void drawAxis(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs, InputArray rvec, InputArray tvec, float length)
Draw coordinate system axis from pose estimation.
Definition: aruco.cpp:1749


aruco_pose
Author(s): Oleg Kalachev
autogenerated on Mon Feb 28 2022 22:08:24