El_Loco
El_Loco

Reputation: 1866

OpenCV and reading data from OutputArrays or (Mat)

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

Upvotes: 1

Views: 534

Answers (1)

sgarizvi
sgarizvi

Reputation: 16796

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.

Upvotes: 1

Related Questions