我正在尝试在 Racket 中编写 OpenCV FFI 并到达需要有效操作数组的地步。但是,我使用 Racket FFI 访问数组的所有尝试都导致代码效率非常低。有没有办法使用 FFI 快速访问 C 数组?
在 Racket 中,这种类型的操作相当快,即:
(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
,如下所示:
typedef struct _IplImage
{
int imageSize; /* sizeof(IplImage) */
...
char *imageData; /* Pointer to aligned image data.*/
}IplImage;
该结构在 Racket 中定义如下:
(define-cstruct _IplImage
([imageSize _int]
...
[imageData _pointer]))
cvLoadImage
现在我们使用如下函数加载图像:
(define img
(ptr-ref
(cvLoadImage "images/test-image.png" CV_LOAD_IMAGE_COLOR)
_IplImage))
imageData
可以通过以下方式访问指针:(define data (IplImage-imageData img)))
现在,我们要操作data
,而我能想到的最有效的方法是使用指针:
(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。
有一个更好的方法吗?