这是时间复杂度和内存使用之间的选择。
看一下源代码(OpenCV 2.4.10)。为了简化,我删除了一些行:
void cv::transpose( InputArray _src, OutputArray _dst )
{
Mat src = _src.getMat();
size_t esz = src.elemSize();
_dst.create(src.cols, src.rows, src.type());
Mat dst = _dst.getMat();
if( dst.data == src.data )
{
TransposeInplaceFunc func = transposeInplaceTab[esz];
CV_Assert( func != 0 );
func( dst.data, dst.step, dst.rows );
}
else
{
TransposeFunc func = transposeTab[esz];
CV_Assert( func != 0 );
func( src.data, src.step, dst.data, dst.step, src.size() );
}
}
显然,
_dst.create(src.cols, src.rows, src.type());
是关键。函数
getMat()
仅返回
Mat
头文件。
OpenCV API参考文档:
C++: void Mat::create(int rows, int cols, int type);
这是最重要的Mat方法之一。大多数新式OpenCV函数和生成数组的方法都会为每个输出数组调用此方法。该方法使用以下算法:
1. 如果当前数组形状和类型与新数组匹配,则立即返回。否则,通过调用Mat::release()取消引用以前的数据。
2. 初始化新标头。
3. 通过使用malloc()分配total()*elemSize()字节的新数据。
4. 分配与数据相关联的新引用计数器并将其设置为1。
如您所见,如果
_src
是一个方阵(rows == cols),它什么也不做(立即返回)。然后使用原地转置算法。如果它是非方阵,则首先通过使用
malloc()
来分配
total()*elemSize()
内存。
与原地算法相比,似乎浪费了很多。但根据维基百科:
已知算法的最坏情况下的计算成本是O(MN log MN),时间复杂度为线性对数级别。
减少内存使用量是否值得以更高的时间复杂度为代价?在大多数情况下,我们更喜欢减少执行时间。
如果要避免分配大缓冲区,您需要自己实现原地非方阵转置算法。OpenCV不提供此类工具。