Search code examples
c++armadillosvd

Svd Armadillo give some NaN values


I am discovering the Armadillo package to perform a SVD on an image. I first try with OpenCV which is very very slow. So now I am writing an example which perform the SVD using this new library, and I don't get the same result as OpenCV. After some researches, it seems to be linked to Lapack which is no longer used by OpenCV but still by Armadillo. So I am reconstructing the image after the SVD computation to verify if I get back the original image. With OpenCV it is okay, the difference is near to 0, but I don't know why for Armadillo I have NaN number as singular values so I can't get back an image.

Thank you in advance for any help/advice you can bring.

My C++ code:

int main()
{
    // Load the image
    cv::Mat img = cv::imread("path/to/the/image.png", 0);
    img.convertTo(img, CV_32FC1);

    // Convert cv::Mat to arma::fmat
    arma::fmat arma_img(reinterpret_cast<float*>(img.data), img.cols, img.rows);

    // Check if the image back from armadillo is okay
    cv::Mat opencv_img(arma_img.n_cols, arma_img.n_rows, CV_32FC1, arma_img.memptr());

    // ------ Perform SVD with OpenCV (2.5s)
    cv::SVD svvd;
    cv::Mat w1, U1, V1t;
    svvd.compute(opencv_img, w1, U1, V1t);

    cv::Mat W1 = cv::Mat::zeros(w1.rows, w1.rows, CV_32FC1);
    for (int i = 0; i<w1.rows; i++)
    {
        W1.at<float>(i, i) = w1.at<float>(i);
    }
    cv::Mat opencv_img_result = U1 * W1 * V1t;

    // ------ Perform SVD with Armadillo (0.05s)
    arma::fmat U2, V2;
    arma::fvec w2;
    arma::svd(U2, w2, V2, arma_img);

    arma::fmat W2 = arma::zeros<arma::fmat>(arma_img.n_rows, arma_img.n_cols);
    for (int i = 0; i < arma_img.n_cols; i++)
    {
        *(W2.memptr() + i * (1 + arma_img.n_rows)) = *(w2.memptr() + i);
    }
    arma::fmat arma_img_result = U2 * W2* V2.t();

    return 0;
}

Solution

  • The problem is because of the mode of computation:

    The method argument is optional; method is either "dc" or "std"

    "dc" indicates divide-and-conquer method (default setting)
    "std" indicates standard method
    the divide-and-conquer method provides slightly different results than the standard method, but is considerably faster for large
    

    matrices

    The dc mode is not working properly, but the std one is. Maybe something is wrong on the Lapack library abotu the dc mode.