Search code examples
c++opencvcomplex-numbersmatrix-inverse

How to do inverse on complex matrix in OpenCV?


I have trouble in doing inverse of a complex matrix. As far as I know, complex matrix is simply a two-channel matrix (CV_32FC2 / CV_64FC2).

Let's say I have a matrix C:

Mat C(2, 2, CV_64FC2);

C.at<Vec2d>(0,0)[0] = 1;
C.at<Vec2d>(0,0)[1] = 1;
C.at<Vec2d>(0,1)[0] = 3;
C.at<Vec2d>(0,1)[1] = 4;
C.at<Vec2d>(1,0)[0] = 2;
C.at<Vec2d>(1,0)[1] = -1;
C.at<Vec2d>(1,1)[0] = 5;
C.at<Vec2d>(1,1)[1] = 2;

Mat InverseMat;
invert(C, InverseMat, DECOMP_SVD);

After I perform the invert function, I keep getting this error:

OpenCV Error: Assertion failed (type == CV_32F || type == CV_64F) in invert

The invert function works well with a grayscale loaded image (1 channel), but I have hard time to do inverse on complex matrix which contains real and imaginary part.

Can someone please tell me how to solve the inverse problem of a complex matrix? Preferably using DECOMP_SVD method, as I can't get desired result using DECOMP_LU or DECOMP_CHOLESKY method when I tried with a single channel image, probably because of the matter of singular matrix. Thanks.


Solution

  • OpenCV does not support inversion of complex matrices. You have to manipulate the complex matrix in a way to form a real matrix containing the real and imaginary parts of the complex matrix. This page explains the process.

    Here is the code to perform inverse of a complex matrix using the above mentioned process:

    //Perform inverse of complex matrix.
    cv::Mat invComplex(const cv::Mat& m)
    {
        //Create matrix with twice the dimensions of original
        cv::Mat twiceM(m.rows * 2, m.cols * 2, CV_MAKE_TYPE(m.type(), 1));
    
        //Separate real & imaginary parts
        std::vector<cv::Mat> components;
        cv::split(m, components);
    
        cv::Mat real = components[0], imag = components[1];
    
        //Copy values in quadrants of large matrix
        real.copyTo(twiceM({ 0, 0, m.cols, m.rows })); //top-left
        real.copyTo(twiceM({ m.cols, m.rows, m.cols, m.rows })); //bottom-right
        imag.copyTo(twiceM({ m.cols, 0, m.cols, m.rows })); //top-right
        cv::Mat(-imag).copyTo(twiceM({ 0, m.rows, m.cols, m.rows })); //bottom-left
    
        //Invert the large matrix
        cv::Mat twiceInverse = twiceM.inv();
    
        cv::Mat inverse(m.cols, m.rows, m.type());
    
        //Copy back real & imaginary parts
        twiceInverse({ 0, 0, inverse.cols, inverse.rows }).copyTo(real);
        twiceInverse({ inverse.cols, 0, inverse.cols, inverse.rows }).copyTo(imag);
    
        //Merge real & imaginary parts into complex inverse matrix
        cv::merge(components, inverse);
        return inverse;
    }