首页 > 解决方案 > OpenCV如何处理Mat作为指针来加速代码?

问题描述

我正在尝试将指针与 cv::Mat 一起使用,但我不太明白。

当我尝试这个时:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat img;
    Mat temp;

    img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));
    temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    temp = img(Range(10, 20), Range(40, 60));
    temp.setTo(255);

    imshow("img", img);
    waitKey();
    return 0;
}

它有效,没有问题。但是,当我将其更改为:

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat* img;
    Mat* temp;

    *img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));
    *temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    temp = img(Range(10, 20), Range(40, 60));
    temp.setTo(255);

    imshow("img", *img);
    waitKey();
    return 0;
}

我收到此错误:

明显调用括号前的表达式必须具有(指向)函数类型

temp = img(Range(10, 20), Range(40, 60));

和错误:

表达式必须具有类类型

temp.setTo(255);

将Mat作为指针处理以加快代码速度的一般规则是什么?

例如,我知道,在函数参数中,我们&用于输入 Mats 和*输出 Mats。但是有一个通用的规则如何在函数内部定义和使用 Mats 吗?

请告诉我这段代码是否还有其他问题,因为我是初学者。谢谢!

标签: c++opencvpointersmat

解决方案


在您发布的示例中,使用指针没有任何好处。在您的带有指针的示例中,存在许多问题。

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    Mat src = imread("image.png");
    Mat* img; // Uninitialized pointer; points to random memory
    Mat* temp; // Uninitialized pointer; points to random memory

    // Undefined behavior: dereferencing an uninitialized pointer
    // You are basically trying to treat some random piece of memory
    // as a cv::Mat and trying to assign another cv::Mat to it.
    *img = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0)); 
    *temp = Mat(src.rows, src.cols, CV_8UC1, cv::Scalar(0));

    // Syntax error: img has type Mat*; you could call the
    // Mat Mat::operator()( Range _rowRange, Range _colRange ) const
    // Like this:
    // *temp = img->operator()(Range(10, 20), Range(40, 60));
    // or like this:
    // *temp = (*img)(Range(10, 20), Range(40, 60));
    // that would work if img and temp were to point to valid cv::Mats
    temp = img(Range(10, 20), Range(40, 60));
    // Syntax error temp has type Mat*
    //  to access a pointers members use -> instead of .
    temp.setTo(255);

    imshow("img", *img);
    waitKey();
    return 0;
}

一般来说,复制 cv::Mat 是一种低成本操作,因为它不会创建整个缓冲区的副本,而只是增加引用计数并复制一些如何解释该缓冲区的信息。在典型的硬件上,您可以预期最多需要几十纳秒。简单的图像处理操作很容易花费一百万倍的时间。

很少有理由拥有指向 cv::Mat 的指针。如果您切换到指针,这样做是因为它更有意义,而不是为了提高性能。不过,通过 (const) 引用而不是按值传递您的垫子可能仍然是正确的默认选择。

一个使用 cv::Mat 指针的用例可能是一个可选的 out 参数:

 void mayBeNull(cv::Mat* matPointer = nullptr)
 {
    if(matPointer!=nullptr)
    {
       // assign something to *matPointer
    }
    else
    {
       // do not use matPointer
       // the caller does not care about our outparam
    }
 }

推荐阅读