OpenCV中用于cv::Mat的自定义类型

3

我想使用自定义类型创建一个cv::Mat数组。以下是我的代码:

typedef struct{
  int x;
  int y;
  float prob;
}CellXY;

void main(){

  cv::Mat_<CellXY> map(10, 10);

  std::cout << "Width = " << map.cols << ", Height = " << map.rows << std::endl;
  std::cout << "### Assignment ###" << std::endl;
  for (int j=0; j<map.rows; j++){
    for (int i=0; i<map.cols; i++){
      map.at<CellXY>(j, i).x = i;
      map.at<CellXY>(j, i).y = j;
      map.at<CellXY>(j, i).prob = (float)(i + j * map.cols);

      std::cout << map.at<CellXY>(j, i).prob 
        << " (" << map.at<CellXY>(j, i).x
        << "," << map.at<CellXY>(j, i).y
        << ")\t";
    }
    std::cout << std::endl;
  }

  std::cout << "### Display ###" << std::endl;
  for (int j=0; j<map.rows; j++){
    for (int i=0; i<map.cols; i++){
      std::cout << map.at<CellXY>(j, i).prob 
        << " (" << map.at<CellXY>(j, i).x
        << "," << map.at<CellXY>(j, i).y
        << ")\t";
    }
    std::cout << std::endl; 
  }
  map.release();
}

然而,“任务”和“展示”部分之间的结果并不相同:

我应该如何使这些结果一致?
1个回答

1
这是因为OpenCV不知道您类的DataType。您需要为其进行专门化处理,例如:
typedef struct {
    int x;
    int y;
    float prob;
}CellXY;


// Add this!!!!!!
namespace cv {
template<> class DataType<CellXY>
{
public:
    typedef CellXY      value_type;
    typedef value_type  work_type;
    typedef value_type  channel_type;
    typedef value_type  vec_type;
    enum { generic_type = 0,
        depth        = CV_32F, // Might cause problems... I'm saying it's all made of floats (and not 2 int a 1 float)
        channels     = 3,
        fmt          = (int)'p',
        type         = CV_MAKETYPE(depth, channels)
    };
};
}

void main() {
    ...
}

但总体而言,我认为最好避免与这些实现细节打交道,而只使用更好的数据结构。建议是:仅针对原始类型使用Mat。实际上,在其他OpenCV函数中也无法使用它...

以下是解决问题的几种方法:

  1. Use another data structure: e.g. a std::vector<std::vector<CellXY>> or an "unrolled" std::vector<CellXY>
  2. Make a class CellXYMatrix which deals with storing the CellXY:

    class CellXYMatrix
    {
         std::vector<CellXY> _mat; // your matrix of CellXY
         int _r; // rows
         int _c; // cols
    
    public:
         CellXYMatrix(int rows, int cols) : _r(rows), _c(cols), _mat(rows * cols) {};
    
         void set(int row, int col, const CellXY& cell) {
            _mat[row * _c + col] = cell;
         }
         CellXY& get(int row, int col) {
            return _mat[row * _c + col];
         }  
    }
    

    You can eventually overload operator() to make the access similar to OpenCV Mats.

  3. If the x and y fields in CellXY refer to the matrix position, why do you need them? You can simply have a Mat1f (aka Mat_<float>) for your probabilities, and x,y are the position in the matrix.


非常感谢您的帮助。我尝试了您提供的解决方案,添加了template<> class DataType<CellXY>,但是我遇到了以下错误:error: specialization of ‘template<class _Tp> class cv::DataType’ in different namespace [-fpermissive] template<> class DataType<CellXY>然而,我同意对于像cv::Point3f或cv::Vec3f这样的基本类型,使用cv::Mat始终更好。另外,我尝试修改“CellXY”结构中的数据类型,如下所示,而不需要添加template DataType类,它可以完美地工作。typedef struct{ float x; float y; float prob; }CellXY; - puwanan
  1. 你需要将专业化放入 namespace cv 中...请参见编辑。
  2. 哦,不知道那个...但是你可以直接使用 cv::Vec3f ;)
- Miki
我想使用cv::Mat而不是std::vector的原因是我想动态改变2D数组的大小。在OpenCV中,可以通过cv::hconcat(B, A, result)或cv::vconcat(B, A, result)轻松实现。因此,新数组可以轻松地添加到原始数组的顶部、底部、左侧或右侧位置。 - puwanan
将其添加到CellXYMatrix类将是微不足道的。但是,只要您100%确定OpenCV函数与您的自定义数据类型配合良好,我想您就是安全的;) - Miki
顺便说一下,第一个问题很棒 ;) - Miki

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