1
votes

I am totally surprised by all of your answers. Thank you very much!

The bug code is showed as following: percentage = (double)kk * 100.0 / (double)totalnum;

After I modified it to: percentage = (double)kk * 100.0 / totalnum;

The problem is SOLVED. And this simple division consumed about 90s out of 150s. Maybe division between double and int is faster than it between doubles.

Again, thanks for all of your answers!


I'm trying to getting the average image from a set of pictures which come from a video. There are only 2 steps for this job:

  1. Sum up all the images into a matrix.
  2. Divide the matrix by the number of images.

I used following code in 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'

And following code in 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

But when I run those two program on 2,100 images, OpenCV took 150.3s(Release) and MatLab took 103.1s. It really confused me that a C++ program runs slower than a MatLab script.

So what's slowing down my OpenCV program? If it's caused by my method of matrix accessing, what should I do to improve the efficiency?

2
1. is it possible that you are running in debug mode instead of release mode in Visual Studio? change it to release mode and run the program with Ctrl+F5 2. is the conversion to float necessary? can you originally read at as float ? - ibezito
1. Yes, it's a Release mode. 2. In fact, I'm just turning someone's code into C++ and I saw there is a (double) before IM. So I think I need a float-type matrix for summing these images. - Seven Wang
Another possible issue: where are your images are located? is it possible that they are located on an external disk? - ibezito
They're from the same folder and it's a hard drive(5400rpm) in my laptop. I've run them seperately with no background program running. - Seven Wang

2 Answers

0
votes

Your code seems good enough, and in my tests I found it's running 10 times faster than Matlab code.

However, I show a slightly optimized code, that performs a little faster than yours.

Notes

Please note that I don't have a folder with images named as you, so I used cv::glob in C++ version, and dir in Matlab version to get the names of the images in the folder.

In my folder I have 82 small images, so the running time is obviously smaller than yours, but the relative performance should be reliable.

Execution time

                    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)

Considerations

Be sure that you're computing the running time consistently in OpenCV and Matlab.


Code

Matlab code:

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++ code:

#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;
}
0
votes

One point that drew my attention is the type "CV_32FC3". Are you specifically preferring that 32 bit float matrix and are you sure Matlab as well gets the pixel values the same way?

Because you have that extra step

tempIM.convertTo(tempIM, CV_32FC3);     

in your Cpp code, where Matlab directly operates as soon as it retrieves the image without any conversion, which might be slowing down your cpp code. Furthermore, if Matlab is not getting the image in float values, that might be contributing the speed difference as float point arithmetics is a harder task for CPU to handle compared to integers.