使用Racket FFI进行快速阵列访问 [英] Fast array access using Racket FFI

查看:185
本文介绍了使用Racket FFI进行快速阵列访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在Racket中编写OpenCV FFI,并到达需要有效处理数组的地步.但是,我通过使用Racket FFI来访问阵列的所有尝试都导致代码效率非常低下.有没有一种方法可以使用FFI快速访问C阵列?

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

现在,在OpenCV中,有一个名为IplImage的结构,如下所示:

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;

该结构在Racket中的定义如下:

The struct is defined in Racket as follows:

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

现在,我们使用cvLoadImage函数加载图像,如下所示:

Now we load an image using cvLoadImage function as follows:

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

指针imageData可以通过以下方式访问:(define data (IplImage-imageData img)))

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

现在,我们要操纵data,而我想出的最有效的方法是使用指针:

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

与本地Racket向量的速度相比,这非常慢. 我还尝试了其他方法,例如_array_cvector,这些方法甚至都无法接近使用指针的速度,只是用C编写了一个可在整个数组上运行的函数的一流函数.将此C函数编译为一个库,并使用FFI在Racket中绑定.然后,可以将Racket过程传递给它,并将其应用于数组的所有元素.速度与指针相同,但仍不足以继续将OpenCV库移植到Racket.

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.

有更好的方法吗?

推荐答案

我尝试了Eli建议的方法,并且效果很好!这个想法是使用一个字节串.由于在这种情况下,数组的大小是已知的,因此可以使用(make-sized-byte-string cptr length):

I tried the approach suggested by Eli 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)))

这将导致运行时间接近Racket的本地向量:

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

谢谢你,以利.

这篇关于使用Racket FFI进行快速阵列访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