简体   繁体   中英

OpenCV Matrix of user-defined type

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.

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));
}

If you don't want to use the OpenCV functionality, then Mat is not the right type for you. Use std::vector<std::vector<Type> > instead. You can give the size during initialization:

std::vector<std::vector<Type> > matrix(42, std::vector<Type>(23));

Then you can access with [] -operator. No need to screw around with obscure cv::Mat s here.

If you would really need to go for an OpenCV-Matrix, you are right in that you have to define the DataType. It is basically a bunch of traits. You can read about C++ Traits on the web.

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!)

You can create a CV mat that users your own allocated memory by specifying the address to the constructor. If you also want the width and height to be correct you will need to find an openCV pixel type that is the same number of bytes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM