Android 如何在保留以前数据的情况下更改OpenCV Mat尺寸
我正在用Android中的OpenCV编写代码。现在,我想更改Mat对象的尺寸,而无需重新缩放它(即保留以前的数据)。例如,4x4垫:Android 如何在保留以前数据的情况下更改OpenCV Mat尺寸,android,opencv,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 我认为使用复制操作会降低性能,那么最有效的方法是什么呢?OpenCV矩阵存储为列首单个数组,这意味着第一个矩阵的内存实际上如下所示
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
我认为使用复制操作会降低性能,那么最有效的方法是什么呢?OpenCV矩阵存储为列首单个数组,这意味着第一个矩阵的内存实际上如下所示:
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]
[0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0]
第二个矩阵如下所示:
[0 0 0 0
0 00 1 0
0 1 0
0 0 00 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;
}
};
大量测试表明,当在非常大的矩阵上操作时,以及当新的尺寸仅略大于原始尺寸时,它的速度仅略快。在所有其他情况下,它都比较慢,因此我不建议在标准情况下使用此方法。OpenCV矩阵存储为列首单个数组,这意味着第一个矩阵的内存实际上如下所示:
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]
[0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0]
第二个矩阵如下所示:
[0 0 0 0
0 00 1 0
0 1 0
0 0 00 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;
}
};
大量测试表明,当在非常大的矩阵上操作时,以及当新的尺寸仅略大于原始尺寸时,它的速度仅略快。在所有其他情况下,它都比较慢,因此我不建议使用此方法而不是标准方法。我只会使用
copyMakeBorder
在右侧和底部添加一个2的边框。如果这太慢了,您最好重新考虑所有代码,因为这不会成为应用程序的瓶颈。我将使用copyMakeBorder
在右侧和底部添加一个2的边框。如果这太慢了,您最好重新考虑所有代码,因为这不会成为应用程序的瓶颈。