OpenCV实现图像的原地旋转或转置吗?

4

https://zh.wikipedia.org/wiki/%E5%8E%9F%E5%9C%B0%E7%9F%A9%E9%98%B5%E8%BD%AC%E7%BD%AE 看起来这是一个经过深入研究和长期存在的问题,所以我对opencv在解决它方面的能力(零?)感到有些惊讶。

我已经尝试了与伪代码相当的内容:

cv::Mat input(width,height,CV_8UC3);
FillMyInput();
cv::transpose(input,input);
cv::flip(input);

transpose方法会改变input.data指针,因此我认为该方法在功能上类似于以下操作:
if (input_image == output_image)
{
    cv::Mat m = CreateNewMat(sizeof(input_image));
    TransposeOutOfPlace(input_image,m)
    output_image = m;
}

这是否正确,如果是的话,opencv是否提供了另一种旋转或转置图像的方法,而不需要分配大小等于原始图像的大缓冲区?
1个回答

4

这是时间复杂度和内存使用之间的选择。

看一下源代码(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不提供此类工具。

这是正确的方向上的一些好分析,但由于我遇到过很多次这个问题,因此我特别关注OpenCV中的Mat创建函数。它们遵循<rows,cols>而不是通常的<width,height>约定。create(nrows, ncols, type)!= create(src.cols, src.rows, src.type()); 在您引用Mat :: create方法时,很明显会分配一个新的Mat,因为dst的形状(相对于旧的dst == src)不匹配。您的回答还需要一些更改,一旦我们解决了问题,也许我们应该测试峰值内存使用率。 - Boyko Perfanov
@Boyko Perfanov,抱歉我的粗心大意,我已经更新了它。 - Qmick Zh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接