Custom type for cv :: Mat in OpenCV
I want to create an array using cv :: Mat with my custom type. Here is my code:
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();
}
However, the results between the Purpose and Display sections do not match:
How do you make these results the same?
source to share
This is because OpenCV doesn't know DataType
your class. For this you need a specialization, for example:
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 all made of floats (and not 2 int a 1 float)
channels = 3,
fmt = (int)'p',
type = CV_MAKETYPE(depth, channels)
};
};
}
void main() {
...
}
But in general, I think it's best to avoid messing with these implementation details and just use a better data structure. Recommendation: use Mat
only for primitive types . In fact, you cannot use it in other OpenCV functions ...
Here are some ways to solve your problem:
- Use a different data structure: eg. a
std::vector<std::vector<CellXY>>
or "expanded"std::vector<CellXY>
-
Make a class
CellXYMatrix
that deals with storageCellXY
: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 access similar to OpenCV masks. -
If the fields
x
andy
inCellXY
are relative to the position of the matrix, why do you need them? You can just haveMat1f
(akaMat_<float>
) for your probabilities and x, y is the position in the matrix.
source to share