简体   繁体   中英

Speeding up access to a array with pointers in C++

I am trying to make a fast image threshold function. Currently what I do is:

void threshold(const cv::Mat &input, cv::Mat &output, uchar threshold) {

    int rows = input.rows;
    int cols = input.cols;

    // cv::Mat for result
    output.create(rows, cols, CV_8U);        

    if(input.isContinuous()) { //we have to make sure that we are dealing with a continues memory chunk

        const uchar* p;

        for (int r = 0; r < rows; ++r) {

            p = input.ptr<uchar>(r);

            for (int c = 0; c < cols; ++c) {

                if(p[c] >= threshold)
                    //how to access output faster??
                    output.at<uchar>(r,c) = 255;
                else
                    output.at<uchar>(r,c) = 0;
            }
        }
    }
}

I know that the at() function is quite slow. How can I set the output faster, or in other words how to relate the pointer which I get from the input to the output?

You are thinking of at as the C++ standard library documents it for a few containers, performing a range check and throwing if out of bounds, however this is not the standard library but OpenCV.

According to the cv::Mat::at documentation:

The template methods return a reference to the specified array element. For the sake of higher performance, the index range checks are only performed in the Debug configuration .

So there's no range check as you may be thinking.

Comparing both cv::Mat::at and cv::Mat::ptr in the source code we can see they are almost identical.

So cv::Mat::ptr<>(row) is as expensive as

return (_Tp*)(data + step.p[0] * y);

While cv::Mat::at<>(row, column) is as expensive as:

return ((_Tp*)(data + step.p[0] * i0))[i1];

You might want to take cv::Mat::ptr directly instead of calling cv::Mat::at every column to avoid further repetition of the data + step.p[0] * i0 operation, doing [i1] by yourself.

So you would do:

/* output.create and stuff */

const uchar* p, o;

for (int r = 0; r < rows; ++r) {

    p = input.ptr<uchar>(r);
    o = output.ptr<uchar>(r); // <-----

    for (int c = 0; c < cols; ++c) {

        if(p[c] >= threshold)
           o[c] = 255;
          else
            o[c] = 0;
    }
}

As a side note you don't and shouldn't check for cv::Mat::isContinuous here, the gaps are from one row to another, you are taking pointers to a single row, so you don't need to deal with the matrix gaps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM