I tried the approach suggested by Eli on Stackoverflow, and it worked out! The idea is to use a bytestring. Since in this case the size of the array is known, (make-sized-byte-string cptr length) can be used:
(define data (make-sized-byte-string (IplImage-imageData img) (* width height channels))) This results in run times close to Racket's native vectors: (time (let loop ([i (- (* 640 480 3) 1)]) (when (>= i 0) ;; invert each pixel channel-wise (bytes-set! data i (- 255 (bytes-ref data i))) (loop (- i 1))))) -> cpu time: 18 real time: 18 gc time: 0 Thank you, Eli. On May 8, 2012, at 3:34 PM, Petr Samarin wrote: > 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