2012-05-08 78 views
3

我想在球拍中編寫OpenCV FFI併到達需要有效操縱數組的點。但是,我所有使用Racket FFI訪問陣列的嘗試都導致代碼非常低效。有沒有辦法使用FFI快速訪問C數組?使用球拍快速陣列訪問FFI

球拍,這種類型的操作是相當快的,即:現在

(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; 

的結構是在球拍中定義如下:

(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。然後,可以將球拍程序傳遞給它並應用於數組的所有元素。速度與指針相同,但仍然不足以繼續將OpenCV庫移植到Racket。

有沒有更好的方法來做到這一點?

回答

4

我試過了Eli建議的方法,它解決了!這個想法是使用一個字節串。因爲在這種情況下,數組的大小是已知的,(make-sized-byte-string cptr length)可用於:

(define data (make-sized-byte-string (IplImage-imageData img) 
            (* width height channels))) 

這導致接近球拍的原始載體的運行時間:

(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 

謝謝你,伊萊。

+0

:)似乎在郵件列表上張貼對其他人也有幫助... –

2

它可能會更好地設置使用字節串(通過_bytes)整個事情,但這是一個非常粗略的猜測。在郵件列表上問這個問題會好得多...

+0

我在Racket'users'郵件列表上轉發了這個問題。 –

+0

嗯,似乎沒有人回覆郵件列表。在這種情況下我如何使用字節串? –