【问题标题】:Efficiency of summing images using MATLAB and OpenCV使用 MATLAB 和 OpenCV 求和图像的效率
【发布时间】:2016-06-10 07:36:51
【问题描述】:

我对您的所有回答感到非常惊讶。 非常感谢!

错误代码如下所示: percentage = (double)kk * 100.0 / (double)totalnum;

在我修改为: percentage = (double)kk * 100.0 / totalnum;

问题已解决。这个简单的除法消耗了 150 中的大约 90。也许 doubleint 之间的划分比 doubles 之间的划分要快。

再次感谢您的所有回答!


我正在尝试从来自视频的一组图片中获取平均图像。这项工作只有两个步骤:

  1. 将所有图像汇总成一个矩阵。
  2. 将矩阵除以图像数。

我在 OpenCV 中使用了以下代码:(C++)

Mat avIM = Mat::zeros(IMG_HEIGHT, IMG_WIDTH, CV_32FC3);

for (ii = startnum; ii <= endnum; ii += interval) {
    string fullname = argv[1];
    sprintf(filename, "\\%d.png", ii);
    fullname.append(filename);

    Mat tempIM = imread(fullname.c_str());
    if (tempIM.empty()) { cout << "Can't open image!\n"; return -1; }
    tempIM.convertTo(tempIM, CV_32FC3);     

    avIM += tempIM;     //Sum up every image
    ++kk;

}
avIM = avIM * (double)(1.0 / kk);   //get average'

MatLab 中的以下代码:(2015a)

