Почему оператор «звезда» (*) быстрее, чем умножение доступа к указателю при масштабировании матрицы с использованием OpenCV? - PullRequest
0 голосов
/ 09 апреля 2019

Я пытаюсь научиться манипулировать значениями матрицы OpenCV наиболее оптимизированным способом. Я попытался масштабировать большое изображение, хранящееся в матрице OpenCV, четырьмя различными способами.

1) Использование оператора * *

2) Использование функции at и петли for

3) Использование доступа к указателю и for циклов

4) Использование справочной таблицы

Округленные результаты этого эксперимента были следующими

* оператор ------- 3 ms

at функция ------- 12 ms

указатель доступа ---- 9 ms

справочная таблица -------- 1 ms

Теперь совершенно очевидно, почему таблицы поиска являются самыми быстрыми. Но я не всегда смогу их использовать. Для случаев, для которых я не могу использовать справочную таблицу, мне нужно понять, как OpenCV реализует масштабирование с помощью оператора *, чтобы я мог использовать этот метод в качестве справочного материала в других моих манипуляциях со значениями матрицы.

Буду очень признателен, если кто-нибудь скажет мне, что происходит за операцией *, которая делает его быстрее, чем метод доступа с указателем?

Пожалуйста, найдите следующий код для справки.

Спасибо

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

typedef std::chrono::system_clock Timer;
typedef std::chrono::duration<double> Duration;

using std::cout;
using std::endl;
using std::vector;

double profile(Timer::time_point start, Timer::time_point end) {
    Duration span = end - start;
    return span.count() * 1000;
}

int main() {

    cv::Mat image = cv::imread("../data/large.jpg", 0);
    float sc = 1;

    while (true) {

        //=================== first method ====================
        Timer::time_point s1 = Timer::now();
        cv::Mat mine = image * sc;
        Timer::time_point s2 = Timer::now();

        //=================== second method ====================
        cv::Mat yours(image.size(), image.type());
        Timer::time_point s3 = Timer::now();
        for (int i = 0; i < image.rows; i++) {
            for (int j = 0; j < image.cols; j++) {
                yours.at<uchar>(i, j) = image.at<uchar>(i, j) * sc;
            }
        }
        Timer::time_point s4 = Timer::now();

        //=================== third method ====================
        if (!image.isContinuous()) {
            std::cerr << "ERROR: image matrix isn't stored as a 1D array" << endl;
            exit(-1);
        }
        Timer::time_point s5 = Timer::now();
        cv::Mat result(image.size(), image.type());
        for (int i = 0; i < image.rows; i++) {
            for (int j = 0; j < image.cols; j++) {
                result.data[i * image.cols + j] = image.data[i * image.cols + j] * sc;
            }
        }
        Timer::time_point s6 = Timer::now();

        //=================== fourth method ====================
        Timer::time_point s7 = Timer::now();
        cv::Mat lookupTable(1, 256, image.type());
        for (int i = 0; i < 256; i++)
            lookupTable.data[i] = i * sc;
        cv::Mat his;
        cv::LUT(image, lookupTable, his);
        Timer::time_point s8 = Timer::now();


        cout << "first = " << profile(s1, s2) << endl;
        cout << "second = " << profile(s3, s4) << endl;
        cout << "third = " << profile(s5, s6) << endl;
        cout << "fourth = " << profile(s7, s8) << endl;
        cout << "=============== " << endl;

    }

    return 0;
}

1 Ответ

0 голосов
/ 09 апреля 2019

Оператор * () использовал parallel_for!Так что это будет быстрее, чем однопоточная функция.И вы можете написать #pragma omp параллельно для цикла перед строками и сравнить результаты.Или вы можете использовать image.forEach - он также параллельный и быстрый.

cv :: LUT: https://github.com/opencv/opencv/blob/master/modules/core/src/lut.cpp#L359

Эта функция имеет ряд реализаций: opencl, openvx, ipp и simpleс параллельным_фор.Я думаю, что в вашем случае была использована ipp_lut, очень-очень оптимизированная версия от Intel для своих процессоров.И это быстро!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...