Boost :: Python: как открыть динамический необъектный массив для PyBuf? - PullRequest
1 голос
/ 13 марта 2012

Я работаю в системе Computer Vision с OpenCV на C ++. Я написал небольшой графический интерфейс для него, используя Boost :: Python и PyQT4. Поскольку я не хочу вводить QT в проект C ++, мне нужен способ представить Mat :: data (член без знака char *) Python, чтобы создать там QImage.

Сначала я попробовал это так:

    class_<cv::Mat>("Mat", init<>())
          .add_property("data_", make_getter(&Mat::data))

но потом я получил это в Python: «Ошибка типа: не найден конвертер to_python (по значению) для типа C ++: unsigned char *»

Я не смог написать конвертер для него, потому что PyBuf, конечно, должен знать его размер.

Итак, мой следующий подход - попытаться создать прокси-объект, подобный этому:

struct uchar_array {
  uchar *data;
  size_t size;
  bool copied;
  static const bool debug = true;

  // copy from byte array
  uchar_array(uchar *ptr, size_t size, bool copy) {
      this->size = size;
      this->copied = copy;
      if(copied) {
          data = new uchar[size];
          memcpy(data, ptr, size);
      } else {
          data = ptr;
      }
      if(debug) LOG_ERR("init %d bytes in @%p, mem @%p", size, this, data);
  }

  PyObject *py_ptr() {
      if(debug) LOG_ERR("py_ptr");
      return boost::python::incref(PyBuffer_FromMemory(data, size));
  }

  ~uchar_array() {
      if(debug)  LOG_ERR("~uchar_array @%p", this);
      if(copied) {
          if(debug) LOG_ERR("free @%p, mem @%p", this, data);
          delete [] data;
      }
  }
};

И разоблачение этого с помощью метода, не являющегося членом:

uchar_array *getMatData(Mat &mat) {
  size_t size = mat.rows * mat.cols * mat.elemSize();
  uchar_array *arr = new uchar_array(mat.data, size, true);
  return arr;
}


class_<cv::Mat>("Mat", init<>())
        .def("data", getMatData, with_custodian_and_ward_postcall<1, 0, return_value_policy<manage_new_object> >())
class_<uchar_array, shared_ptr<uchar_array> >("uchar_array", no_init)
        .def("ptr", &uchar_array::py_ptr);

Это работает и возвращает меня в буфер Python, но с этим подходом связаны две проблемы:

  1. Теперь мне нужно использовать mat.data (). Ptr (), было бы лучше просто сделать mat.data
  2. При выполнении mat.data (). Ptr () кажется, что временный uchar_array разрушается сразу после вызова ptr (), освобождая память, пока я все еще хочу ее использовать

Я провел несколько экспериментов с custodian_and_ward и другими вещами, но дошел до того, что остановился, чтобы понять это.

Итак, кто-нибудь может сказать мне: каков предпочтительный способ экспорта беззнакового символа * в PyBuf? В двух вариантах, если это возможно: выделено для Python, поэтому должно быть освобождено Python или как внутренний указатель, где C ++ освобождает его.

1 Ответ

0 голосов
/ 14 марта 2012

char* буферы не совсем дружественны к питону. В моем проекте (который не чувствителен к производительности) я бы использовал std :: vector или std :: string, в зависимости от того, что он должен был содержать. Обе они прекрасно подходят для Python.

Если вы не можете изменить базовую структуру данных, вы можете использовать add_property и несколько функций получения и установки для преобразования данных в более удобную структуру.

...