C++中追加PyList的快速方法

5sxhfpxr  于 2022-12-20  发布在  其他
关注(0)|答案(2)|浏览(128)

我刚接触c++,正在寻找一种更快的方法来将像素值附加到python列表中,因为目前在循环中处理一帧分辨率为854 x480的图像大约需要0.1秒,有人知道吗?
我尽量避免使用第三方模块,如果可能的话。
以下是我目前所了解到的:

PyObject* byte_list = PyList_New(static_cast<Py_ssize_t>(0));

AVFrame *pFrameRGB = av_frame_alloc();
av_frame_copy_props(pFrameRGB, this->pFrame);
pFrameRGB->width = this->pFrame->width;
pFrameRGB->height = this->pFrame->height;
pFrameRGB->format = AV_PIX_FMT_RGB24;
av_frame_get_buffer(pFrameRGB, 0);

sws_scale(this->swsCtx, this->pFrame->data, this->pFrame->linesize, 0, 
        this->pCodecContext->height, pFrameRGB->data, pFrameRGB->linesize);

if (this->_debug) {
    std::cout << "Frame linesize " << pFrameRGB->linesize[0] << "\n";
    std::cout << "Frame width " << pFrameRGB->width << "\n";
    std::cout << "Frame height " << pFrameRGB->height << "\n";
}

// This looping method seems slow
for(int y = 0; y < pFrameRGB->height; ++y) {
    for(int x = 0; x < pFrameRGB->width; ++x) {
        int p = x * 3 + y * pFrameRGB->linesize[0];
        int r = pFrameRGB->data[0][p];
        int g = pFrameRGB->data[0][p+1];
        int b = pFrameRGB->data[0][p+2];
        PyList_Append(byte_list, PyLong_FromLong(r));
        PyList_Append(byte_list, PyLong_FromLong(g));
        PyList_Append(byte_list, PyLong_FromLong(b));
    }
}

av_frame_free(&pFrameRGB);

谢谢!

ruarlubt

ruarlubt1#

在四处查看之后,我决定使用Python内置数组库,它可以使用memcpy而不是PyList,后者需要逐个输入数据。
从我的测试,这提高了速度从2-10倍,这取决于数据。

PyObject *vec_to_array(std::vector<uint8_t>& vec) {
    static PyObject *single_array;
    if (!single_array) {
        PyObject *array_module = PyImport_ImportModule("array");
        if (!array_module)
            return NULL;
        PyObject *array_type = PyObject_GetAttrString(array_module, "array");
        Py_DECREF(array_module);
        if (!array_type)
            return NULL;
        single_array = PyObject_CallFunction(array_type, "s[B]", "B", 0);
        Py_DECREF(array_type);
        if (!single_array)
            return NULL;
    }
    // extra-fast way to create an empty array of count elements:
    //   array = single_element_array * count
    PyObject *pysize = PyLong_FromSsize_t(vec.size());
    if (!pysize)
        return NULL;
    PyObject *array = PyNumber_Multiply(single_array, pysize);
    Py_DECREF(pysize);
    if (!array)
        return NULL;

    // now, obtain the address of the array's buffer
    PyObject *buffer_info = PyObject_CallMethod(array, "buffer_info", "");
    if (!buffer_info) {
        Py_DECREF(array);
        return NULL;
    }
    PyObject *pyaddr = PyTuple_GetItem(buffer_info, 0);
    void *addr = PyLong_AsVoidPtr(pyaddr);

    // and, finally, copy the data.
    if (vec.size())
        memcpy(addr, &vec[0], vec.size() * sizeof(uint8_t));

    return array;
}

然后我把向量传递给那个函数

std::vector<uint8_t> rgb_arr;

// Copy data from AV Frame
uint8_t* rgb_data[4];  int rgb_linesize[4];
av_image_alloc(rgb_data, rgb_linesize, this->pFrame->width, this->pFrame->height, AV_PIX_FMT_RGB24, 32); 
sws_scale(this->swsCtx, this->pFrame->data, this->pFrame->linesize, 0, this->pFrame->height, rgb_data, rgb_linesize);

// Put the data into vector
int rgb_size = pFrame->height * rgb_linesize[0];
std::vector<uint8_t> rgb_vector(rgb_size);
memcpy(rgb_vector.data(), rgb_data[0], rgb_size);

// Transfer the data from vector to rgb_arr
for(int y = 0; y < pFrame->height; ++y) {
    rgb_arr.insert(
        rgb_arr.end(), 
        rgb_vector.begin() + y * rgb_linesize[0],
        rgb_vector.begin() + y * rgb_linesize[0] + 3 * pFrame->width
    );
}

PyObject* arr = vec_to_array(rgb_arr);

这在以后可以被python访问。

mrphzbgm

mrphzbgm2#

使用插入时间更快的容器,如std::vector或std::deque,而不是std::list。这些容器的插入时间为常数,而std::list的插入时间为线性。
使用批量插入方法,如std::vector::insert()或std::deque::insert(),一次插入多个值,而不是一次插入一个值。这可以减少插入单个元素的开销。
如果每个像素只有几个可能的值(如0或1),则使用内存效率高的数据结构(如std::bitset)来存储像素值。这可以减少内存使用并提高插入和访问值的性能。
使用C++11的emplace_back()方法,它通过在容器中就地构造元素来避免构造和复制元素的开销。
为容器预分配内存,以避免随着容器的增长而频繁重新分配内存的开销。可以使用std::vector或std::deque的reserve()方法预分配内存。
考虑对图像处理任务本身使用更快的算法或数据结构。例如,您可以使用优化的图像处理库,或者使用多线程或SIMD指令并行化图像处理。

相关问题