1.cv::Mat到 Eigen::MatrixXf,使用深拷贝

// 将 cv::Mat 转换为 Eigen::MatrixXf,支持多通道图像
Eigen::MatrixXf cvMatToEigen(const cv::Mat& cvMat) {
     // 获取通道数
    int channels = cvMat.channels();
    int rows = cvMat.rows;
    int cols = cvMat.cols * channels; // 展开列数以包含所有通道数据

    // 将数据转换为浮点型并按通道展开
    cv::Mat cvMatFloat;
    if (cvMat.type() != CV_32F) {
        cvMat.convertTo(cvMatFloat, CV_32F);
    }
    else {
        cvMatFloat = cvMat.clone();
    }

    // 创建 Eigen::MatrixXf,并进行深拷贝
    Eigen::MatrixXf eigenMat(rows, cols);
    for (int i = 0; i < rows; ++i) {
        const float* rowPtr = cvMatFloat.ptr<float>(i);
        for (int j = 0; j < cols; ++j) {
            eigenMat(i, j) = rowPtr[j];
        }
    }
    return eigenMat;
}

 2.Eigen默认按列优先存储,cv::Mat按照行优先存储,为了保证数据访问的一致性,需要对Eigen二次转化,Eigen列存储转行存储

  // 从列优先的 Eigen::MatrixXf 转换为行优先的 Eigen::Matrix
  Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> toRowMajor(const Eigen::MatrixXf& mat) {
      // 创建行优先的矩阵,并逐元素复制
      Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> rowMajorMat(mat.rows(), mat.cols());
      rowMajorMat = mat;  // 自动完成逐元素复制,确保正确布局
      return rowMajorMat;
  }

3.同理,在Eigen转回cv::Mat时,如果是列存储,转换行存储到cv::Mat。

 //从行优先的 Eigen::Matrix 转换为列优先的 Eigen::MatrixXf
     Eigen::MatrixXf toColumnMajor(const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>&rowMajorMat) {
     // 创建列优先的 Eigen::MatrixXf,并逐元素复制
     Eigen::MatrixXf colMajorMat(rowMajorMat.rows(), rowMajorMat.cols());
     colMajorMat = rowMajorMat;  // 自动完成逐元素复制,确保正确布局
     return colMajorMat;
 }

4.Eigen转cv::Mat,这里需要额外输入转换的行列和通道类型

 // 将 Eigen::MatrixXf 转换为 cv::Mat,支持多通道图像
 cv::Mat eigenToCvMat(const Eigen::MatrixXf& eigenMat, int rows, int cols, int type) {
    // 获取通道数
         int channels = (type == CV_8UC3) ? 3 : (type == CV_8UC4) ? 4 : 1;

     // 确保 Eigen::MatrixXf 的列数和 cv::Mat 的列数(含通道)一致
     if (eigenMat.cols() != cols * channels || eigenMat.rows() != rows) {
         throw std::runtime_error("Matrix dimensions do not match the expected rows, columns, and channels.");
     }

     // 创建 cv::Mat,并根据类型分配内存
     cv::Mat cvMat(rows, cols, type);

     // 将数据转换到相应类型并逐元素拷贝
     if (type == CV_32F || type == CV_32FC3 || type == CV_32FC4) {
         // 直接拷贝浮点数据
         for (int i = 0; i < rows; ++i) {
             float* rowPtr = cvMat.ptr<float>(i);
             for (int j = 0; j < cols * channels; ++j) {
                 rowPtr[j] = eigenMat(i, j);
             }
         }
     }
     else if (type == CV_8UC3 || type == CV_8UC4 || type == CV_8UC1) {
         // 转换为8位无符号整数(假设Eigen中的值在[0, 255]范围内)
         for (int i = 0; i < rows; ++i) {
             uchar* rowPtr = cvMat.ptr<uchar>(i);
             for (int j = 0; j < cols * channels; ++j) {
                 rowPtr[j] = static_cast<uchar>(eigenMat(i, j));
             }
         }
     }
     else {
         throw std::runtime_error("Unsupported cv::Mat type.");
     }

     return cvMat;
 }

使用案例:

 cv::Mat zimg = cv::imread("temp.jpg", cv::IMREAD_UNCHANGED);
float z11 = zimg.data[0];
float z12 = zimg.data[1];
float z13 = zimg.data[2];
float z14 = zimg.data[3];
auto zimg2 = toRowMajor(cvMatToEigen(zimg));
float z121 = zimg2.data()[0];
float z122 = zimg2.data()[1];
float z123 = zimg2.data()[2];
float z124 = zimg2.data()[3];
auto zimg3 = eigenToCvMat(cvMatToEigen(zimg), zimg.rows, zimg.cols, zimg.type());
float z131 = zimg3.data[0];
float z132 = zimg3.data[1];
float z133 = zimg3.data[2];
float z134 = zimg3.data[3];
auto zimg4 = eigenToCvMat(toColumnMajor(toRowMajor(cvMatToEigen(zimg))), zimg.rows, zimg.cols, zimg.type());
float z141 = zimg4.data[0];
float z142 = zimg4.data[1];
float z143 = zimg4.data[2];
float z144 = zimg4.data[3];

如上所有对应索引项的数据和原图片zimg的索引项数据值一致,则转换成功。 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