私はOpenCVFFIをRacketで書き込もうとしていて、アレイを効率的に操作する必要があるポイントに到達しました。ただし、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]))
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
これは、ネイティブのラケットベクトルの速度と比較して非常に遅いです。また、配列全体を実行するための関数を取得するファーストクラスの関数をCで記述することを除いて、ポインターを使用する速度にさえ近づかないなど、他の方法も試し_array
ました。_cvector
このC関数はライブラリにコンパイルされ、FFIを使用してRacketにバインドされます。次に、Racketプロシージャをそれに渡して、配列のすべての要素に適用できます。速度はポインターの場合と同じでしたが、OpenCVライブラリをRacketに移植し続けるにはまだ十分ではありません。
これを行うためのより良い方法はありますか?