avIM = zeros(size(imread([im.dir,'\',num2str(startnum),'.png'])));

pointIdx = startnum:interval:endnum;
for j=pointIdx,
    IM = imread([im.dir,'\',num2str(j),'.png']);
    avIM = avIM + double(IM); %Sum up every image
end
avIM = uint8(round(avIM./size(pointIdx,2))); %get average

但是当我在 2,100 张图像上运行这两个程序时,OpenCV 用了 150.3s(发布)而 MatLab 用了 103.1s。 C++ 程序的运行速度比 MatLab 脚本慢,这让我很困惑。

那么是什么让我的 OpenCV 程序变慢了?如果是我的矩阵访问方式造成的,应该怎么做才能提高效率?

【问题讨论】:

  • 1.您是否有可能在 Visual Studio 中以调试模式而不是发布模式运行?将其更改为释放模式并使用 Ctrl+F5 运行程序 2. 是否需要转换为浮动?你最初可以读为 float 吗?
  • 1.是的,这是一个发布模式。 2.其实我只是把别人的代码转成C++,看到IM前面有个(double)。所以我想我需要一个浮点型矩阵来对这些图像求和。
  • 另一个可能的问题:您的图像在哪里?它们是否可能位于外部磁盘上?
  • 它们来自同一个文件夹,它是我笔记本电脑中的硬盘驱动器(5400rpm)。我已经单独运行它们,没有运行后台程序。

标签: c++ matlab opencv


【解决方案1】:

您的代码似乎足够好,在我的测试中,我发现它的运行速度比 Matlab 代码快 10 倍。

但是,我展示了一个稍微优化的代码,它的执行速度比您的要快一些。

备注

请注意,我没有名为你的图片的文件夹,所以我在 C++ 版本中使用 cv::glob,在 Matlab 版本中使用 dir 来获取文件夹中图像的名称。

我的文件夹里有82张小图,所以运行时间明显比你小,但相对性能应该是靠谱的。

执行时间

                    Sum only      Get filenames + Sum
Matlab:             0.173543 s    (0.185308 s)
OpenCV @Seven Wang: 0.0145206 s   (0.0155748 s)
OpenCV @Miki:       0.0128943 s   (0.013333 s)

注意事项

确保您在 OpenCV 和 Matlab 中一致地计算运行时间。


代码

Matlab 代码:

tic

folder = 'D:\\SO\\temp\\old_075_6\\';
filenames = dir([folder '*.bmp']);

% Get rows and cols from 1st image
img = imread([folder name]);



S = zeros(size(img));

for ii = 1 : length(filenames)
    name = filenames(ii).name;
    currentImage = imread([folder name]);    
    S = S + double(currentImage);
end

S = uint8(round(S / length(filenames)));

toc

C++ 代码:

#include <opencv2\opencv.hpp>
#include <vector>
#include <iostream>

int main()
{
    double ticLoad = double(cv::getTickCount());

    std::string folder = "D:\\SO\\temp\\old_075_6\\*.bmp";
    std::vector<cv::String> filenames;
    cv::glob(folder, filenames);

    int rows, cols;
    {
        // Just load the first image to get rows and cols
        cv::Mat3b img = cv::imread(filenames[0]);
        rows = img.rows;
        cols = img.cols;
    }

    /*{
        double tic = double(cv::getTickCount());

        cv::Mat3d S(rows, cols, 0.0);

        for (const auto& name : filenames)
        {
            cv::Mat currentImage = cv::imread(name);
            currentImage.convertTo(currentImage, CV_64F);

            S += currentImage;

        }
        S = S * double(1.0 / filenames.size());

        cv::Mat3b avg;
        S.convertTo(avg, CV_8U);

        double toc = double(cv::getTickCount());

        double timeLoad = (toc - ticLoad) / cv::getTickFrequency();
        double time = (toc - tic) / cv::getTickFrequency();
        std::cout << "@Seven Wang: " << time << " s (" << timeLoad << " s)" << std::endl;
    }*/

    {
        double tic = double(cv::getTickCount());

        cv::Mat3d S(rows, cols, 0.0);
        cv::Mat3b currentImage;

        for (const auto& name : filenames)
        {
            currentImage = cv::imread(name);
            cv::add(S, currentImage, S, cv::noArray(), CV_64F);
        }
        S /= filenames.size();

        cv::Mat3b avg;
        S.convertTo(avg, CV_8U);

        double toc = double(cv::getTickCount());

        double timeLoad = (toc - ticLoad) / cv::getTickFrequency();
        double time = (toc - tic) / cv::getTickFrequency();
        std::cout << "@Miki: " << time << " s (" << timeLoad << " s)" << std::endl;
    }
    getchar();






    return 0;
}

【讨论】:

  • 天啊,感谢您的分析!但不幸的是,这完全是我的错,我没有在我的问题上发布:percentage = (double)kk * 100.0 / (double)totalnum; 这是占用我时间的错误代码。将其更改为percentage = (double)kk * 100.0 / totalnum; 后,问题完全解决了。无论如何,我会研究你的代码。再次,非常感谢!
【解决方案2】:

引起我注意的一点是“CV_32FC3”类型。您是否特别喜欢 32 位浮点矩阵,并且您确定 Matlab 也以相同的方式获取像素值?

因为你有额外的步骤

tempIM.convertTo(tempIM, CV_32FC3);     

在您的 Cpp 代码中,Matlab 在检索图像后立即直接运行而无需任何转换,这可能会减慢您的 cpp 代码。此外,如果 Matlab 没有以浮点值获取图像,这可能会导致速度差异,因为与整数相比,浮点运算对于 CPU 来说是一项更难处理的任务。

【讨论】:

  • 这很重要。但在 MatLab 代码中,还多了一个步骤:avIM = avIM + double(IM);
  • 你指的是哪一步?
  • 对不起,我是这里的新用户,我对 mini-Markdown 格式感到困惑。我的意思是第 5 行的 double(),它也进行类型转换。
  • 我没有彻底搜索,但这里显示 CV_32FC3 介于 0 和 1 stackoverflow.com/questions/5724715/… 之间。如果 Matlab 以整数(从 0 到 255)获取矩阵,将其转换为 double 将只执行 0.0、255.0,没有复杂的操作。但是在 cpp 中,它必须用浮点运算除以每个数字以获得 0 和 1 之间的结果。(再次,如果引用的页面是正确的)
  • @OE1 这可能是一个要点。 @Seven,您能否再次与 MATLAB 代码中的 im2double 而不是 double 进行比较?这也将扩展到[0,1],并使比较“公平”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
  • 2017-05-01
  • 2019-02-24
相关资源
最近更新 更多