【问题标题】:How to perform LU-decomposition with OpenCV?如何使用 OpenCV 执行 LU 分解?
【发布时间】:2013-07-11 15:40:40
【问题描述】:

cvInvert() 方法采用标志 CV_LU,它执行 LU 因式分解以反转输入矩阵。但是,有没有办法获得在此计算过程中形成的 L 和 U 矩阵? 为 LU 分解写一个新函数似乎毫无意义,因为 OpenCV 已经为它优化了代码。

【问题讨论】:

    标签: image-processing opencv eigen


    【解决方案1】:

    不幸的是,OpenCV 似乎没有为您提供访问 L 和 U 矩阵的方法。 Here 是函数的实现方式。而且,出于性能原因,LU 分解似乎是就地完成的。所以,你可能不得不自己做。

    编辑:看起来,在查看了 Matlab 和 Eigen 如何进行 LU 分解之后,您实际上可以在 cvInvert 调用之后检索它们。 L矩阵是结果的严格下三角矩阵加上Identity矩阵,U矩阵是上三角矩阵。

    编辑: Eigen 实际上与 OpenCV 集成得相当好。而且,他们似乎已经实现了一个 LU 分解类here。如果您自己构建 Eigen,它已经是 OpenCV 的依赖项,您应该可以使用它(它完全在头文件中实现,因此非常易于使用)。还有一个OpenCV头实现了Eigen矩阵和OpenCV矩阵之间的转换@#include <opencv2/core/eigen.hpp>

    但是,至少在我的 SVN 版本中,此标头无法正常工作,所以我自己制作了:

    #ifndef __OPENCV_CORE_EIGEN_HPP__
    #define __OPENCV_CORE_EIGEN_HPP__
    
    #ifdef __cplusplus
    
    #include "opencv/cxcore.h"
    #include <eigen3/Eigen/Dense>
    
    namespace cv
    {
    
    template<typename _Tp, int _rows, int _cols, int _options, int _maxRows, int _maxCols>
    void eigen2cv( const Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& src, Mat& dst )
    {
        if( !(src.Flags & Eigen::RowMajorBit) )
        {
            Mat _src(src.cols(), src.rows(), DataType<_Tp>::type,
                  (void*)src.data(), src.stride()*sizeof(_Tp));
            transpose(_src, dst);
        }
        else
        {
            Mat _src(src.rows(), src.cols(), DataType<_Tp>::type,
                     (void*)src.data(), src.stride()*sizeof(_Tp));
            _src.copyTo(dst);
        }
    }
    
    template<typename _Tp, int _rows, int _cols, int _options, int _maxRows, int _maxCols>
    void cv2eigen( const Mat& src,
                   Eigen::Matrix<_Tp, _rows, _cols, _options, _maxRows, _maxCols>& dst )
    {
        CV_DbgAssert(src.rows == _rows && src.cols == _cols);
        if( !(dst.Flags & Eigen::RowMajorBit) )
        {
            Mat _dst(src.cols, src.rows, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            if( src.type() == _dst.type() )
                transpose(src, _dst);
            else if( src.cols == src.rows )
            {
                src.convertTo(_dst, _dst.type());
                transpose(_dst, _dst);
            }
            else
                Mat(src.t()).convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
        else
        {
            Mat _dst(src.rows, src.cols, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            src.convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
    }
    
    template<typename _Tp>
    void cv2eigen( const Mat& src,
                   Eigen::Matrix<_Tp, Eigen::Dynamic, Eigen::Dynamic>& dst )
    {
        dst.resize(src.rows, src.cols);
        if( !(dst.Flags & Eigen::RowMajorBit) )
        {
            Mat _dst(src.cols, src.rows, DataType<_Tp>::type,
                 dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            if( src.type() == _dst.type() )
                transpose(src, _dst);
            else if( src.cols == src.rows )
            {
                src.convertTo(_dst, _dst.type());
                transpose(_dst, _dst);
            }
            else
                Mat(src.t()).convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
        else
        {
            Mat _dst(src.rows, src.cols, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            src.convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
    }
    
    
    template<typename _Tp>
    void cv2eigen( const Mat& src,
                   Eigen::Matrix<_Tp, Eigen::Dynamic, 1>& dst )
    {
        CV_Assert(src.cols == 1);
        dst.resize(src.rows);
    
        if( !(dst.Flags & Eigen::RowMajorBit) )
        {
            Mat _dst(src.cols, src.rows, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            if( src.type() == _dst.type() )
                transpose(src, _dst);
            else
                Mat(src.t()).convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
        else
        {
            Mat _dst(src.rows, src.cols, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            src.convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
    }
    
    
    template<typename _Tp>
    void cv2eigen( const Mat& src,
                   Eigen::Matrix<_Tp, 1, Eigen::Dynamic>& dst )
    {
        CV_Assert(src.rows == 1);
        dst.resize(src.cols);
        if( !(dst.Flags & Eigen::RowMajorBit) )
        {
            Mat _dst(src.cols, src.rows, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            if( src.type() == _dst.type() )
                transpose(src, _dst);
            else
                Mat(src.t()).convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
        else
        {
            Mat _dst(src.rows, src.cols, DataType<_Tp>::type,
                     dst.data(), (size_t)(dst.stride()*sizeof(_Tp)));
            src.convertTo(_dst, _dst.type());
            CV_DbgAssert(_dst.data == (uchar*)dst.data());
        }
    }
    
    }
    
    #endif
    
    #endif
    

    希望对你有帮助!

    【讨论】:

    • 谢谢。我正在考虑使用 Boost 什么的,这个 Eigen 似乎不那么麻烦。
    • 没问题!很高兴我能帮上忙!
    • 您对 MATLAB 和 Eigen 中的 LU 分解的解释有点误导,因为 L 本身不是严格的下三角矩阵。它是 A 的严格下半部分加上单位矩阵。
    • 感谢指正!更正并更新了大部分已失效的链接。
    【解决方案2】:

    可以使用OpenCV提供的函数Cholesky()(使用2.4.6),见modules\stitching\src\autocalib.cpp的源码。但它需要一些缩放才能获得与 Matlab 相当的结果:

    Mat chol = mat.clone();
    if (Cholesky(chol.ptr<float>(), chol.step, chol.cols, 0, 0, 0))
    {
        Mat diagElem = chol.diag();
        for (int e = 0; e < diagElem.rows; ++e)
        {
            float elem = diagElem.at<float>(e);
            chol.row(e) *= elem;
            chol.at<float>(e,e) = 1.0f / elem;
        }
    }
    

    【讨论】:

    • 你知道 OpenCV 的 Cholesky 参数的含义吗?另外,OpenCV Cholesky 函数相对于 Cholesky 分解 A=LL*(其中 * 表示共轭转置)的实际输出是多少?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-25
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多