-3

I have been struggling to get right calibration done using openCV with c++. Below I have included my code snippet for its' calculation, would greatly appreciate if you can point out what I am doing wrong, or how I can improve it.

// Initialize and reset calibration params
        void InitCaliberation()
        {
            //numBoards = 0;
            numCornersHor = horizontalCorners;
            numCornersVer = verticalCorners;
            numSquares = horizontalCorners * verticalCorners;

            board_sz = Size(horizontalCorners, verticalCorners);
            frame_sz = Size(frameWidth, frameHeight);
            sqSizeInmm = sqSizemm; //25 mm
            object_points.clear();
            image_points.clear();
            corners.clear();

            finishedCalberation = false;
        }

//Process frames
bool CheckCheckerboardFrame(Mat image, bool debug=false)
        {
            vector<Point3f> obj;
            Mat grayImage;
            cvtColor(image, grayImage, COLOR_BGR2GRAY);

            for (int j = 0; j < numSquares; j++)
                obj.push_back(Point3f(sqSizeInmm * j / numCornersHor, sqSizeInmm * j%numCornersHor, 0.0f));
            bool found = findChessboardCorners(grayImage, board_sz, corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FILTER_QUADS);

            if (found)
            {
                //sub-pixel accurate location
                cornerSubPix(grayImage, corners, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 30, 0.1));
                if(debug)
                    drawChessboardCorners(image, board_sz, corners, found);
                else {
                    image_points.push_back(corners);
                    object_points.push_back(obj);
                }
            }

            return found;
        }

// Calculate params
void FinishCaliberation()
        {
            calibrateCamera(object_points, image_points, frame_sz, intrinsic, distCoeffs, R, T);
            finishedCalberation = true;
            cout <<"\nIntrinsic: "<< intrinsic.size<<endl;

            for (int i = 0; i < intrinsic.rows; i++)
            {
                for (int j = 0; j < intrinsic.cols; j++)
                    cout << intrinsic.at<float>(i, j) << " ";
                cout << endl;
            }

            cout << "\nDist coeff: " << distCoeffs.size << endl;
            for (int i = 0; i < distCoeffs.rows; i++)
            {
                for (int j = 0; j < distCoeffs.cols; j++)
                    cout << distCoeffs.at<float>(i, j) << " ";
                cout << endl;
            }
            //cout<<
        }

Below is the output that I am getting with openCV.

output

And this is the expected output. I have calculated this calibration from matlab.

expected_output

I am not trying to match the results! but want to understand why Fy and Cx values are 0, and why intrinsic.at(0,1) is non-zero? and what am I doing wrong here?

here is the minimal code of the calibration process: http://collabedit.com/3vay2 if anyone's interested.

E_net4
  • 27,810
  • 13
  • 101
  • 139
enigma
  • 113
  • 8
  • You have a working matlab script and C++ code with logical errors. You can run both codes in a debugger and compare the values. – Thomas Sablik Apr 09 '20 at 10:50
  • @ThomasSablik What are the logical errors here? – enigma Apr 09 '20 at 11:11
  • The results are not correct. That's caused by logical errors. Without [mcve] and the Matlab script it's difficult or impossible to find them. You have the whole code and the Matlab script. Debug both codes concurrently and find the differences. – Thomas Sablik Apr 09 '20 at 11:15
  • I understand what you mean. But I am not trying to match the results... If you look at the output values of c++, fy and cx value are 0! and why am i getting intrinsic.at(0,1) as non zero? Where is that value coming from. – enigma Apr 09 '20 at 11:28
  • 1
    I don't know, but your debugger will tell you. This is a C++ question. I'm looking at the code. You are getting `intrinsic.at(0,1)` as non zero because you wrote non zero into it. Find the place where you write values into this variable. – Thomas Sablik Apr 09 '20 at 11:31
  • @ThomasSablik If you are familiar with the process, maybe you can point out what's going wrong... I have tried debugging the code... but like i mentioned above, it doesn't make sense. I have tried to switch the corner values and debug the corner points (which seems to be ok). – enigma Apr 09 '20 at 11:34
  • As I already said I think it's nearly impossible to help without [mcve] with input data. – Thomas Sablik Apr 09 '20 at 11:35
  • @ThomasSablik the intrinsic matrix is populated by calibrateCamera method which is defined in openCV. – enigma Apr 09 '20 at 11:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/211281/discussion-between-shubhamrock828-and-thomas-sablik). – enigma Apr 09 '20 at 11:38
  • 1
    try type `double` instead of `float`. OpenCV uses double precision for those small matrices and lens distortion values, but you are interpreting the memory regions as being floats. – Micka Apr 09 '20 at 13:31
  • 1
    @Micka You are a life savior. Many thanks :) – enigma Apr 09 '20 at 13:47

1 Answers1

1

Finally figured out the issue. Thanks to - @Micka

so I was getting garbage values because of data type mismatch. Opencv expects double precision, while I was using float type for Mat params. This was also the reason for unexpected values like non-zero value at intrinsic.at(0,1).

Which actually made me doubtful of my implementation. But converting it to double fixes that as well. Although I am not sure how the double value of 0 is being casted to 6.05179 in float. May have to do with hidden implementation of OpenCV.

enigma
  • 113
  • 8
  • 1
    it is not a typecast. Let's have a similar example with 16bit vs. 8bit unsigned int. If you have 3 16bit values, let's say [2,255,1] which is this in bits: 0000000000000010 0000000011111111 0000000000000001 and you interpret the memory as being 8 bit integers, you will get 6 values: 00000000 00000010 00000000 11111111 00000000 00000001 whih is [0,2,0,255,0,1], so you would read your expected 3 values as being [0,2,0] (example is simplified and doesnt handle little endian, big endian, etc. which can introduce additional stuff) – Micka Apr 09 '20 at 14:50
  • 1
    Right. That makes sense. Thank you for detailed explanation. – enigma Apr 09 '20 at 16:11