Quantcast

CVtypes python bindings. How to assign data to a matrix?

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

CVtypes python bindings. How to assign data to a matrix?

wl2776
Administrator
Hi all.
Is there any one using CVtypes.py, created by G. Bishop, based on ctypes?

I have a usual pyhton list

src=[1,2,23,1,12,1]

I want to conver it to CvMat:
I write

import CVtypes as cv

n=len(src)/2
xy=cv.cvCreateMatHeader(n,2,cv.CV_32FC1)
cv.cvSetData(xy,src,cv.CV_AUTOSTEP)

Then python gives the error:
ArgumentError: argument 2: <type 'exceptions.TypeError'>: wrong type

If I write
cv.cvSetData(xy,pointer(src),cv.CV_AUTOSTEP)
then I have
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/wl/SOBG/panorama/python/<ipython console> in <module>()

/usr/lib/python2.5/ctypes/__init__.pyc in pointer(inst)
    316
    317 def pointer(inst):
--> 318     return POINTER(type(inst))(inst)
    319
    320 # XXX Deprecated

/usr/lib/python2.5/ctypes/__init__.pyc in POINTER(cls)
    260         klass = type(_Pointer)(name,
    261                                (_Pointer,),
--> 262                                {'_type_': cls})
    263         _pointer_type_cache[cls] = klass
    264     return klass

TypeError: _type_ must have storage info

Another variant gives another error:

cv.cvSetData(xy,ctypes.POINTER(src),cv.CV_AUTOSTEP)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/wl/SOBG/panorama/python/<ipython console> in <module>()

/usr/lib/python2.5/ctypes/__init__.pyc in POINTER(cls)
    247 def POINTER(cls):
    248     try:
--> 249         return _pointer_type_cache[cls]
    250     except KeyError:
    251         pass

TypeError: list objects are unhashable


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: CVtypes python bindings. How to assign data to a matrix?

David Bolen
"wl27761" <[hidden email]> writes:

> Is there any one using CVtypes.py, created by G. Bishop, based on ctypes?

I was, but have since switched over the ctypes-opencv package, which
was originally based on CVtypes, but has been extended quite a bit,
especially with respect to data structures and memory management.

But I believe the answer is similar for either package, which is you
need to convert your data into a C-compatible data block:

> I have a usual pyhton list
>
> src=[1,2,23,1,12,1]

First thing to remember is that, under the covers this is actually a
Python structure that is an internal array of python objects (which
happen to be integers).  So this structure has no actual compact
memory block holding nothing but the numeric values, as would an
OpenCV matrix.

> I want to conver it to CvMat:
> I write
>
> import CVtypes as cv
>
> n=len(src)/2
> xy=cv.cvCreateMatHeader(n,2,cv.CV_32FC1)
> cv.cvSetData(xy,src,cv.CV_AUTOSTEP)

This can't work, since as noted above, there's no raw memory block for
OpenCV to reference that will yield the numeric values.  Taking a
pointer of the list isn't going to help either since all you get is
one level of indirection still to the wrong sort of data.

As long as you are starting with a Python data structure, I can't
really think of any method to assign the data in a single step that
doesn't involve creating an appropriate memory block that contains the
true values.  If memory usage would be a problem, you could avoid that
by walking the Python list and assigning the matrix individually (with
something like cvSetReal2D) but if memory is an issue, the scale if
probably such that iterating over the list would be a performance
problem.

But something like this would work:

    >>> from CVtypes import *
    >>> from ctypes import c_float
    >>> src = [1,2,23,1,12,1]
    >>> data = (c_float * len(src))(*src)
    >>> data
    <__main__.c_float_Array_6 object at 0x009DF5D0>
    >>> xy = cvCreateMatHeader(len(src)/2, 2, CV_32FC1)
    >>> cvSetData(xy, data, CV_AUTOSTEP)
    >>> xy
    <ctypes.LP_CvMat object at 0x009DFDF0>
    >>> cvGetReal2D(xy,0,0)
    1.0
    >>> cvGetReal2D(xy,0,1)
    2.0
    >>> cvGetReal2D(xy,1,0)
    23.0
    >>> cvGetReal2D(xy,1,1)
    1.0

The use  of "c_float *  len" creates an  array data type of  the right
length.  You need to match  the expected data type (e.g., "c_float" to
match your array type of 32F - you would use c_byte for an 8U matrix).
Creating an instance of that type creates an array, whose contents are
set during construction by passing in the list contents.

Note that if you use cvSetData as above, you have to keep the "data"
reference around to ensure the ctypes object (and thus the underlying
buffer) stays alive, since SetData just points to your data block.

One note - the ctypes-opencv package does define a helper function
"as_c_array" which essentially creates the same array

    >>> from opencv import *
    >>> as_c_array(src, elem_ctype=c_float)
    <__main__.c_float_Array_6 object at 0x009DFE90>

Also, if you use the cvMat constructor with ctypes-opencv in lieu of
the CreateMatHeader/SetData combination, as in:

    >>> xy = cvMat(len(src)/2, 2, CV_32FC1, data)

then ctypes-opencv will automatically hold a reference to the data
object for you.

-- David

Loading...