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

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

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

  1. PyObject* byte_list = PyList_New(static_cast<Py_ssize_t>(0));
  2. AVFrame *pFrameRGB = av_frame_alloc();
  3. av_frame_copy_props(pFrameRGB, this->pFrame);
  4. pFrameRGB->width = this->pFrame->width;
  5. pFrameRGB->height = this->pFrame->height;
  6. pFrameRGB->format = AV_PIX_FMT_RGB24;
  7. av_frame_get_buffer(pFrameRGB, 0);
  8. sws_scale(this->swsCtx, this->pFrame->data, this->pFrame->linesize, 0,
  9. this->pCodecContext->height, pFrameRGB->data, pFrameRGB->linesize);
  10. if (this->_debug) {
  11. std::cout << "Frame linesize " << pFrameRGB->linesize[0] << "\n";
  12. std::cout << "Frame width " << pFrameRGB->width << "\n";
  13. std::cout << "Frame height " << pFrameRGB->height << "\n";
  14. }
  15. // This looping method seems slow
  16. for(int y = 0; y < pFrameRGB->height; ++y) {
  17. for(int x = 0; x < pFrameRGB->width; ++x) {
  18. int p = x * 3 + y * pFrameRGB->linesize[0];
  19. int r = pFrameRGB->data[0][p];
  20. int g = pFrameRGB->data[0][p+1];
  21. int b = pFrameRGB->data[0][p+2];
  22. PyList_Append(byte_list, PyLong_FromLong(r));
  23. PyList_Append(byte_list, PyLong_FromLong(g));
  24. PyList_Append(byte_list, PyLong_FromLong(b));
  25. }
  26. }
  27. av_frame_free(&pFrameRGB);

谢谢!

ruarlubt

ruarlubt1#

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

  1. PyObject *vec_to_array(std::vector<uint8_t>& vec) {
  2. static PyObject *single_array;
  3. if (!single_array) {
  4. PyObject *array_module = PyImport_ImportModule("array");
  5. if (!array_module)
  6. return NULL;
  7. PyObject *array_type = PyObject_GetAttrString(array_module, "array");
  8. Py_DECREF(array_module);
  9. if (!array_type)
  10. return NULL;
  11. single_array = PyObject_CallFunction(array_type, "s[B]", "B", 0);
  12. Py_DECREF(array_type);
  13. if (!single_array)
  14. return NULL;
  15. }
  16. // extra-fast way to create an empty array of count elements:
  17. // array = single_element_array * count
  18. PyObject *pysize = PyLong_FromSsize_t(vec.size());
  19. if (!pysize)
  20. return NULL;
  21. PyObject *array = PyNumber_Multiply(single_array, pysize);
  22. Py_DECREF(pysize);
  23. if (!array)
  24. return NULL;
  25. // now, obtain the address of the array's buffer
  26. PyObject *buffer_info = PyObject_CallMethod(array, "buffer_info", "");
  27. if (!buffer_info) {
  28. Py_DECREF(array);
  29. return NULL;
  30. }
  31. PyObject *pyaddr = PyTuple_GetItem(buffer_info, 0);
  32. void *addr = PyLong_AsVoidPtr(pyaddr);
  33. // and, finally, copy the data.
  34. if (vec.size())
  35. memcpy(addr, &vec[0], vec.size() * sizeof(uint8_t));
  36. return array;
  37. }

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

  1. std::vector<uint8_t> rgb_arr;
  2. // Copy data from AV Frame
  3. uint8_t* rgb_data[4]; int rgb_linesize[4];
  4. av_image_alloc(rgb_data, rgb_linesize, this->pFrame->width, this->pFrame->height, AV_PIX_FMT_RGB24, 32);
  5. sws_scale(this->swsCtx, this->pFrame->data, this->pFrame->linesize, 0, this->pFrame->height, rgb_data, rgb_linesize);
  6. // Put the data into vector
  7. int rgb_size = pFrame->height * rgb_linesize[0];
  8. std::vector<uint8_t> rgb_vector(rgb_size);
  9. memcpy(rgb_vector.data(), rgb_data[0], rgb_size);
  10. // Transfer the data from vector to rgb_arr
  11. for(int y = 0; y < pFrame->height; ++y) {
  12. rgb_arr.insert(
  13. rgb_arr.end(),
  14. rgb_vector.begin() + y * rgb_linesize[0],
  15. rgb_vector.begin() + y * rgb_linesize[0] + 3 * pFrame->width
  16. );
  17. }
  18. 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指令并行化图像处理。

相关问题