Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenCV Matrix of user-defined type

Tags:

c++

opencv

Is there a way to have a matrix of user-defined type in OpenCV 2.x? Something like :

cv::Mat_<KalmanRGBPixel> backgroundModel;

I know cv::Mat<> is meant for image and mathematic, but I want to hold data in a matrix form. I don't plan to use inverse, transpose, multiplication, etc., it's only to store data. I want it to be in matrix form because the pixel_ij of each frame of a video will be linked to backgroundModel_ij.

I know there is a DataType<_Tp> class in core.hpp that needs to be defined for my type but I'm not sure how to do it.

EDIT : KalmanRGBPixel is only a wrapper for cv::KalmanFilter class. As for now, it's the only member.

... some functions ...
private:
    cv::KalmanFilter kalman;

Thanks for your help.

like image 455
Nil Avatar asked Aug 25 '11 18:08

Nil


People also ask

What is a matrix in OpenCV?

In OpenCV the main matrix class is called Mat and is contained in the OpenCV-namespace cv. This matrix is not templated but nevertheless can contain different data types. These are indicated by a certain type-number.

What is CV mat in OpenCV?

OpenCV matrices cv::Mat and cv::Mat_ In OpenCV the main matrix class is called Mat and is contained in the OpenCV-namespace cv. This matrix is not templated but nevertheless can contain different data types. These are indicated by a certain type-number.

What is the difference between column and scalar in OpenCV matrix?

columns is the columns of the matrix. type is the data type used to store the elements in the matrix. Scalar &s specifies the value to be stored in the matrix. Mat is a class in OpenCV consisting of two data parts namely matrix header and a pointer to the matrix.

What is the use of create function in OpenCV?

Another OpenCV idiom in this function, a call of Mat::create for the destination array, that allocates the destination array unless it already has the proper size and type. And while the newly allocated arrays are always continuous, you still need to check the destination array because Mat::create does not always allocate a new matrix.


2 Answers

I have a more long winded answer for anybody wanting to create a matrix of custom objects, of whatever size.

You will need to specialize the DataType template but instead of having 1 channel, you make the channels the same size of your custom object. You may also need to override a few functions to get expected functionality, but back to that later.

First, here is an example of my custom type template specialization:

typedef HOGFilter::Sample Sample;
namespace cv {
    template<> class DataType<Sample>
    {
    public:
        typedef HOGFilter::Sample       value_type;
        typedef HOGFilter::Sample       channel_type;
        typedef HOGFilter::Sample       work_type;
        typedef HOGFilter::Sample       vec_type;

        enum {
            depth = CV_8U,
            channels = sizeof(HOGFilter::Sample),
            type = CV_MAKETYPE(depth, channels),
        };
    };
}

Second.. you may want to override some functions to get expected functionality:

// Special version of Mat, a matrix of Samples. Using the power of opencvs
// matrix manipulation and multi-threading capabilities 
class SampleMat : public cv::Mat_<Sample>
{
    typedef cv::Mat_<Sample> super;
public:
    SampleMat(int width = 0, int height = 0);
    SampleMat &operator=(const SampleMat &mat);

    const Sample& at(int x, int y = 0);
};

The typedef of super isnt required but helps with readability in the cpp. Notice I have overriden the constructor with width/hight parameters. This is because we have to instantiate the mat this way if we want a 2D matrix.

SampleMat::SampleMat(int width, int height)
{
    int count = width * height;

    for (int i = 0; i < count; ++i)
    {
        HOGFilter::Sample sample;
        this->push_back(sample);
    }

    *dynamic_cast<Mat_*>(this) = super::reshape(channels(), height);
}

The at<_T>() override is just for cleaner code:

const Sample & SampleMat::at(int x, int y)
{
    if (y == 0)
        return super::at<Sample>(x);

    return super::at<Sample>(cv::Point(x, y));
}
like image 57
Sam Hartlebury Avatar answered Sep 17 '22 05:09

Sam Hartlebury


In the OpenCV documentation it is explained how to add custom types to OpenCV matrices. You need to define the corresponding cv::DataType.

https://docs.opencv.org/master/d0/d3a/classcv_1_1DataType.html

The DataType class is basically used to provide a description of such primitive data types without adding any fields or methods to the corresponding classes (and it is actually impossible to add anything to primitive C/C++ data types). This technique is known in C++ as class traits. It is not DataType itself that is used but its specialized versions […] The main purpose of this class is to convert compilation-time type information to an OpenCV-compatible data type identifier […]

(Yes, finally I answer the question itself in this thread!)

like image 33
ypnos Avatar answered Sep 19 '22 05:09

ypnos