I have a couple of problems with OpenCV's own functions for PnP and Rodrigues formula. I think it is related to cv::solvePnPRansac()
cv::Mat w = cv::Mat::zeros(3,1,CV_32FC1);
cv::Mat t = cv::Mat::zeros(3,1,CV_32FC1);
std::vector<float> distortion = {0,0,0,0};
std::vector<cv::Point3f> tmp1 = eig_vec_to_cv3(pts);
std::vector<cv::Point2f> tmp2 = eig_vec_to_cv2(pixels);
cv::solvePnPRansac(tmp1, tmp2, eig_mat_2_cv(K),distortion, w, t,false, 100, 2.0f);
cv::Mat R_ = cv::Mat::zeros(3,3,CV_32FC1);
cv::Rodrigues(w,R_);
std::cout<<"R_"<<std::endl;
std::cout<<R_<<std::endl;
std::cout<<R_.at<float>(0,0)<<std::endl;
For std::cout<<R_<<std::endl
it looks ok, but R_.at<float>(0,0)
gives a trash number, like the memory is not allocated. The same holds for w
and t
.
However, if I make like this:
cv::Mat w_ = cv::Mat(3,1,cv_32FC1);
w.at<float>(0,0) = 0.2;
w.at<float>(0,1) = 0.4;
w.at<float>(0,2) = 0.3;
cv::Rodrigues(w_,R_);
std::cout<<"R_"<<std::endl;
std::cout<<R_<<std::endl;
std::cout<<R_.at<float>(0,0)<<std::endl;
It works just fine.
This is a minimal (non)-working example:
#include <opencv2/calib3d.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
int main()
{
cv::Mat w = cv::Mat(3,1,CV_32FC1);
cv::Mat t = cv::Mat(3,1, CV_32FC1);
std::vector<cv::Point3f> tmp1;
std::vector<cv::Point2f> tmp2;
for (int k = 0; k < 10; ++k)
{
cv::Point3f p1(0.2f+k, 0.3f-k, 7.5f-k);
cv::Point2f p2(3.2f*k, 4.5f/k);
tmp1.push_back(p1);
tmp2.push_back(p2);
}
cv::Mat K = cv::Mat::zeros(3,3,CV_32FC1);
K.at<float>(0,0) = 525.0;
K.at<float>(0,2) = 234.5;
K.at<float>(1,1) = 525;
K.at<float>(1,2) = 312.5;
K.at<float>(2,2) = 1.0f;
std::vector<float> distortion = {0,0,0,0};
cv::solvePnPRansac(tmp1, tmp2, K,distortion, w, t,false, 100, 2.0f);
std::cout<<w<<std::endl;
cv::Mat R = cv::Mat::zeros(3,3,CV_32FC1);
cv::Rodrigues(w,R);
std::cout<<R<<std::endl;
std::cout<<R.at<float>(0,0)<<std::endl;
return 0;
}
Compiled with
g++ main.cpp -I /usr/local/include/opencv4/ -o test -L /usr/local/lib/ -lopencv_calib3d -lopencv_core
The reason is that the function cv::Rodrigues
creates the output matrix of type CV_64FC1
. So the values have to be read as follows:
std::cout<<R.at<double>(0,0)<<std::endl;
Even if we pre-allocate the output matrix to be of any other type ( say CV_32FC1
), it will be reallocated by cv::Rodrigues
to type CV_64FC1
.
In my opinion, the OpenCV documentation lacks clarity about the input and output types of many functions. In cases like these, one must be sure about the output types by printing the return value of Mat::type()
function.
Thanks a lot, I think the OpenCV documentation is questionable in many ways. In particular for python.
@El_Loco.. Yes indeed. Even the primary language (C++) has some ambiguous documentation. I guess it is time to start contributing to the code base and improve its documentation. :)
@El_Loco.. Also, you may consider accepting the answer if it solves your problem.
I am at work now, so cannot try it until tonight.
@sgarizvi Now is a great time to contribute---the OpenCV hackathon starts this weekend! opencv.org/opencv-hackathon-is-coming