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