6

私は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に移植し続けるにはまだ十分ではありません。

これを行うためのより良い方法はありますか?

4

2 に答える 2

7

私はエリによって提案されたアプローチを試しました、そしてそれはうまくいきました!アイデアは、バイト文字列を使用することです。この場合、配列のサイズがわかっているので、次(make-sized-byte-string cptr length)を使用できます。

(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

ありがとう、エリ。

于 2012-05-09T00:44:34.940 に答える
4

(を介して)バイト文字列を使用して全体を設定する方がおそらく良いでしょうが_bytes、それは非常に大まかな推測です。メーリングリストでこの質問をする方がはるかに良いでしょう...

于 2012-05-08T01:08:09.803 に答える