如何在保留以前的数据的情况下更改OpenCV Mat尺寸

时间:2017-01-21 04:22:24

标签: android opencv

我正在Android中使用OpenCV编写代码。现在我想改变Mat对象的尺寸而不重新缩放它(这是保留以前的数据)。例如,4x4垫:

0 0 0 0
0 1 1 0
0 1 1 0
0 0 0 0

将其大小更改为6x6

0 0 0 0 0 0
0 1 1 0 0 0
0 1 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

我认为使用复制操作会降低性能,那么最有效的方法是什么?

1 个答案:

答案 0 :(得分:0)

OpenCV Matrices存储为第一列的单个数组,这意味着第一个矩阵的内存实际上如下所示:

[0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0]

虽然第二个矩阵看起来像这样:

[0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ]

粗体零是新值。意味着要将第一个数组转换为第二个数组,您将无法直接使用第一个数组,但仍然必须分别复制每一行。因此,保留原始数组并不能真正提高效率。

但是如果您想最小化内存占用,可以使用realloc来更改已分配内存的大小。我发现这是一个有趣的练习,并创建了以下继承OpenCV Mat的类,并添加了resize函数。

template <class T>
class ResizableMat : public cv::Mat_<T> {
public:
    // This only works when allocating dynamic memory up front
    ResizableMat(int rows, int cols) : cv::Mat_<T>(rows, cols, (T*)malloc(rows * cols * sizeof(T))) {;}
    ResizableMat(int rows, int cols, T initial) : cv::Mat_<T>(rows, cols, (T*)malloc(rows * cols * sizeof(T))) {
        std::fill((T*)this->data, ((T*)this->data) + rows * cols, initial);
    }

    ~ResizableMat() {
        if (this->data)
            free(this->data);
    }

    void resize(const size_t width, const size_t height) {
        assert(width > this->cols && "width must be bigger than original width");
        assert(height > this->rows && "height must be bigger than original height");
        const int newstep = width * sizeof(T);
        const size_t step_diff = newstep - this->step;
        this->data = (uchar *)realloc(this->data, width * height * sizeof(T));  // expand the memory
        for (int y = this->rows-1; y > 0; y--) {
            uchar *src = this->data + this->step * y;
            uchar *dst = this->data + newstep * y;
            memcpy(dst, src, this->step);               // copy the rows
            memset(&dst[this->step], 0, step_diff);     // fill the remainder of this row with 0
        }
        memset(&this->data[this->step], 0, step_diff);
        memset(&this->data[newstep * this->rows], 0, (newstep * height) - (newstep * this->rows));   // fill the remaining rows with 0
        this->step = newstep;
        this->rows = height;
        this->cols = width;
    }
};

这可以这样使用:

ResizableMat<uchar> m(3,3, 1);
cout << "before:" << endl << m << endl;
m.resize(5, 5);
cout << "after:" << endl << m << endl;

其中输出以下内容:

before:
[  1,   1,   1;
   1,   1,   1;
   1,   1,   1]
after:
[  1,   1,   1,   0,   0;
   1,   1,   1,   0,   0;
   1,   1,   1,   0,   0;
   0,   0,   0,   0,   0;
   0,   0,   0,   0,   0]

许多测试表明,当在非常大的矩阵上运行时,以及当新尺寸仅略大于原始尺寸时,它只会稍微快一些。在所有其他情况下,它较慢,因此我不建议使用此方法而不是标准。