[C++-sig] how to return arbitrary (python-)objects from boost?

Joerg Kurlbaum jkur at informatik.uni-bremen.de
Wed Apr 23 16:52:21 CEST 2008


On Wed, Apr 23, 2008 at 08:26:29AM -0400, Stefan Seefeld wrote:
> Joerg,
>
> I'm not sure I completely understand what you are trying to do, or  
> whether that's actually needed...

Hm, i supected that.

> If you mean by 'arbitrary objects' python objects, you can certainly  
> pass those. In C++ they are spelled boost::python::object, and you can  
> pass them as function arguments or return values as any other type.  
> Conversion from C++ types to boost::python::object is implicit as long  
> as there are registered converters.

Okay. I've read about converters. But the noddy example isn't very
helpful. The problem is, i think, that all the types i want to use are
already there. I have the QImage in C++ and in Python. I want to create
a QImage in the wrapper code from the image data and return that to the
python program.

> For a more specific answer it might be best if you show some code...

You are right. In the boost wrapper i derive from the class that does
all the camera-specific handling in C/C++. I'm adding another function
to convert from the uchar array with the image data to a numpy array
(get_image_as_array). This code works. The actual handling of the RGB
values is not important and can be ignored.

Now i want to have a function that does not return a numpy array but a
QImage, which is available in C++ and with pyqt4 in python as well.
The function get_image_as_qimage() would be my naive approach to do
that, but this code doesn't even compile, because the cast from
python::object to QImage does not work and several other problems.
And that makes sense if there isn't some information for boost::python
what a QImage actually is. But maybe you can get an idea of what i
wanted to do.
Do i have to write a complete type description (like in the noddy
example) for QImage? I would think that this description is already
existent, because PyQt4 uses the QImage derived from the C++ library.

#include <boost/python.hpp>
#include <num_util.h>
#include <QtGui/QImage>
#include "camera.h"

class Camera_wrap : public Camera
{
public:
    // THIS CODE WORKS
    virtual numeric::array get_image_asarray()
    {
        int* size = reinterpret_cast<int*>(&rgbframe->size[0]);
        boost::python::object obj(boost::python::handle<>(PyArray_FromDims(2, size, NPY_UINT32)));
        void *arr_data = PyArray_DATA((PyArrayObject*) obj.ptr());
        uint32_t* dest = static_cast<uint32_t*>(arr_data);
        unsigned char* src = rgbframe->image;
        unsigned char R,G,B,A;
        for ( uint32_t y = 0; y < rgbframe->size[1]; ++y)
        {
            for ( uint32_t x = 0; x < rgbframe->size[0]; ++x)
            {
                R = *src++;
                G = *src++;
                B = *src++;
                A = 255;
                unsigned char* pixel = reinterpret_cast<unsigned char*>( &(dest[x*size[1]+y])  );
                *pixel++ = B;
                *pixel++ = G;
                *pixel++ = R;
                *pixel =   A;
            }
        }
        return boost::python::extract<boost::python::numeric::array>(obj);
    }

    // THIS IS ONLY HOW I THINK I COULD LOOK LIKE
    virtual QImage get_image_qimage()
    {
        unsigned int nx = rgbframe->size[0];
        unsigned int ny = rgbframe->size[1];
        boost::python::object obj(boost::python::handle<>( new QImage(nx, ny, QImage::Format_ARGB32)));
        for (int j = 0; j < ny; ++j)
        {
            uint8_t* line = static_cast<uint8_t*>( reinterpret_cast<QImage*>(obj.ptr())->scanLine(j) );
            uint8_t* data = rgbframe->image + j*nx*3;
            for (int i=0; i<nx; i++)
            {
                *line++ = *data++;
                *line++ = *data++;
                *line++ = *data++;
                *line++ = 255;
            }
        }
        return obj;
    }

    // ...
}


BOOST_PYTHON_MODULE(camera1394)
{
    import_array();
    numeric::array::set_module_and_type("numpy", "ndarray");

    class_<Camera_wrap>("Camera", init<Camera_Configuration>())
        .def("capture", &Camera_wrap::capture)
        .def("capture_end", &Camera_wrap::capture_end)
        .def("get_image_asarray", &Camera_wrap::get_image_asarray )
        .def("get_image_qimage", &Camera_wrap::get_image_qimage )
        .def("image_size", &Camera_wrap::get_size_wrap )
        ;

    // ...
}

Another approach i tried, is to create the QImage in python and pass it as
an argument to a function in the wrapper, store the image data in the
scanLines and return it (or as in the code modify a reference)

void get_image_as_qimage2(boost::python::object obj)
{
        QImage& img = extract<QImage&>(obj);
        // do some image stuff
        // ...
}

And in python:

from camera1394 import *
from PyQt4 import Qt, QtGui

def main():
    conf = Camera_Configuration()
    c = Camera(conf)
    c.capture()
    qimage = QtGui.QImage(640, 480, Qt.QImage.Format_ARGB32)
    c.get_image_as_qimage(qimage)
    c.capture_end()

But here i get a type error:
TypeError: No registered converter was able to extract a C++
           reference to type QImage from this Python object of type QImage

Okay. Now i would be in the situation to write a converter. There is an
example in the FAQ with some custom_string class but as far i can see
all this conversion does is breaking a custom string down to a char*
which is then implicitly converted to a python string. This seems very
different to what i'm trying.

I hope i could make it a bit more clear what my problem is. Somehow i
think this is more or less a standard/newbie problem when using
boost::python but i haven't found suitable documentation.

Greetings,
   Jörg :-)

-- 
Jörg Kurlbaum (jkur at informatik.uni-bremen.de)           Cartesium 00.056
GPG-ID: CAC40EA9                                        Enrique Schmidt Str. 5
T: 0421/218-64201                                       Universität Bremen



More information about the Cplusplus-sig mailing list