Skip to content

Commit ba147d2

Browse files
committed
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
2 parents 1192cbe + 01324b0 commit ba147d2

File tree

13 files changed

+768
-171
lines changed

13 files changed

+768
-171
lines changed

doc/mymath.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ MathJax.Hub.Config(
99
forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
1010
vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
1111
vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
12+
cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
13+
distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
14+
distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
1215
hdotsfor: ["\\dots", 1],
1316
mathbbm: ["\\mathbb{#1}", 1],
1417
bordermatrix: ["\\matrix{#1}", 1]

doc/mymath.sty

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,20 @@
5151
#7 & #8 & #9
5252
\end{bmatrix}
5353
}
54+
55+
\newcommand{\cameramatrix}[1]{
56+
#1 =
57+
\begin{bmatrix}
58+
f_x & 0 & c_x\\
59+
0 & f_y & c_y\\
60+
0 & 0 & 1
61+
\end{bmatrix}
62+
}
63+
64+
\newcommand{\distcoeffs}[]{
65+
(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]]) \text{ of 4, 5, 8, 12 or 14 elements}
66+
}
67+
68+
\newcommand{\distcoeffsfisheye}[]{
69+
(k_1, k_2, k_3, k_4)
70+
}

doc/pattern_tools/gen_pattern.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,27 @@ def __init__(self, cols, rows, output, units, square_size, radius_rate, page_wid
3636
def make_circles_pattern(self):
3737
spacing = self.square_size
3838
r = spacing / self.radius_rate
39-
for x in range(1, self.cols + 1):
40-
for y in range(1, self.rows + 1):
41-
dot = SVG("circle", cx=x * spacing, cy=y * spacing, r=r, fill="black", stroke="none")
39+
pattern_width = ((self.cols - 1.0) * spacing) + (2.0 * r)
40+
pattern_height = ((self.rows - 1.0) * spacing) + (2.0 * r)
41+
x_spacing = (self.width - pattern_width) / 2.0
42+
y_spacing = (self.height - pattern_height) / 2.0
43+
for x in range(0, self.cols):
44+
for y in range(0, self.rows):
45+
dot = SVG("circle", cx=(x * spacing) + x_spacing + r,
46+
cy=(y * spacing) + y_spacing + r, r=r, fill="black", stroke="none")
4247
self.g.append(dot)
4348

4449
def make_acircles_pattern(self):
4550
spacing = self.square_size
4651
r = spacing / self.radius_rate
47-
for i in range(0, self.rows):
48-
for j in range(0, self.cols):
49-
dot = SVG("circle", cx=((j * 2 + i % 2) * spacing) + spacing, cy=self.height - (i * spacing + spacing),
50-
r=r, fill="black", stroke="none")
52+
pattern_width = ((self.cols-1.0) * 2 * spacing) + spacing + (2.0 * r)
53+
pattern_height = ((self.rows-1.0) * spacing) + (2.0 * r)
54+
x_spacing = (self.width - pattern_width) / 2.0
55+
y_spacing = (self.height - pattern_height) / 2.0
56+
for x in range(0, self.cols):
57+
for y in range(0, self.rows):
58+
dot = SVG("circle", cx=(2 * x * spacing) + (y % 2)*spacing + x_spacing + r,
59+
cy=(y * spacing) + y_spacing + r, r=r, fill="black", stroke="none")
5160
self.g.append(dot)
5261

5362
def make_checkerboard_pattern(self):
@@ -84,9 +93,9 @@ def main():
8493
parser.add_argument("-R", "--radius_rate", help="circles_radius = square_size/radius_rate", default="5.0",
8594
action="store", dest="radius_rate", type=float)
8695
parser.add_argument("-w", "--page_width", help="page width in units", default="216", action="store",
87-
dest="page_width", type=int)
96+
dest="page_width", type=float)
8897
parser.add_argument("-h", "--page_height", help="page height in units", default="279", action="store",
89-
dest="page_width", type=int)
98+
dest="page_width", type=float)
9099
parser.add_argument("-a", "--page_size", help="page size, supersedes -h -w arguments", default="A4", action="store",
91100
dest="page_size", choices=["A0", "A1", "A2", "A3", "A4", "A5"])
92101
args = parser.parse_args()

