Hello everyone,

I am trying to write OpenCV FFI in Racket and arrived at a point where arrays 
need to be manipulated efficiently. However, all my attempts to access arrays 
by using Racket FFI resulted in very inefficient code. Is there a way for fast 
access of C arrays using FFI?

In Racket, this type of manipulation is reasonably fast, i.e.:

    (define a-vector (make-vector (* 640 480 3)))
    (time (let loop ([i (- (* 640 480 3) 1)])
        (when (>= i 0)
          ;; invert each pixel channel-wise
          (vector-set! a-vector i (- 255 (vector-ref a-vector i)))
          (loop (- i 1)))))
    ->  cpu time: 14 real time: 14 gc time: 0

Now, in OpenCV, there is a struct called `IplImage` that looks like this:

    typedef struct _IplImage
    {
        int  imageSize;             /* sizeof(IplImage) */
        ...
        char *imageData;        /* Pointer to aligned image data.*/
    }IplImage;
The struct is defined in Racket as follows:

    (define-cstruct _IplImage
        ([imageSize _int]
         ...
         [imageData _pointer]))

Now we load an image using `cvLoadImage` function as follows:

    (define img
      (ptr-ref
       (cvLoadImage "images/test-image.png" CV_LOAD_IMAGE_COLOR)
       _IplImage))

The pointer `imageData` can be accessed by: `(define data (IplImage-imageData 
img)))`

Now, we want to manipulate `data`, and the most efficient way I could come up 
with was by using pointers:

    (time (let loop ([i (- (* width height channels) 1)]) ;; same 640 480 3
        (when (>= i 0)
          ;; invert each pixel channel-wise
          (ptr-set! data _ubyte i (- 255 (ptr-ref data _ubyte i)))
          (loop (- i 1)))))
    -> cpu time: 114 real time: 113 gc time: 0

This is very slow, compared to the speed of native Racket vectors.
I also tried other ways, such as `_array`, `_cvector` that don't even come 
close to the speed of using pointers, except for writing a first-class function 
in C that gets a function for running over the whole array. This C function is 
compiled to a library and bound in Racket using FFI. Then, Racket procedures 
can be passed to it and applied to all elements of the array. The speed was the 
same as with pointers, but still not sufficient to continue porting OpenCV 
library to Racket.

Is there a better way to do this?

Regards,
Petr
____________________
  Racket Users list:
  http://lists.racket-lang.org/users

Reply via email to