cv::Mat 转换为 Eigen-Matrix 并返回

5
我有几个特征向量存储在一个 cv::Mat 中,其中每一行都是一个特征向量(几行像这个样子:[ x1 y1 x2 y2 x3 y3.... ])。我必须对每个特征向量应用 SVD,并为此使用 Eigen 库。但是,在应用 SVD 之前,特征矩阵必须转换为 Eigen::Matrix 格式。
稍后,我必须将 SVD 结果转换回 cv::Mat
请问是否有一个好的方法来实现这一点?我需要它在 cv::Mat 表单中,因为我必须将其输入到 OpenCV 中的神经网络中,而只有 cv::Mat 输入矩阵被允许。
谢谢!

1
可能是 OpenCV CV::Mat 和 Eigen::Matrix 的重复问题。无需复制数据,可以使用 Eigen::Map。请查看此处的答案: https://dev59.com/lmUq5IYBdhLWcg3wHcv5/21706778#21706778。 - Ela782
3个回答

6

3

尝试使用以下代码将Eigen转换为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转换为eigen:

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。我不明白为什么将格式转换到这样的库和Qt没有通过API公开。


谢谢您的建议!您能告诉我这里的“模板”是什么吗?我还不是很熟练...另外,我该如何将cv::Mat转换为Eigen::Matrix...感谢您的帮助!@ypnos - learner
请解释一下 "typename _Tp" 和 DataType<_Tp> 是什么,更详细地解释一下...这非常重要... - learner
你需要自己学习模板。但使用这段代码相当容易,不涉及模板。例如:cv :: Mat_ <float> src; Eigen :: MatrixXf dest(src.rows,src.cols); cv2eigen(src,dest); - ypnos
我会尝试一下!请告诉我一下"typename _Tp"和DataType<_Tp>是什么,我不太理解...谢谢... @ypnos - learner
刚刚读了你最喜欢的关于C++模板的书。这是非常基础的C++概念!关于数据类型,请参见http://docs.opencv.org/modules/core/doc/basic_structures.html - ypnos
显示剩余2条评论

1
请查看从Eigen到OpenCV的数据映射文章。它描述了如何以较少的开销映射数据。在最简单的情况下,根本不需要复制。它还涉及到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));

1
你在博客中提到的新头文件与OpenCV 2.4.9不兼容。我刚刚包含了头文件Eigen2CV.h,但g++报了一堆奇怪的错误。 - mkuse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接