modules/calib3d/include/opencv2/calib3d.hpp

Lines changed: 110 additions & 114 deletions
Large diffs are not rendered by default.

modules/calib3d/src/calibration_handeye.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ static Mat homogeneousInverse(const Mat& T)
2929
// q = sin(theta/2) * v
3030
// theta - rotation angle
3131
// v - unit rotation axis, |v| = 1
32+
// Reference: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
3233
static Mat rot2quatMinimal(const Mat& R)
3334
{
3435
CV_Assert(R.type() == CV_64FC1 && R.rows >= 3 && R.cols >= 3);
@@ -44,7 +45,7 @@ static Mat rot2quatMinimal(const Mat& R)
4445
qx = (m21 - m12) / S;
4546
qy = (m02 - m20) / S;
4647
qz = (m10 - m01) / S;
47-
} else if ((m00 > m11)&(m00 > m22)) {
48+
} else if (m00 > m11 && m00 > m22) {
4849
double S = sqrt(1.0 + m00 - m11 - m22) * 2; // S=4*qx
4950
qx = 0.25 * S;
5051
qy = (m01 + m10) / S;
@@ -98,6 +99,7 @@ static Mat quatMinimal2rot(const Mat& q)
9899
//
99100
// q - 4x1 unit quaternion <qw, qx, qy, qz>
100101
// R - 3x3 rotation matrix
102+
// Reference: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
101103
static Mat rot2quat(const Mat& R)
102104
{
103105
CV_Assert(R.type() == CV_64FC1 && R.rows >= 3 && R.cols >= 3);
@@ -114,7 +116,7 @@ static Mat rot2quat(const Mat& R)
114116
qx = (m21 - m12) / S;
115117
qy = (m02 - m20) / S;
116118
qz = (m10 - m01) / S;
117-
} else if ((m00 > m11)&(m00 > m22)) {
119+
} else if (m00 > m11 && m00 > m22) {
118120
double S = sqrt(1.0 + m00 - m11 - m22) * 2; // S=4*qx
119121
qw = (m21 - m12) / S;
120122
qx = 0.25 * S;
@@ -572,7 +574,11 @@ static void calibrateHandEyeAndreff(const std::vector<Mat>& Hg, const std::vecto
572574
R = R.reshape(1, 2, newSize);
573575
//Eq 15
574576
double det = determinant(R);
575-
R = pow(sign_double(det) / abs(det), 1.0/3.0) * R;
577+
if (std::fabs(det) < FLT_EPSILON)
578+
{
579+
CV_Error(Error::StsNoConv, "calibrateHandEye() with CALIB_HAND_EYE_ANDREFF method: determinant(R) is null");
580+
}
581+
R = cubeRoot(static_cast<float>(sign_double(det) / abs(det))) * R;
576582

577583
Mat w, u, vt;
578584
SVDecomp(R, w, u, vt);

modules/calib3d/src/solvepnp.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151

5252
#include "usac.hpp"
5353

54+
#include <opencv2/core/utils/logger.hpp>
55+
5456
namespace cv
5557
{
5658
#if defined _DEBUG || defined CV_STATIC_ANALYSIS
@@ -809,6 +811,15 @@ int solvePnPGeneric( InputArray _opoints, InputArray _ipoints,
809811
vector<Mat> vec_rvecs, vec_tvecs;
810812
if (flags == SOLVEPNP_EPNP || flags == SOLVEPNP_DLS || flags == SOLVEPNP_UPNP)
811813
{
814+
if (flags == SOLVEPNP_DLS)
815+
{
816+
CV_LOG_DEBUG(NULL, "Broken implementation for SOLVEPNP_DLS. Fallback to EPnP.");
817+
}
818+
else if (flags == SOLVEPNP_UPNP)
819+
{
820+
CV_LOG_DEBUG(NULL, "Broken implementation for SOLVEPNP_UPNP. Fallback to EPnP.");
821+
}
822+
812823
Mat undistortedPoints;
813824
undistortPoints(ipoints, undistortedPoints, cameraMatrix, distCoeffs);
814825
epnp PnP(cameraMatrix, opoints, undistortedPoints);

modules/calib3d/test/test_calibration_hand_eye.cpp

Lines changed: 111 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,38 @@
77

88
namespace opencv_test { namespace {
99

10+
static std::string getMethodName(HandEyeCalibrationMethod method)
11+
{
12+
std::string method_name = "";
13+
switch (method)
14+
{
15+
case CALIB_HAND_EYE_TSAI:
16+
method_name = "Tsai";
17+
break;
18+
19+
case CALIB_HAND_EYE_PARK:
20+
method_name = "Park";
21+
break;
22+
23+
case CALIB_HAND_EYE_HORAUD:
24+
method_name = "Horaud";
25+
break;
26+
27+
case CALIB_HAND_EYE_ANDREFF:
28+
method_name = "Andreff";
29+
break;
30+
31+
case CALIB_HAND_EYE_DANIILIDIS:
32+
method_name = "Daniilidis";
33+
break;
34+
35+
default:
36+
break;
37+
}
38+
39+
return method_name;
40+
}
41+
1042
class CV_CalibrateHandEyeTest : public cvtest::BaseTest
1143
{
1244
public:
@@ -48,7 +80,6 @@ class CV_CalibrateHandEyeTest : public cvtest::BaseTest
4880
std::vector<Mat> &R_target2cam, std::vector<Mat> &t_target2cam,
4981
bool noise, Mat& R_cam2gripper, Mat& t_cam2gripper);
5082
Mat homogeneousInverse(const Mat& T);
51-
std::string getMethodName(HandEyeCalibrationMethod method);
5283
double sign_double(double val);
5384

5485
double eps_rvec[5];
@@ -340,45 +371,95 @@ Mat CV_CalibrateHandEyeTest::homogeneousInverse(const Mat& T)
340371
return Tinv;
341372
}
342373

343-
std::string CV_CalibrateHandEyeTest::getMethodName(HandEyeCalibrationMethod method)
374+
double CV_CalibrateHandEyeTest::sign_double(double val)
344375
{
345-
std::string method_name = "";
346-
switch (method)
347-
{
348-
case CALIB_HAND_EYE_TSAI:
349-
method_name = "Tsai";
350-
break;
376+
return (0 < val) - (val < 0);
377+
}
351378

352-
case CALIB_HAND_EYE_PARK:
353-
method_name = "Park";
354-
break;
379+
///////////////////////////////////////////////////////////////////////////////////////////////////
355380

356-
case CALIB_HAND_EYE_HORAUD:
357-
method_name = "Horaud";
358-
break;
381+
TEST(Calib3d_CalibrateHandEye, regression) { CV_CalibrateHandEyeTest test; test.safe_run(); }
359382

360-
case CALIB_HAND_EYE_ANDREFF:
361-
method_name = "Andreff";
362-
break;
383+
TEST(Calib3d_CalibrateHandEye, regression_17986)
384+
{
385+
const std::string camera_poses_filename = findDataFile("cv/hand_eye_calibration/cali.txt");
386+
const std::string end_effector_poses = findDataFile("cv/hand_eye_calibration/robot_cali.txt");
363387

364-
case CALIB_HAND_EYE_DANIILIDIS:
365-
method_name = "Daniilidis";
366-
break;
388+
std::vector<Mat> R_target2cam;
389+
std::vector<Mat> t_target2cam;
390+
// Parse camera poses
391+
{
392+
std::ifstream file(camera_poses_filename.c_str());
393+
ASSERT_TRUE(file.is_open());
394+
395+
int ndata = 0;
396+
file >> ndata;
397+
R_target2cam.reserve(ndata);
398+
t_target2cam.reserve(ndata);
399+
400+
std::string image_name;
401+
Matx33d cameraMatrix;
402+
Matx33d R;
403+
Matx31d t;
404+
Matx16d distCoeffs;
405+
Matx13d distCoeffs2;
406+
while (file >> image_name >>
407+
cameraMatrix(0,0) >> cameraMatrix(0,1) >> cameraMatrix(0,2) >>
408+
cameraMatrix(1,0) >> cameraMatrix(1,1) >> cameraMatrix(1,2) >>
409+
cameraMatrix(2,0) >> cameraMatrix(2,1) >> cameraMatrix(2,2) >>
410+
R(0,0) >> R(0,1) >> R(0,2) >>
411+
R(1,0) >> R(1,1) >> R(1,2) >>
412+
R(2,0) >> R(2,1) >> R(2,2) >>
413+
t(0) >> t(1) >> t(2) >>
414+
distCoeffs(0) >> distCoeffs(1) >> distCoeffs(2) >> distCoeffs(3) >> distCoeffs(4) >>
415+
distCoeffs2(0) >> distCoeffs2(1) >> distCoeffs2(2)) {
416+
R_target2cam.push_back(Mat(R));
417+
t_target2cam.push_back(Mat(t));
418+
}
419+
}
367420

368-
default:
369-
break;
421+
std::vector<Mat> R_gripper2base;
422+
std::vector<Mat> t_gripper2base;
423+
// Parse end-effector poses
424+
{
425+
std::ifstream file(end_effector_poses.c_str());
426+
ASSERT_TRUE(file.is_open());
427+
428+
int ndata = 0;
429+
file >> ndata;
430+
R_gripper2base.reserve(ndata);
431+
t_gripper2base.reserve(ndata);
432+
433+
Matx33d R;
434+
Matx31d t;
435+
Matx14d last_row;
436+
while (file >>
437+
R(0,0) >> R(0,1) >> R(0,2) >> t(0) >>
438+
R(1,0) >> R(1,1) >> R(1,2) >> t(1) >>
439+
R(2,0) >> R(2,1) >> R(2,2) >> t(2) >>
440+
last_row(0) >> last_row(1) >> last_row(2) >> last_row(3)) {
441+
R_gripper2base.push_back(Mat(R));
442+
t_gripper2base.push_back(Mat(t));
443+
}
370444
}
371445

372-
return method_name;
373-
}
446+
std::vector<HandEyeCalibrationMethod> methods;
447+
methods.push_back(CALIB_HAND_EYE_TSAI);
448+
methods.push_back(CALIB_HAND_EYE_PARK);
449+
methods.push_back(CALIB_HAND_EYE_HORAUD);
450+
methods.push_back(CALIB_HAND_EYE_ANDREFF);
451+
methods.push_back(CALIB_HAND_EYE_DANIILIDIS);
374452

375-
double CV_CalibrateHandEyeTest::sign_double(double val)
376-
{
377-
return (0 < val) - (val < 0);
378-
}
453+
for (size_t idx = 0; idx < methods.size(); idx++) {
454+
SCOPED_TRACE(cv::format("method=%s", getMethodName(methods[idx]).c_str()));
379455

380-
///////////////////////////////////////////////////////////////////////////////////////////////////
456+
Matx33d R_cam2gripper_est;
457+
Matx31d t_cam2gripper_est;
458+
calibrateHandEye(R_gripper2base, t_gripper2base, R_target2cam, t_target2cam, R_cam2gripper_est, t_cam2gripper_est, methods[idx]);
381459

382-
TEST(Calib3d_CalibrateHandEye, regression) { CV_CalibrateHandEyeTest test; test.safe_run(); }
460+
EXPECT_TRUE(checkRange(R_cam2gripper_est));
461+
EXPECT_TRUE(checkRange(t_cam2gripper_est));
462+
}
463+
}
383464

384465
}} // namespace

modules/dnn/src/layers/scale_layer.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Implementation of Scale layer.
1616
#include "../op_inf_engine.hpp"
1717
#include "../ie_ngraph.hpp"
1818

19+
#include <opencv2/imgproc.hpp>
1920
#include <opencv2/dnn/shape_utils.hpp>
2021

2122
#ifdef HAVE_CUDA
@@ -389,7 +390,7 @@ class DataAugmentationLayerImpl CV_FINAL : public DataAugmentationLayer
389390
std::vector<MatShape> &internals) const CV_OVERRIDE
390391
{
391392
CV_Assert_N(inputs.size() == 1, blobs.size() == 3);
392-
CV_Assert_N(blobs[0].total() == 1, blobs[1].total() == total(inputs[0], 1),
393+
CV_Assert_N(blobs[0].total() == 1,
393394
blobs[2].total() == inputs[0][1]);
394395

395396
outputs.assign(1, inputs[0]);
@@ -412,15 +413,20 @@ class DataAugmentationLayerImpl CV_FINAL : public DataAugmentationLayer
412413
float* outData = outputs[0].ptr<float>();
413414

414415
Mat data_mean_cpu = blobs[1].clone();
416+
Mat mean_resize = Mat(inputs[0].size[3], inputs[0].size[2], CV_32FC3);
417+
Mat mean_3d = Mat(data_mean_cpu.size[3], data_mean_cpu.size[2], CV_32FC3, data_mean_cpu.ptr<float>(0));
418+
resize(mean_3d, mean_resize, Size(inputs[0].size[3], inputs[0].size[2]));
419+
int new_size[] = {1, mean_resize.channels(), mean_resize.cols, mean_resize.rows};
420+
Mat data_mean_cpu_resize = mean_resize.reshape(1, *new_size);
415421
Mat data_mean_per_channel_cpu = blobs[2].clone();
416422

417-
const int numWeights = data_mean_cpu.total();
423+
const int numWeights = data_mean_cpu_resize.total();
418424
CV_Assert(numWeights != 0);
419425

420426
++num_iter;
421427
if (num_iter <= recompute_mean)
422428
{
423-
data_mean_cpu *= (num_iter - 1);
429+
data_mean_cpu_resize *= (num_iter - 1);
424430
const int batch = inputs[0].size[0];
425431
float alpha = 1.0 / batch;
426432

@@ -429,15 +435,15 @@ class DataAugmentationLayerImpl CV_FINAL : public DataAugmentationLayer
429435
Mat inpSlice(1, numWeights, CV_32F, inpData);
430436
inpSlice = alpha * inpSlice;
431437

432-
add(data_mean_cpu.reshape(1, 1), inpSlice, data_mean_cpu.reshape(1, 1));
438+
add(data_mean_cpu_resize.reshape(1, 1), inpSlice, data_mean_cpu_resize.reshape(1, 1));
433439
inpData += numWeights;
434440
}
435-
data_mean_cpu *= (1.0 / num_iter);
441+
data_mean_cpu_resize *= (1.0 / num_iter);
436442

437-
int newsize[] = {blobs[1].size[1], (int)blobs[1].total(2)};
438-
reduce(data_mean_cpu.reshape(1, 2, &newsize[0]), data_mean_per_channel_cpu, 1, REDUCE_SUM, CV_32F);
443+
int newsize[] = {inputs[0].size[1], (int)inputs[0].total(2)};
444+
reduce(data_mean_cpu_resize.reshape(1, 2, &newsize[0]), data_mean_per_channel_cpu, 1, REDUCE_SUM, CV_32F);
439445

440-
int area = blobs[1].total(2);
446+
int area = inputs[0].total(2);
441447
data_mean_per_channel_cpu *= (1.0 / area);
442448
}
443449

@@ -452,7 +458,7 @@ class DataAugmentationLayerImpl CV_FINAL : public DataAugmentationLayer
452458
Mat inpSlice(1, numWeights, CV_32F, inpData);
453459
Mat outSlice(1, numWeights, CV_32F, outData);
454460

455-
add(inpSlice, (-1) * data_mean_cpu, outSlice);
461+
add(inpSlice, (-1) * data_mean_cpu_resize, outSlice);
456462
inpData += numWeights;
457463
outData += numWeights;
458464
}

0 commit comments

Comments
 (0)