Home > database >  Convert python with numpy to c with opencv
Convert python with numpy to c with opencv

Time:05-07

I'm working on some optimazation and want to convert some parts from python to c

Is it possible to convert this code to c with opencv?

The python code uses 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]]

update

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;
}

CodePudding user response:

This is the equivalent code in C 11. This should be several times faster than your python code.

#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);
}

There are a couple of additional notes.

Note1: Due to the difference in the shuffle algorithm between python and std, the results are not exactly the same.

Note2: With your code, num_samples cannot be larger than the number of pixels in the input image, which seems to be a bug. Please check the length of the samples.

Note3: In both implementations, the most expensive part is shuffle. 60% for python and more than 80% for C is spent here. If you want to optimize further, this is definitely where you should exploit.

  • Related