Opencv 使用Racket FFI的快速阵列访问

Opencv 使用Racket FFI的快速阵列访问,opencv,racket,ffi,Opencv,Racket,Ffi,我正试图在Racket中编写opencvffi,并达到了一个需要高效操作数组的点。然而,我所有使用Racket FFI访问数组的尝试都导致代码效率非常低。有没有一种使用FFI快速访问C阵列的方法 在球拍中,这种操纵相当快,即: (define a-vector (make-vector (* 640 480 3))) (time (let loop ([i (- (* 640 480 3) 1)]) (when (>= i 0) ;; invert each pixel

我正试图在Racket中编写opencvffi,并达到了一个需要高效操作数组的点。然而,我所有使用Racket FFI访问数组的尝试都导致代码效率非常低。有没有一种使用FFI快速访问C阵列的方法

在球拍中,这种操纵相当快,即:

(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]))
(define img
  (ptr-ref
   (cvLoadImage "images/test-image.png" CV_LOAD_IMAGE_COLOR)
   _IplImage))
现在,我们使用
cvLoadImage
函数加载图像,如下所示:

(define-cstruct _IplImage
    ([imageSize _int]
     ...
     [imageData _pointer]))
(define img
  (ptr-ref
   (cvLoadImage "images/test-image.png" CV_LOAD_IMAGE_COLOR)
   _IplImage))
指针
imageData
可通过以下方式访问:
(定义数据(IplImage imageData img))

现在,我们想要操纵
数据
,我能想到的最有效的方法是使用指针:

(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
与本地球拍矢量的速度相比,这是非常慢的。 我还尝试了其他方法,比如
\u array
\u cvector
,它们甚至都没有达到使用指针的速度,除了用C编写一个一级函数,该函数可以在整个数组中运行。这个C函数被编译到一个库中,并使用FFI绑定到Racket中。然后,可以将Racket过程传递给它并应用于数组的所有元素。速度与指针相同,但仍然不足以继续将OpenCV库移植到Racket


有更好的方法吗?

使用bytestring(通过
\u bytes
)设置整个过程可能会更好,但这是一个非常粗略的猜测。在邮件列表上问这个问题会更好…

我尝试了Eli建议的方法,结果成功了!这个想法是使用bytestring。由于在这种情况下数组的大小是已知的,因此可以使用
(使字节字符串大小为cptr长度)

(define data (make-sized-byte-string (IplImage-imageData img)
                                     (* width height channels)))
这导致运行时间接近Racket的本机向量:

(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
用户
邮件列表上回复了这个问题。嗯,邮件列表上似乎没有人回答。在这种情况下,我如何使用bytestring?你做得很好!我现在的问题是,我们如何支持其他类型(如浮点),以及如何像数组一样访问数据?如果能够依赖类似于Python中使用numpy数组访问opencv图像的Racket数组类型,那就太好了。