Преобразовать python с numpy в c++ с помощью opencv

Я работаю над оптимизацией и хочу преобразовать некоторые части с python на c++.

Можно ли преобразовать этот код в C++ с помощью opencv?

В коде Python используется numpy

import numpy as np
from PIL import Image

pil_img = Image.open(input_filename)
img = np.array(pil_img)
pixels = img.reshape((-1, 3))

num_pixels = pixels.shape[0]
num_samples = int(num_pixels*5)

idx = np.arange(num_pixels)
np.random.shuffle(idx)

samples = pixels[idx[:num_samples]]

Обновить

std::vector<uchar> sample_pixels(const cv::Mat& m, int sample_percent=5){
    assert(m.isContinuous());
    
    const auto* input = m.ptr<uchar>();
    
    int
        num_pixels      = m.total(),
        num_samples     = num_pixels * sample_percent;
    
    std::cout
        << "num pixels:  " << num_pixels << '\n'
        << "num samples: " << num_samples << '\n';
    
    std::vector<uchar> samples(num_samples);
    
    //  Fills idx with sequentially increasing values
    std::vector<int> idx(num_pixels);
    std::iota(idx.begin(), idx.end(), 0);
    
    //  Shuffle idx
    std::mt19937 engine(0);
    std::shuffle(idx.begin(), idx.end(), engine);
    
    for(int i = 0; i < num_samples; i++){
        //samples[i] = input[idx[i]];
    }
    
    //auto output_mat = cv::Mat(samples, false);
    //cv::imwrite("enhance-samples.png", output_mat);
    
    return samples;
}

Разве Numpy в основном не BLAS?

DrBwts 05.05.2022 16:05

да это возможно. Однако вы можете не получить никакого улучшения производительности.

Miki 05.05.2022 17:05
opencv можно использовать с python, а также с его родным C++. Таким образом, первым шагом может быть замена использования PIL на opencv. Существует множество примеров SO с использованием opencv. Любое дальнейшее использование С++ зависит от вашего знакомства с языком.
hpaulj 05.05.2022 17:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это эквивалентный код в C++11. Это должно быть в несколько раз быстрее, чем ваш код на Python.

#include <random>
#include <numeric>

#include <opencv2/opencv.hpp>

void shuffling(const std::string &input_filename, const std::string &output_filename) {

    // ========== UPDATE ==========
    const cv::Mat plain_input_mat = cv::imread(input_filename, -1);
    // Equivalent to img.reshape((-1, 3))
    const cv::Mat input_mat = plain_input_mat.reshape(3);
    // ============================

    // By doing this, you can access the pixels without any extra checks.
    assert(input_mat.isContinuous());
    const auto *input = input_mat.ptr<cv::Vec3b>();

    const auto num_samples = input_mat.total();
    std::vector<cv::Vec3b> output(num_samples);

    std::vector<int> idx(input_mat.total());
    std::iota(idx.begin(), idx.end(), 0);  // Equivalent to arange.

    // Note: numpy uses PCG64 which does not exist in the std library.
    std::mt19937 engine(0);
    std::shuffle(idx.begin(), idx.end(), engine);

    for (int i = 0; i < num_samples; i++) {
        output[i] = input[idx[i]];
    }

    // Save as an image if necessary.
    auto output_mat = cv::Mat(output, false);
    cv::imwrite(output_filename, output_mat);
}

Есть пара дополнительных замечаний.

Примечание 1. Из-за разницы в алгоритме перетасовки между python и std результаты не совсем совпадают.

Примечание 2. В вашем коде num_samples не может быть больше, чем количество пикселей во входном изображении, что кажется ошибкой. Пожалуйста, проверьте длину samples.

Примечание 3: В обеих реализациях самая дорогая часть — shuffle. Здесь тратится 60% на python и более 80% на C++. Если вы хотите оптимизировать дальнейшую оптимизацию, это определенно то, что вам следует использовать.

Я смотрю на ваш код. Что делает input_mat.ptr<cv::Vec3b>();? Будет ли он преобразовывать матрицу в указатель и будет ли это <cv::Vec3b> своего рода кастингом? Приведет ли он матрицу к CV_8UC1?

clarkk 05.05.2022 23:09

Хорошо, после некоторых исследований выяснилось, что cv::Vec3b - это 3 канала :) Внесли обновление в вопрос с некоторыми изменениями. Изменено cv::Vec3b на uchar, потому что вход представляет собой 1 канал в оттенках серого. Но есть проблема с кодом. Если samples[i] = input[idx[i]]; раскомментирован, код возвращает ошибку

clarkk 06.05.2022 00:59

Извините за задержку с ответом. input_mat.ptr<cv::Vec3b>() приводит указатель к CV_8UC3 (не преобразование). Это не должно соответствовать формату входного изображения, а скорее тому, как вы хотите его обрабатывать. В вашем коде Python вы изменяете изображение, оставляя 3 канала, это означает, что 3 элемента будут скопированы за одно назначение. Если вы хотите такое поведение, оставьте его как Vec3b. Вместо этого вы должны изменить форму ввода так же, как ваш код Python. Смотрите мое обновление.

ken 06.05.2022 05:41

Следует отметить две вещи: во-первых, это изменение допустимо только в том случае, если количество пикселей во входных данных кратно 3 (как в коде Python). Во-вторых, вы определяете num_samples как num_pixels * sample_percent, но это в 5 раз больше num_pixels, а не 5 процентов. Это вызывает внеиндексацию (так же, как и в коде Python, поэтому вы должны сначала отладить его).

ken 06.05.2022 05:41

Извините, что пришлось 0.05 (5%).. Спасибо за ваше время :)

clarkk 06.05.2022 22:09

а надо ли делать plain_input_mat.reshape(3); когда делаешь input_mat.ptr<cv::Vec3b>() ??

clarkk 06.05.2022 22:22
mat.reshape(3) изменяет только информацию о форме, чтобы mat.total() возвращал правильное значение. Таким образом, вы можете удалить mat.reshape(3) и настроить эти значения вручную, например mat.total() / 3. Но я думаю, что mat.reshape(3) было бы намного проще.
ken 07.05.2022 05:55

Другие вопросы по теме