【问题标题】:cv::Mat conversion to Eigen-Matrix and backcv::Mat 转换为特征矩阵并返回
【发布时间】:2013-05-08 22:13:12
【问题描述】:

我有几个特征向量存储在cv::Mat 中,其中每一行都是一个特征向量(这里有几行:[ x1 y1 x2 y2 x3 y3.... ])。我必须对每个特征向量应用 SVD,为此我使用 Eigen 库。但是,在应用 SVD 之前,必须将特征矩阵转换为 Eigen::Matrix 形式。

稍后,我必须将 SVD 结果转换回cv::Mat

任何人都可以提出一个很好的方法来做到这一点吗?我需要 cv::Mat 形式的原因是因为我必须将它输入到 OpenCV 中的神经网络,并且只允许 cv::Mat 输入矩阵。

谢谢!!!

【问题讨论】:

标签: c++ opencv eigen eigen3


【解决方案1】:

来自http://forum.kde.org/viewtopic.php?f=74&t=97516的例子:

#include <opencv2/core/eigen.hpp>
cv::Mat_<float> a = Mat_<float>::ones(2,2);
Eigen::Matrix<float,Dynamic,Dynamic> b;
cv2eigen(a,b);

另外,OpenCV CV::Mat and Eigen::Matrix 有一个使用 Eigen::Map 的解决方案。

【讨论】:

    【解决方案2】:

    试试这个代码的 eigen to 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, cv::Mat& dst)
    {
        if (!(src.Flags & Eigen::RowMajorBit))
        {
            cv::Mat _src(src.cols(), src.rows(), cv::DataType<_Tp>::type,
                (void*)src.data(), src.stride() * sizeof(_Tp));
            cv::transpose(_src, dst);
        }
        else
        {
            cv::Mat _src(src.rows(), src.cols(), cv::DataType<_Tp>::type,
                (void*)src.data(), src.stride() * sizeof(_Tp));
            _src.copyTo(dst);
        }
    }
    

    如您所见,这执行了复制。使用这么小的矩阵,您不应该关心,但您可以更改代码。要获取第一列,请使用cv::Mat::column()

    尝试使用以下方法之一将 cv 转换为特征:

    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());
        }
    }
    

    来源: 此代码取自 OpenCV 本身,它们在内部使用它,因为 OpenCV 可以在内部使用 libeigen 执行某些任务。我不明白为什么不通过 API 公开对此类库和 Qt 的格式转换。

    【讨论】:

    • 感谢您的建议!你能告诉我这里的“模板”是什么吗?我还没有达到高级水平...以及如何将 cv::Mat 转换为 Eigen::Matrix ....谢谢您的输入!!! @ypnos
    • 这个“typename _Tp”和DataType是什么<_tp>请多解释一下......非常重要......
    • 您需要自己学习模板。但是使用此代码相当容易,并且不涉及模板。例如:cv::Mat_ src;特征::MatrixXf dest(src.rows, src.cols); cv2eigen(src, dest);
    • 我试试这个!还请告诉我这个“typename _Tp”和 DataType<_tp> 是什么……我不明白……谢谢……@ypnos
    • 阅读您最喜欢的有关 C++ 模板的书籍。这是非常基本的 C++ 概念!关于 DataType 见docs.opencv.org/modules/core/doc/basic_structures.html
    【解决方案3】:

    看看Mapping data from Eigen to OpenCV and back 文章。它描述了如何以更少的开销映射数据。在最简单的情况下,根本没有副本。它也处理 Eigen 表达式:

    // Unsharp mask
    Eigen::ArrayXXd img, blur;    
    eigen2cv(img) = cv::imread("lena.jpg");
    cv::GaussianBlur(eigen2cv(img), eigen2cv(blur));
    
    cv::imshow("sharpened", eigen2cv(1.5 * img - 0.5 * blur));
    

    【讨论】:

    • 您在博客中讨论的新头文件不适用于 OpenCV 2.4.9。我刚刚包含了头文件 Eigen2CV.h 和 g++ 抛出了一堆奇怪的错误。
    猜你喜欢
    • 2012-07-17
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 2013-06-12
    • 1970-01-01
    相关资源
    最近更新 更多