Closed thompson318 closed 1 year ago
Thanks Steve to point out where triangulated=cvpy.triangulate_points_using_hartley( is used in video_calibration_metrics.py, implemented: https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Code/Lib/sksTriangulate.cpp#L291 and tested https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Testing/sksTriangulateTest.cpp
CV_64FC1: 64-bit double with 1 channel
> https://stackoverflow.com/questions/64604533/215assertion-failed-type-cv-32fc1-type-cv-32fc2-type-cv-64fc1, I have implemented matrices as np.zeros((4, 4, 1), dtype=np.double64)
cv.solve(src1, src2[, dst[, flags]]) ->retval, dst
> https://docs.opencv.org/4.6.0/d2/de8/group__core__array.html#ga12b43690dbd31fed96f213eefead2373cv2.solve
extracted from open source projects: https://python.hotexamples.com/examples/cv2/-/solve/python-solve-function-examples.htmlcv2.triangulatePoints
Tutorials https://scikit-surgerycalibration.readthedocs.io/en/latest/tutorials/calibration.html seems to work much better using jupypter notebook, specially for this bit: "If you hold the chessboard in view of your camera, and run the below cell repeatedly, it will grab some frames." But got few errors:
1 if number_of_views > 1:
2 # proj_err, params = calibrator.calibrate()
----> 3 proj_err, recon_err, params = calibrator.calibrate()
4
5 print(f'Reprojection (2D) error is: {proj_err}')
ValueError: not enough values to unpack (expected 3, got 2)
Sorted with `proj_err, params = calibrator.calibrate()`
* [x] for Dot Calibration, I get: error: OpenCV(4.6.0) :-1: error: (-5:Bad argument) in function 'circle'
error Traceback (most recent call last)
/tmp/ipykernel_44007/3599310274.py in
error: OpenCV(4.6.0) :-1: error: (-5:Bad argument) in function 'circle'
Overload resolution failed:
- Can't parse 'center'. Sequence item with index 0 has a wrong type
- Can't parse 'center'. Sequence item with index 0 has a wrong type
## conda env packages
name: scikit-surgerycalibrationVE channels:
dependencies:
Few errors from the C++ to python
migration:
Traceback (most recent call last):
File "sand.py", line 3, in <module>
P1 = np.zeros((3, 4, 1), dtype=np.double64)
File "/home/mxochicale/anaconda3/envs/scikit-surgerycalibrationVE/lib/python3.7/site-packages/numpy/__init__.py", line 314, in __getattr__
"{!r}".format(__name__, attr))
AttributeError: module 'numpy' has no attribute 'double64'
Sorted with `P1 = np.zeros((3, 4, 1), dtype=np.double)` > https://numpy.org/doc/stable/user/basics.types.html
* [x] `AttributeError: module 'cv2' has no attribute 'Point3d'`
Traceback (most recent call last):
File "sand.py", line 5, in
sorted with `u1 = np.zeros((3, 1, 1), dtype=np.double)` > https://docs.opencv.org/4.6.0/df/d6c/classcv_1_1Point3__.html
* [x] `AttributeError: 'numpy.ndarray' object has no attribute 'row'`
Traceback (most recent call last):
File "sand.py", line 76, in
sorted with `P1[2][:]`
* [x] `double p2x1 = cv::Mat_<double>(cv::Mat_<double>(P1).row(2)*X)(0);` to its python version
Traceback (most recent call last):
File "sand.py", line 80, in
`row` seems to be implemented in an old version of opencv https://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat-row
Do you know the reference of the following snippet at cv::Point3d InternalIterativeTriangulatePointUsingSVD(...
? would to see the equation for this: double p2x1 = cv::Mat_<double>(cv::Mat_<double>(P1).row(2)*X)(0);
Do we want p2x1=(P1[2][:] * X)[0] ?
Using np.arrays did not correctly make matrix multiplications, so I use asmatrix and transpose T
print(f'i: {i}')
AA = np.asmatrix( P1[2][:] ).T
print(f'PRINT: { AA.shape }')
print(f'PRINT: {AA} ')
BB = np.asmatrix( X ).T
print(f'PRINT: { BB.shape }')
print(f'PRINT: { BB }')
print(f'PRINT AA*BB: { (AA * BB).shape }')
print(f'PRINT AA*BB: { (AA * BB) }')
resulting in
i: 0
PRINT: (1, 4)
PRINT: [[0. 0. 0. 0.]]
PRINT: (4, 1)
PRINT: [[0.]
[0.]
[0.]
[1.]]
PRINT AA*BB: (1, 1)
PRINT AA*BB: [[0.]]
The following make sense to me but need to check the equation to confirm its right implementation
p2x1 = (np.asmatrix(P1[2][:]).T) * (np.asmatrix(X).T)
Looking for further references of p2x1 and p2x1 in mitkCameraCalibrationFacade.cxx and sksTriangulate.cpp
double p2x1 = cv::Mat_<double>(cv::Mat_<double>(P1).row(2)*X)(0);
double p2x2 = cv::Mat_<double>(cv::Mat_<double>(P2).row(2)*X)(0);
def IterativeLinearLSTriangulation(u, P, u1, P1):
wi = 1
wi1 = 1
X = np.empty([4,1]);
for i in xrange(0, 10):
X_ = LinearLSTriangulation(u,P,u1,P1)
X[0] = X_[0]
X[1] = X_[1]
X[2] = X_[2]
X[3] = 1.0
p2x = (P[2,].dot(X))[0]
p2x1 = (P1[2,].dot(X))[0]
if (abs(wi - p2x) <= EPSILON and abs(wi1 - p2x1) <= EPSILON):
break
wi = p2x
wi1 = p2x1
A = np.array([[(u[0]*P[2,0]-P[0,0])/wi, (u[0]*P[2,1]-P[0,1])/wi, (u[0]*P[2,2]-P[0,2])/wi],
[(u[1]*P[2,0]-P[1,0])/wi, (u[1]*P[2,1]-P[1,1])/wi, (u[1]*P[2,2]-P[1,2])/wi],
[(u1[0]*P1[2,0]-P1[0,0])/wi1, (u1[0]*P1[2,1]-P1[0,1])/wi1, (u1[0]*P1[2,2]-P1[0,2])/wi1],
[(u1[1]*P1[2,0]-P1[1,0])/wi1, (u1[1]*P1[2,1]-P1[1,1])/wi1, (u1[1]*P1[2,2]-P1[1,2])/wi1]])
B = np.array([[-(u[0]*P[2,3]-P[0,3])/wi],
[-(u[1]*P[2,3]-P[1,3])/wi],
[-(u1[0]*P1[2,3]-P1[0,3])/wi1],
[-(u1[1]*P1[2,3]-P1[1,3])/wi1]])
(retval, X_) = cv2.solve(A,B,flags=cv2.DECOMP_SVD)
X[0] = X_[0]
X[1] = X_[1]
X[2] = X_[2]
X[3] = 1.0
return X
def iterative_LS_triangulation(u1, P1, u2, P2, tolerance=3.e-5):
"""
Iterative (Linear) Least Squares based triangulation.
From "Triangulation", Hartley, R.I. and Sturm, P., Computer vision and image understanding, 1997.
Relative speed: 0.025
(u1, P1) is the reference pair containing normalized image coordinates (x, y) and the corresponding camera matrix.
(u2, P2) is the second pair.
"tolerance" is the depth convergence tolerance.
Additionally returns a status-vector to indicate outliers:
1: inlier, and in front of both cameras
0: outlier, but in front of both cameras
-1: only in front of second camera
-2: only in front of first camera
-3: not in front of any camera
Outliers are selected based on non-convergence of depth, and on negativity of depths (=> behind camera(s)).
u1 and u2 are matrices: amount of points equals #rows and should be equal for u1 and u2.
"""
A = np.zeros((4, 3))
b = np.zeros((4, 1))
# Create array of triangulated points
x = np.empty((4, len(u1))); x[3, :].fill(1) # create empty array of homogenous 3D coordinates
x_status = np.empty(len(u1), dtype=int)
# Initialize C matrices
C1 = np.array(iterative_LS_triangulation_C)
C2 = np.array(iterative_LS_triangulation_C)
for xi in range(len(u1)):
# Build C matrices, to construct A and b in a concise way
C1[:, 2] = u1[xi, :]
C2[:, 2] = u2[xi, :]
# Build A matrix
A[0:2, :] = C1.dot(P1[0:3, 0:3]) # C1 * R1
A[2:4, :] = C2.dot(P2[0:3, 0:3]) # C2 * R2
# Build b vector
b[0:2, :] = C1.dot(P1[0:3, 3:4]) # C1 * t1
b[2:4, :] = C2.dot(P2[0:3, 3:4]) # C2 * t2
b *= -1
# Init depths
d1 = d2 = 1.
for i in range(10): # Hartley suggests 10 iterations at most
# Solve for x vector
#x_old = np.array(x[0:3, xi]) # TODO: remove
cv2.solve(A, b, x[0:3, xi:xi+1], cv2.DECOMP_SVD)
# Calculate new depths
d1_new = P1[2, :].dot(x[:, xi])
d2_new = P2[2, :].dot(x[:, xi])
# Convergence criterium
#print i, d1_new - d1, d2_new - d2, (d1_new > 0 and d2_new > 0) # TODO: remove
#print i, (d1_new - d1) / d1, (d2_new - d2) / d2, (d1_new > 0 and d2_new > 0) # TODO: remove
#print i, np.sqrt(np.sum((x[0:3, xi] - x_old)**2)), (d1_new > 0 and d2_new > 0) # TODO: remove
##print i, u1[xi, :] - P1[0:2, :].dot(x[:, xi]) / d1_new, u2[xi, :] - P2[0:2, :].dot(x[:, xi]) / d2_new # TODO: remove
#print bool(i) and ((d1_new - d1) / (d1 - d_old), (d2_new - d2) / (d2 - d1_old), (d1_new > 0 and d2_new > 0)) # TODO: remove
##if abs(d1_new - d1) <= tolerance and abs(d2_new - d2) <= tolerance: print "Orig cond met" # TODO: remove
if abs(d1_new - d1) <= tolerance and \
abs(d2_new - d2) <= tolerance:
#if i and np.sum((x[0:3, xi] - x_old)**2) <= 0.0001**2:
#if abs((d1_new - d1) / d1) <= 3.e-6 and \
#abs((d2_new - d2) / d2) <= 3.e-6: #and \
#abs(d1_new - d1) <= tolerance and \
#abs(d2_new - d2) <= tolerance:
#if i and 1 - abs((d1_new - d1) / (d1 - d_old)) <= 1.e-2 and \ # TODO: remove
#1 - abs((d2_new - d2) / (d2 - d1_old)) <= 1.e-2 and \ # TODO: remove
#abs(d1_new - d1) <= tolerance and \ # TODO: remove
#abs(d2_new - d2) <= tolerance: # TODO: remove
break
# Re-weight A matrix and b vector with the new depths
A[0:2, :] *= 1 / d1_new
A[2:4, :] *= 1 / d2_new
b[0:2, :] *= 1 / d1_new
b[2:4, :] *= 1 / d2_new
# Update depths
#d_old = d1 # TODO: remove
#d1_old = d2 # TODO: remove
d1 = d1_new
d2 = d2_new
# Set status
x_status[xi] = ( i < 10 and # points should have converged by now
(d1_new > 0 and d2_new > 0) ) # points should be in front of both cameras
if d1_new <= 0: x_status[xi] -= 1
if d2_new <= 0: x_status[xi] -= 2
return x[0:3, :].T.astype(output_dtype), x_status
Just testing few matrix operations
print(f'P1= {P1}')
print(f'P1[2,] = {P1[2,]}')
print(f'P1[2][:] = {P1[2][:]}')
logs
P1= [[[0.]
[0.]
[0.]
[0.]]
[[0.]
[0.]
[0.]
[0.]]
[[0.]
[0.]
[0.]
[0.]]]
P1[2,] = [[0.]
[0.]
[0.]
[0.]]
P1[2][:] = [[0.]
[0.]
[0.]
[0.]]
Steve and I discussed current status and next steps to unit test:
def triangulate_points_using_hartley_opencv(left_undistorted,
right_undistorted,
leftCameraIntrinsicParams,
rightCameraIntrinsicParams,
leftToRightRotationMatrix,
leftToRightTranslationVector):
Steve suggest to look into points_in_2d to extract left_undistorted and right_undistorted :
points_in_2d = np.zeros((4, 4), dtype=np.double) points_in_2d[0, 0] = 1100.16 points_in_2d[0, 1] = 262.974 points_in_2d[0, 2] = 1184.84 points_in_2d[0, 3] = 241.915 points_in_2d[1, 0] = 1757.74 points_in_2d[1, 1] = 228.971 points_in_2d[1, 2] = 1843.52 points_in_2d[1, 3] = 204.083 points_in_2d[2, 0] = 1065.44 points_in_2d[2, 1] = 651.593 points_in_2d[2, 2] = 1142.75 points_in_2d[2, 3] = 632.817 points_in_2d[3, 0] = 1788.22 points_in_2d[3, 1] = 650.41 points_in_2d[3, 2] = 1867.78 points_in_2d[3, 3] = 632.59
from: scikit-surgeryopencvcpp/blob/master/Testing/sksTriangulateTest.cpp
cv::Mat pointsIn2D = cv::Mat::zeros(4, 4, CV_64FC1);
pointsIn2D.at
cv2.triangulatePoints
print(f'\n {p_l}')
print(f'\n {p_r}')
print(f'\n {left_undistorted}')
print(f'\n {right_undistorted}')
triangulated_cv = cv2.triangulatePoints(p_l,
p_r,
left_undistorted,
right_undistorted)
Terminal logs:
tests/algorithms/test_triangulate.py::test_triangulate_points_using_hartley_opencv [[2.01218631e+03 0.00000000e+00 9.44717371e+02 0.00000000e+00] [0.00000000e+00 2.01796602e+03 6.17109398e+02 0.00000000e+00] [0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00]]
[[ 2.00989229e+03 -2.32425602e+01 1.10225114e+03 -8.06867616e+03] [-1.53917938e+01 2.03922444e+03 5.93705918e+02 1.26399541e+03] [-2.53880000e-02 -2.24050000e-02 9.99426000e-01 1.30025600e+00]]
[[1100.16 262.974] [1757.74 228.971] [1065.44 651.593] [1788.22 650.41 ]]
[[1184.84 241.915] [1843.52 204.083] [1142.75 632.817] [1867.78 632.59 ]] FAILED
triangulated_cv = cv2.triangulatePoints(p_l,
p_r,
left_undistorted,
right_undistorted)
E cv2.error: OpenCV(4.5.5) /io/opencv/modules/calib3d/src/triangulate.cpp:75: error: (-209:Sizes of input arguments do not match) Number of proj points coordinates must be == 2 in function 'icvTriangulatePoints'
sksurgerycalibration/algorithms/triangulate.py:283: error
* Sorted out by transposing vectors:
print(f'\n {p_l}')
print(f'\n {p_r}')
print(f'\n {left_undistorted.T}')
print(f'\n {right_undistorted.T}')
triangulated_cv = cv2.triangulatePoints(p_l,
p_r,
left_undistorted.T,
right_undistorted.T)
logs:
tests/algorithms/test_triangulate.py::test_triangulate_points_using_hartley_opencv [[2.01218631e+03 0.00000000e+00 9.44717371e+02 0.00000000e+00] [0.00000000e+00 2.01796602e+03 6.17109398e+02 0.00000000e+00] [0.00000000e+00 0.00000000e+00 1.00000000e+00 0.00000000e+00]]
[[ 2.00989229e+03 -2.32425602e+01 1.10225114e+03 -8.06867616e+03] [-1.53917938e+01 2.03922444e+03 5.93705918e+02 1.26399541e+03] [-2.53880000e-02 -2.24050000e-02 9.99426000e-01 1.30025600e+00]]
[[1100.16 1757.74 1065.44 1788.22 ] [ 262.974 228.971 651.593 650.41 ]]
[[1184.84 1843.52 1142.75 1867.78 ] [ 241.915 204.083 632.817 632.59 ]] PASSED
Currently migrating the following test to its python version https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Testing/sksTriangulateTest.cpp , along with ComputeRMSBetweenCorrespondingPoints()
from https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Code/Lib/sksMaths.cpp
cv::Mat modelPointsTransposed;
cv::transpose(modelPoints, modelPointsTransposed);
cv::Mat rotatedModelPoints = cv::Mat(modelPointsTransposed.rows, modelPointsTransposed.cols, CV_64FC1);
cv::gemm(leftRotation, modelPointsTransposed, 1, cv::Mat(), 0, rotatedModelPoints);
cv::Mat modelPointsRotatedAndTransposed;
cv::transpose(rotatedModelPoints, modelPointsRotatedAndTransposed);
cv::Mat transformedModelPoints = cv::Mat(modelPointsRotatedAndTransposed.rows, modelPointsRotatedAndTransposed.cols, CV_64FC1);
for (int r = 0; r < modelPointsRotatedAndTransposed.rows; r++)
{
for (int c = 0; c < modelPointsRotatedAndTransposed.cols; c++)
{
transformedModelPoints.at<double>(r, c) = modelPointsRotatedAndTransposed.at<double>(r, c) + leftTranslation.at<double>(c, 0);
}
}
std::cerr << "pointsFromHartley=" << pointsFromHartley << std::endl;
std::cerr << "pointsFromMidpoint=" << pointsFromMidpoint << std::endl;
std::cerr << "transformedModelPoints=" << transformedModelPoints << std::endl;
double rmsHartley = sks::ComputeRMSBetweenCorrespondingPoints(transformedModelPoints, pointsFromHartley);
double rmsMidpoint = sks::ComputeRMSBetweenCorrespondingPoints(transformedModelPoints, pointsFromMidpoint);
std::cerr << "rmsHartley=" << rmsHartley << std::endl;
std::cerr << "rmsMidpoints=" << rmsMidpoint << std::endl;
cv::gemm(
https://docs.opencv.org/4.6.0/d9/d88/group__cudaarithm__arithm.html#ga42efe211d7a43bbc922da044c4f17130double ComputeRMSBetweenCorrespondingPoints(const cv::Mat& a, const cv::Mat& b)
https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Code/Lib/sksMaths.cpplint run-test: commands[0] | pylint --rcfile=tests/pylintrc sksurgerycalibration tests
************* Module sksurgerycalibration.video.video_calibration_driver_stereo
sksurgerycalibration/video/video_calibration_driver_stereo.py:118:24: E1101: Module 'cv2' has no 'CALIB_USE_INTRINSIC_GUESS' member (no-member)
sksurgerycalibration/video/video_calibration_driver_stereo.py:180:43: E1101: Module 'cv2' has no 'CALIB_USE_INTRINSIC_GUESS' member (no-member)
************* Module sksurgerycalibration.video.video_calibration_data
sksurgerycalibration/video/video_calibration_data.py:210:12: E1101: Module 'cv2' has no 'imwrite' member (no-member)
sksurgerycalibration/video/video_calibration_data.py:246:20: E1101: Module 'cv2' has no 'imread' member (no-member)
sksurgerycalibration/video/video_calibration_data.py:291:15: E1101: Module 'cv2' has no 'FONT_HERSHEY_SIMPLEX' member (no-member)
sksurgerycalibration/video/video_calibration_data.py:301:16: E1101: Module 'cv2' has no 'putText' member (no-member)
sksurgerycalibration/video/video_calibration_data.py:305:55: E1101: Module 'cv2' has no 'LINE_AA' member (no-member)
sksurgerycalibration/video/video_calibration_data.py:312:12: E1101: Module 'cv2' has no 'imwrite' member (no-member)
Solutions:
from cv2 import cv2
PyLint not recognizing cv2 members, https://github.com/PyCQA/pylint/issues/2426 generated-members=cv2.*
in pylintrc: https://stackoverflow.com/questions/50612169/pylint-not-recognizing-cv2-members/73145142#73145142. Chose this one as does not require to change scripts imports.C0301: Line too long (108/80) (line-too-long
************* Module sksurgerycalibration.video.video_calibration_metrics
sksurgerycalibration/video/video_calibration_metrics.py:153:0: C0301: Line too long (100/80) (line-too-long)
************* Module sksurgerycalibration.algorithms.triangulate
sksurgerycalibration/algorithms/triangulate.py:98:0: C0301: Line too long (108/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:132:0: C0301: Line too long (125/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:137:0: C0301: Line too long (84/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:160:0: C0301: Line too long (92/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:169:0: C0301: Line too long (100/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:177:0: C0301: Line too long (99/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:178:0: C0301: Line too long (93/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:179:0: C0301: Line too long (105/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:204:0: C0301: Line too long (112/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:206:0: C0301: Line too long (122/80) (line-too-long)
sksurgerycalibration/algorithms/triangulate.py:232:0: C0301: Line too long (95/80) (line-too-long)
max-line-length=240
> https://stackoverflow.com/questions/30667612/pylint-overriding-max-line-length-in-individual-file C0103: Function name
sksurgerycalibration/algorithms/triangulate.py:10:0: C0103: Function name "internal_triangulate_point_using_svd" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
C0103: Argument name
************* Module sksurgerycalibration.algorithms.triangulate
sksurgerycalibration/algorithms/triangulate.py:11:33: C0103: Argument name "p2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:12:33: C0103: Argument name "u1" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:13:33: C0103: Argument name "u2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:14:33: C0103: Argument name "w1" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:15:33: C0103: Argument name "w2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:37:4: C0103: Variable name "a" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:51:4: C0103: Variable name "b" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:57:4: C0103: Variable name "x" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:63:0: C0103: Function name "_iterative_triangulate_point_using_svd" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:64:43: C0103: Argument name "p2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:65:43: C0103: Argument name "u1" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:66:43: C0103: Argument name "u2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:84:4: C0103: Variable name "w1" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:85:4: C0103: Variable name "w2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:86:4: C0103: Variable name "x" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:90:8: C0103: Variable name "x_" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:103:8: C0103: Variable name "w1" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:104:8: C0103: Variable name "w2" doesn't conform to '[a-z_][a-z0-9_]{2,30}$' pattern (invalid-name)
sksurgerycalibration/algorithms/triangulate.py:89:8: W0612: Unused variable 'i' (unused-variable)
W0612: Unused variable 'i' (unused-variable)
i
with dummy_index
at for dummy_index in range(0, 10):
> https://stackoverflow.com/questions/10107350/how-to-handle-the-pylint-message-idw0612-unused-variable C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
if (b.shape[1] != 3):
with `if b.shape[1] != 3: > https://pylint.pycqa.org/en/latest/user_guide/messages/convention/superfluous-parens.htmltest_charuco_plus_chessboard.py
def test_stereo_davinci():
left_images = []
...
reproj_err, recon_err, params = calibrator.calibrate()
print("Reproj:" + str(reproj_err))
print("Recon:" + str(recon_err))
> assert reproj_err < 1.1
E assert 82521.00771341282 < 1.1
tests/video/test_charuco_plus_chessboard.py:55: AssertionError
test_handeye_dots.py
...
> assert reproj_err_1 == pytest.approx(1., rel=0.2)
E assert 146.10223709746785 == 1.0 ± 2.0e-01
E comparison failed
E Obtained: 146.10223709746785
E Expected: 1.0 ± 2.0e-01
tests/video/test_hand_eye.py:78: AssertionError
[x] test_charuco_dataset_B, test_precalbration with test_precalib.py
print(stereo_reproj_err, stereo_recon_err, tracked_reproj_err, tracked_recon_err)
> assert stereo_reproj_err < 1
E assert 7.116922375480872 < 1
tests/video/test_precalib.py:92: AssertionError
calib_driver.handeye_calibration()
print(stereo_reproj_err, stereo_recon_err, tracked_reproj_err, tracked_recon_err)
assert stereo_reproj_err < 4.5
E assert 34.74794862170866 < 4.5
tests/video/test_precalib.py:124: AssertionError
### Notes
* Steve suggested to trying from a clean repo: clone repo and run tox
* Cloning repo and running tox passed tests ( on Fri 23 Dec 10:21:21 GMT 2022)
py37: OK (339.19=setup[16.31]+cmd[0.39,0.05,322.30,0.14] seconds) lint: OK (24.84=setup[15.34]+cmd[0.37,9.13] seconds) congratulations :) (364.18 seconds)
Running tox in a second time:
py37: OK (325.41=setup[0.02]+cmd[0.32,0.05,324.88,0.14] seconds) lint: OK (9.47=setup[0.01]+cmd[0.32,9.14] seconds) congratulations :) (335.00 seconds)
Running tox in the original cloned path
py37: OK (306.90=setup[2.35]+cmd[0.45,0.06,303.89,0.14] seconds) lint: OK (12.65=setup[2.39]+cmd[0.46,9.81] seconds) congratulations :) (319.68 seconds)
Reproducing TriangulatePointsUsingHartley
implementation to compute rmsHartley
/*=============================================================================
TriangulatePointsUsingHartley
References:
SKSURGERYCVCPP: scikit-surgeryopencvcpp provides opencv functions in C++
https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Testing/sksTriangulateTest.cpp
https://github.com/SciKit-Surgery/scikit-surgeryopencvcpp/blob/master/Code/Lib/sksMaths.cpp
=============================================================================*/
#include <opencv2/opencv.hpp>
namespace sks
{
//-----------------------------------------------------------------------------
cv::Mat_<double> InternalTriangulatePointUsingSVD(
const cv::Matx34d& P1,
const cv::Matx34d& P2,
const cv::Point3d& u1,
const cv::Point3d& u2,
const double& w1,
const double& w2
)
{
// Build matrix A for homogeneous equation system Ax = 0
// Assume X = (x,y,z,1), for Linear-LS method
// Which turns it into a AX = B system, where A is 4x3, X is 3x1 and B is 4x1
cv::Matx43d A((u1.x*P1(2,0)-P1(0,0))/w1, (u1.x*P1(2,1)-P1(0,1))/w1, (u1.x*P1(2,2)-P1(0,2))/w1,
(u1.y*P1(2,0)-P1(1,0))/w1, (u1.y*P1(2,1)-P1(1,1))/w1, (u1.y*P1(2,2)-P1(1,2))/w1,
(u2.x*P2(2,0)-P2(0,0))/w2, (u2.x*P2(2,1)-P2(0,1))/w2, (u2.x*P2(2,2)-P2(0,2))/w2,
(u2.y*P2(2,0)-P2(1,0))/w2, (u2.y*P2(2,1)-P2(1,1))/w2, (u2.y*P2(2,2)-P2(1,2))/w2
);
cv::Matx41d B(-(u1.x*P1(2,3) -P1(0,3))/w1,
-(u1.y*P1(2,3) -P1(1,3))/w1,
-(u2.x*P2(2,3) -P2(0,3))/w2,
-(u2.y*P2(2,3) -P2(1,3))/w2
);
cv::Mat_<double> X;
cv::solve(A,B,X,cv::DECOMP_SVD);
return X;
}
//-----------------------------------------------------------------------------
cv::Point3d InternalIterativeTriangulatePointUsingSVD(
const cv::Matx34d& P1,
const cv::Matx34d& P2,
const cv::Point3d& u1,
const cv::Point3d& u2
)
{
double epsilon = 0.00000000001;
double w1 = 1, w2 = 1;
cv::Mat_<double> X(4,1);
for (int i=0; i<10; i++) // Hartley suggests 10 iterations at most
{
cv::Mat_<double> X_ = InternalTriangulatePointUsingSVD(P1,P2,u1,u2,w1,w2);
X(0) = X_(0);
X(1) = X_(1);
X(2) = X_(2);
X(3) = 1.0;
double p2x1 = cv::Mat_<double>(cv::Mat_<double>(P1).row(2)*X)(0);
double p2x2 = cv::Mat_<double>(cv::Mat_<double>(P2).row(2)*X)(0);
if(fabs(w1 - p2x1) <= epsilon && fabs(w2 - p2x2) <= epsilon)
break;
w1 = p2x1;
w2 = p2x2;
}
cv::Point3d result;
result.x = X(0);
result.y = X(1);
result.z = X(2);
return result;
}
//-----------------------------------------------------------------------------
cv::Mat TriangulatePointsUsingHartley(
const cv::Mat& inputUndistortedPoints,
const cv::Mat& leftCameraIntrinsicParams,
const cv::Mat& rightCameraIntrinsicParams,
const cv::Mat& leftToRightRotationMatrix,
const cv::Mat& leftToRightTranslationVector
)
{
int numberOfPoints = inputUndistortedPoints.rows;
cv::Mat outputPoints = cv::Mat(numberOfPoints, 3, CV_64FC1);
cv::Mat K1 = cv::Mat(3, 3, CV_64FC1);
cv::Mat K2 = cv::Mat(3, 3, CV_64FC1);
cv::Mat K1Inv = cv::Mat(3, 3, CV_64FC1);
cv::Mat K2Inv = cv::Mat(3, 3, CV_64FC1);
cv::Mat R1 = cv::Mat::eye(3, 3, CV_64FC1);
cv::Mat R2 = leftToRightRotationMatrix;
cv::Mat E1 = cv::Mat::eye(4, 4, CV_64FC1);
cv::Mat E1Inv = cv::Mat::eye(4, 4, CV_64FC1);
cv::Mat E2 = cv::Mat::eye(4, 4, CV_64FC1);
cv::Mat L2R = cv::Mat(4, 4, CV_64FC1);
cv::Matx34d P1d, P2d;
// Construct:
// E1 = Object to Left Camera = Left Camera Extrinsics.
// E2 = Object to Right Camera = Right Camera Extrinsics.
// K1 = Copy of Left Camera intrinsics.
// K2 = Copy of Right Camera intrinsics.
// Copy data into cv::Mat data types.
// Camera calibration routines are 32 bit, as some drawing functions require 32 bit data.
// These triangulation routines need 64 bit data.
for (int r = 0; r < 3; r++)
{
for (int c = 0; c < 3; c++)
{
K1.at<double>(r, c) = leftCameraIntrinsicParams.at<double>(r, c);
K2.at<double>(r, c) = rightCameraIntrinsicParams.at<double>(r, c);
E2.at<double>(r, c) = R2.at<double>(r, c);
}
E2.at<double>(r, 3) = leftToRightTranslationVector.at<double>(r, 0);
}
// We invert the intrinsic params, so we can convert from pixels to normalised image coordinates.
K1Inv = K1.inv();
K2Inv = K2.inv();
// We want output coordinates relative to left camera.
E1Inv = E1.inv();
L2R = E2 * E1Inv;
// Reading Prince 2012 Computer Vision, the projection matrix, is just the extrinsic parameters,
// as our coordinates will be in a normalised camera space. P1 should be identity, so that
// reconstructed coordinates are in Left Camera Space, to P2 should reflect a right to left transform.
P1d(0,0) = 1; P1d(0,1) = 0; P1d(0,2) = 0; P1d(0,3) = 0;
P1d(1,0) = 0; P1d(1,1) = 1; P1d(1,2) = 0; P1d(1,3) = 0;
P1d(2,0) = 0; P1d(2,1) = 0; P1d(2,2) = 1; P1d(2,3) = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
P2d(i,j) = L2R.at<double>(i,j);
}
}
#pragma omp parallel
{
cv::Mat u1 = cv::Mat(3, 1, CV_64FC1);
cv::Mat u2 = cv::Mat(3, 1, CV_64FC1);
cv::Mat u1t = cv::Mat(3, 1, CV_64FC1);
cv::Mat u2t = cv::Mat(3, 1, CV_64FC1);
cv::Point3d u1p, u2p; // Normalised image coordinates. (i.e. relative to a principal point of zero, and in millimetres not pixels).
cv::Point3d reconstructedPoint; // the output 3D point, in reference frame of left camera.
#pragma omp for
for (int i = 0; i < numberOfPoints; i++)
{
u1.at<double>(0,0) = inputUndistortedPoints.at<double>(i, 0);
u1.at<double>(1,0) = inputUndistortedPoints.at<double>(i, 1);
u1.at<double>(2,0) = 1;
u2.at<double>(0,0) = inputUndistortedPoints.at<double>(i, 2);
u2.at<double>(1,0) = inputUndistortedPoints.at<double>(i, 3);
u2.at<double>(2,0) = 1;
// Converting to normalised image points
u1t = K1Inv * u1;
u2t = K2Inv * u2;
u1p.x = u1t.at<double>(0,0);
u1p.y = u1t.at<double>(1,0);
u1p.z = u1t.at<double>(2,0);
u2p.x = u2t.at<double>(0,0);
u2p.y = u2t.at<double>(1,0);
u2p.z = u2t.at<double>(2,0);
reconstructedPoint = InternalIterativeTriangulatePointUsingSVD(P1d, P2d, u1p, u2p);
outputPoints.at<double>(i, 0) = reconstructedPoint.x;
outputPoints.at<double>(i, 1) = reconstructedPoint.y;
outputPoints.at<double>(i, 2) = reconstructedPoint.z;
} // end for
} // end parallel block
return outputPoints;
}
//-----------------------------------------------------------------------------
double ComputeRMSBetweenCorrespondingPoints(const cv::Mat& a, const cv::Mat& b)
{
double rms = 0;
double diff = 0;
double squaredDiff = 0;
if (a.rows != b.rows)
{
std::cout << "a has " << a.rows << " rows, but b has " << b.rows;
}
if (a.cols != 3)
{
std::cout << "a does not have 3 columns.";
}
if (b.cols != 3)
{
std::cout << "b does not have 3 columns.";
}
for (unsigned int r = 0; r < a.rows; r++)
{
for (unsigned int c = 0; c < a.cols; c++)
{
diff = (b.at<double>(r, c) - a.at<double>(r, c));
squaredDiff = diff * diff;
rms += squaredDiff;
}
}
rms /= static_cast<double>(a.rows);
rms = std::sqrt(rms);
return rms;
}
}
int main(int, char**)
{
std::cout << "Hello, OpenCV\n";
cv::Mat leftIntrinsic = cv::Mat::eye(3, 3, CV_64FC1);
leftIntrinsic.at<double>(0, 0) = 2012.186314;
leftIntrinsic.at<double>(1, 1) = 2017.966019;
leftIntrinsic.at<double>(0, 2) = 944.7173708;
leftIntrinsic.at<double>(1, 2) = 617.1093984;
cv::Mat rightIntrinsic = cv::Mat::eye(3, 3, CV_64FC1);
rightIntrinsic.at<double>(0, 0) = 2037.233928;
rightIntrinsic.at<double>(1, 1) = 2052.018948;
rightIntrinsic.at<double>(0, 2) = 1051.112809;
rightIntrinsic.at<double>(1, 2) = 548.0675962;
cv::Mat leftRotation = cv::Mat::eye(3, 3, CV_64FC1);
leftRotation.at<double>(0, 0) = 0.966285949;
leftRotation.at<double>(0, 1) = -0.1053020017;
leftRotation.at<double>(0, 2) = 0.2349530874;
leftRotation.at<double>(1, 0) = -0.005105986897;
leftRotation.at<double>(1, 1) = 0.9045241988;
leftRotation.at<double>(1, 2) = 0.4263917244;
leftRotation.at<double>(2, 0) = -0.2574206552;
leftRotation.at<double>(2, 1) = -0.4132159994;
leftRotation.at<double>(2, 2) = 0.8734913532;
cv::Mat leftTranslation = cv::Mat::eye(3, 1, CV_64FC1);
leftTranslation.at<double>(0, 0) = 9.847672184;
leftTranslation.at<double>(1, 0) = -22.45992103;
leftTranslation.at<double>(2, 0) = 127.7836183;
cv::Mat rightRotation = cv::Mat::eye(3, 3, CV_64FC1);
rightRotation.at<double>(0, 0) = 0.958512625;
rightRotation.at<double>(0, 1) = -0.1175427792;
rightRotation.at<double>(0, 2) = 0.2596868167;
rightRotation.at<double>(1, 0) = -0.0115032253;
rightRotation.at<double>(1, 1) = 0.8943292319;
rightRotation.at<double>(1, 2) = 0.4472615574;
rightRotation.at<double>(2, 0) = -0.2848178778;
rightRotation.at<double>(2, 1) = -0.4316930854;
rightRotation.at<double>(2, 2) = 0.8558737386;
cv::Mat rightTranslation = cv::Mat::eye(3, 1, CV_64FC1);
rightTranslation.at<double>(0, 0) = 8.461514886;
rightTranslation.at<double>(1, 0) = -19.3242747;
rightTranslation.at<double>(2, 0) = 129.0937601;
cv::Mat pointsIn2D = cv::Mat::zeros(4, 4, CV_64FC1);
pointsIn2D.at<double>(0, 0) = 1100.16;
pointsIn2D.at<double>(0, 1) = 262.974;
pointsIn2D.at<double>(0, 2) = 1184.84;
pointsIn2D.at<double>(0, 3) = 241.915;
pointsIn2D.at<double>(1, 0) = 1757.74;
pointsIn2D.at<double>(1, 1) = 228.971;
pointsIn2D.at<double>(1, 2) = 1843.52;
pointsIn2D.at<double>(1, 3) = 204.083;
pointsIn2D.at<double>(2, 0) = 1065.44;
pointsIn2D.at<double>(2, 1) = 651.593;
pointsIn2D.at<double>(2, 2) = 1142.75;
pointsIn2D.at<double>(2, 3) = 632.817;
pointsIn2D.at<double>(3, 0) = 1788.22;
pointsIn2D.at<double>(3, 1) = 650.41;
pointsIn2D.at<double>(3, 2) = 1867.78;
pointsIn2D.at<double>(3, 3) = 632.59;
cv::Mat leftToRightRotation = cv::Mat::eye(3, 3, CV_64FC1);
leftToRightRotation.at<double>(0, 0) = 0.999678;
leftToRightRotation.at<double>(0, 1) = 0.000151;
leftToRightRotation.at<double>(0, 2) = 0.025398;
leftToRightRotation.at<double>(1, 0) = -0.000720;
leftToRightRotation.at<double>(1, 1) = 0.999749;
leftToRightRotation.at<double>(1, 2) = 0.022394;
leftToRightRotation.at<double>(2, 0) = -0.025388;
leftToRightRotation.at<double>(2, 1) = -0.022405;
leftToRightRotation.at<double>(2, 2) = 0.999426;
cv::Mat leftToRightTranslation = cv::Mat::eye(3, 1, CV_64FC1);
leftToRightTranslation.at<double>(0, 0) = -4.631472;
leftToRightTranslation.at<double>(1, 0) = 0.268695;
leftToRightTranslation.at<double>(2, 0) = 1.300256;
cv::Mat modelPoints = cv::Mat::eye(4, 3, CV_64FC1);
modelPoints.at<double>(0, 0) = 0;
modelPoints.at<double>(0, 1) = 0;
modelPoints.at<double>(0, 2) = 0;
modelPoints.at<double>(1, 0) = 39;
modelPoints.at<double>(1, 1) = 0;
modelPoints.at<double>(1, 2) = 0;
modelPoints.at<double>(2, 0) = 0;
modelPoints.at<double>(2, 1) = 27;
modelPoints.at<double>(2, 2) = 0;
modelPoints.at<double>(3, 0) = 39;
modelPoints.at<double>(3, 1) = 27;
modelPoints.at<double>(3, 2) = 0;
cv::Mat modelPointsTransposed;
cv::transpose(modelPoints, modelPointsTransposed);
std::cout << "modelPointsTransposed: \n" << modelPointsTransposed << std::endl;
cv::Mat rotatedModelPoints = cv::Mat(modelPointsTransposed.rows, modelPointsTransposed.cols, CV_64FC1);
cv::gemm(leftRotation, modelPointsTransposed, 1, cv::Mat(), 0, rotatedModelPoints);
std::cout << "rotatedModelPoints: \n" << rotatedModelPoints << std::endl;
cv::Mat modelPointsRotatedAndTransposed;
cv::transpose(rotatedModelPoints, modelPointsRotatedAndTransposed);
std::cout << "modelPointsRotatedAndTransposed: \n" << modelPointsRotatedAndTransposed << std::endl;
cv::Mat transformedModelPoints = cv::Mat(modelPointsRotatedAndTransposed.rows, modelPointsRotatedAndTransposed.cols, CV_64FC1);
for (int r = 0; r < modelPointsRotatedAndTransposed.rows; r++)
{
for (int c = 0; c < modelPointsRotatedAndTransposed.cols; c++)
{
transformedModelPoints.at<double>(r, c) = modelPointsRotatedAndTransposed.at<double>(r, c) + leftTranslation.at<double>(c, 0);
}
}
std::cout << "transformedModelPoints: \n" << transformedModelPoints << std::endl;
std::cout << "TriangulatePointsUsingHartley> pointsIn2D: \n" << pointsIn2D << std::endl;
std::cout << "TriangulatePointsUsingHartley> leftIntrinsic: \n" << leftIntrinsic << std::endl;
std::cout << "TriangulatePointsUsingHartley> rightIntrinsic: \n" << rightIntrinsic << std::endl;
std::cout << "TriangulatePointsUsingHartley> leftToRightRotation: \n" << leftToRightRotation << std::endl;
std::cout << "TriangulatePointsUsingHartley> leftToRightTranslation: \n" << leftToRightTranslation << std::endl;
cv::Mat pointsFromHartley = sks::TriangulatePointsUsingHartley(pointsIn2D,
leftIntrinsic,
rightIntrinsic,
leftToRightRotation,
leftToRightTranslation
);
std::cout << "pointsFromHartley: \n" << pointsFromHartley << std::endl;
double rmsHartley = sks::ComputeRMSBetweenCorrespondingPoints(transformedModelPoints, pointsFromHartley);
std::cout << "rmsHartley: \n" << rmsHartley << std::endl;
return 0;
}
TriangulatePointsUsingHartley> pointsIn2D:
[1100.16, 262.974, 1184.84, 241.915;
1757.74, 228.971, 1843.52, 204.083;
1065.44, 651.593, 1142.75, 632.817;
1788.22, 650.41, 1867.78, 632.59]
TriangulatePointsUsingHartley> leftIntrinsic:
[2012.186314, 0, 944.7173708;
0, 2017.966019, 617.1093984;
0, 0, 1]
TriangulatePointsUsingHartley> rightIntrinsic:
[2037.233928, 0, 1051.112809;
0, 2052.018948, 548.0675962;
0, 0, 1]
TriangulatePointsUsingHartley> leftToRightRotation:
[0.999678, 0.000151, 0.025398;
-0.00072, 0.999749, 0.022394;
-0.025388, -0.022405, 0.999426]
TriangulatePointsUsingHartley> leftToRightTranslation:
[-4.631472;
0.268695;
1.300256]
pointsFromHartley:
[9.882561793478274, -22.44358672047434, 127.9216596991245;
48.46473971483012, -23.09607651651325, 119.9524462287327;
6.946803109459471, 1.973326991586282, 115.7921729428552;
44.77458535398358, 1.768363607856355, 106.8097293986459]
rmsHartley:
1.29547
Don't need the definition of
# p1_array = np.zeros((3, 4), dtype=np.double) #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# p2_array = np.zeros((3, 4), dtype=np.double) #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# u1_array = np.zeros((3, 1), dtype=np.double) #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# u2_array = np.zeros((3, 1), dtype=np.double) #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Correct matrix multiplication
# l2r = e2_array * e1inv
l2r = np.matmul(e2_array, e1inv) #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# u1t = k1inv * u1_array
# u2t = k2inv * u2_array
u1t = np.matmul(k1inv, u1_array) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
u2t = np.matmul(k2inv, u2_array) # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
Correct least-squares operation
# x_array = np.zeros((4, 1), dtype=np.double)
# cv2.solve(a_array, b_array, x_array, flags=cv2.DECOMP_SVD)
x_array, _, _, _ = np.linalg.lstsq(a_array, b_array, rcond=-1)
Steve and I discussed next steps: to remove import sksurgeryopencvpython as cvpy
from video_calibration_metrics.py and remove scikit-surgeryopencvcpp in requirements.text and setup.py
R0914: Too many local variables (31/30) (too-many-locals)
************* Module sksurgerycalibration.algorithms.triangulate
sksurgerycalibration/algorithms/triangulate.py:113:0: R0914: Too many local variables (31/30) (too-many-locals)
:tada: SORTED OUT > https://github.com/SciKit-Surgery/scikit-surgerycalibration/commit/4cc816a664cc87fb2c78e8c7d22fbee65b510031
np.linalg.lstsq
# CODE
start = time.time_ns()
# x_array = cv2.solve(a_array, b_array, flags=cv2.DECOMP_SVD)
x_array, _, _, _ = np.linalg.lstsq(a_array, b_array, rcond=-1) #Alternatively
print(f'{ time.time_ns() - start } nsecs')
return x_array#for np.linalg.lstsq #x_array[1] #for cv2.solve
100124 nsecs 34191 nsecs 19551 nsecs 16927 nsecs 15039 nsecs 14558 nsecs 14539 nsecs 15572 nsecs 14425 nsecs 14266 nsecs 14468 nsecs 14576 nsecs 14288 nsecs
rms_hartley: 1.2954729076605125
* `cv2.solve`
start = time.time_ns()
x_array = cv2.solve(a_array, b_array, flags=cv2.DECOMP_SVD)
# x_array, _, _, _ = np.linalg.lstsq(a_array, b_array, rcond=-1) #Alternatively
print(f'{ time.time_ns() - start } nsecs')
return x_array[1] #for cv2.solve #x_array#for np.linalg.lstsq
62866 nsecs 4518 nsecs 2809 nsecs 2494 nsecs 2471 nsecs 2363 nsecs 2323 nsecs 2403 nsecs 2240 nsecs 2299 nsecs 2384 nsecs 2335 nsecs 2340 nsecs
rms_hartley: 1.2954729076604021
triangulate_points_hartley
, sorting out matrix operation and linting messages[x] Compare values from triangulate_points_opencv
with already working version.
l2r_mat = stm.construct_rigid_transformation(left_to_right_rotation_matrix, left_to_right_trans_vector)
p_l = np.zeros((3, 4))
p_l[:, :-1] = left_camera_intrinsic_params
p_r = np.zeros((3, 4))
p_r[:, :-1] = right_camera_intrinsic_params
p_l = np.matmul(p_l, np.eye(4))
p_r = np.matmul(p_r, l2r_mat)
triangulated_cv = cv2.triangulatePoints(p_l,
p_r,
left_undistorted.T,
right_undistorted.T)
* [x] check usage of `cv2.triangulatePoints()` www.programcreek.com/python/example/110665/cv2.triangulatePoints ; https://python.hotexamples.com/examples/cv2/-/triangulatePoints/python-triangulatepoints-function-examples.html
* [x] test results `triangulate_points_opencv` and `test_triangulate_points_opencv`
It looks like we only use scikit-surgeryopencvcpp here https://github.com/SciKit-Surgery/scikit-surgerycalibration/blob/master/sksurgerycalibration/video/video_calibration_metrics.py#L174. We should try and remove this dependency. i.e. re-implment triangulate_points_using_hartley locally