1

わかりました、このtranslate-from-foreignメソッドを試してみましたが、うまくいきました。これらはライブラリのstructs.lispファイルで定義されており、他のすべての依存関係の前に最初にロードされます

(cffi:defcstruct (cv-size :class cv-size-type)
  (width :int)
  (height :int))

(defmethod cffi:translate-from-foreign (p (type cv-size-type))
  (let ((plist (call-next-method)))
    (make-size :width (getf plist 'width)
               :height (getf plist 'height))))

CvGetSize と cvCreateImage、get-size と create-image の私の opencv ラッパーは、次のように定義されています。

;; CvSize cvGetSize(const CvArr* arr)
 (cffi:defcfun ("cvGetSize" get-size) (:struct cv-size)
   (arr cv-arr))

 ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
 (cffi:defcfun ("cvCreateImage" %create-image) ipl-image
   (size :int64)
   (depth :int)
   (channels :int))

 (defun create-image (size depth channels)
   "Create an image with dimensions given by SIZE, DEPTH bits per
 channel, and CHANNELS number of channels."
   (let ((nsize (size->int64 size)))
     (%create-image nsize depth channels)))

これが size->int64 の定義です

(DEFUN SIZE->INT64 (S) (+ (SIZE-WIDTH S) (ASH (SIZE-HEIGHT S) 32)))

 it converts get-size output which is a structure here:

#S(SIZE :WIDTH 640 :HEIGHT 480)

into 64-bit integer, which CFFI can handle 

でも私は translate-foreign defmethod のアイデアが大好きです

だから私はあなたが私のライブラリを本当に素晴らしいものにする方法から以下の外国語への翻訳バージョンを作る方法を示すことができるかどうか疑問に思っていました

(defmethod cffi:translate-from-foreign (p (type cv-size-type))
  (let ((plist (call-next-method)))
    (make-size :width (getf plist 'width)
               :height (getf plist 'height))))

私は何かを試して追加するつもりでしたが、get-size 出力構造の場合、それは plist ではないので、何をそこに置くべきか本当にわかりません

(let ((plist (call-next-method)))

一部、

  (make-size :width (getf plist 'width)
               :height (getf plist 'height))))

一部、 size->64 関数以外の別の方法を見つけたいと思っていました。これは、cl-opencv https://github.com/ryepup/cl-opencvが最初に出た2年前に作成されたものであり、作成したいそれよりも優れたラッパー...私はすでに cl-opencv を使用して、100 個の新しい関数、5000 行のコード サンプルとドキュメント、および新しい structs.lisp ファイルを追加しました。だから私はint64以外のことをすることができました...さらに、int64がうまくいかない場所をラップする関数があれば、準備ができています

SO のすべての回答者に感謝します。皆さんは本当に私のライブラリを大きく助けてくれました。

編集

わかりました、マデイラ氏としてすべてを以下のように定義したと思います(replセッションを示します)

 CL-OPENCV> 
 ;; (cffi:foreign-type-size '(:struct cv-size)) = 8
 (cffi:defcstruct (cv-size :class cv-size-type)
   (width :int)
   (height :int))



 (defmethod cffi:translate-from-foreign (p (type cv-size-type))
   (let ((plist (call-next-method)))
     (make-size :width (getf plist 'width)
                :height (getf plist 'height))))

 (defmethod cffi:translate-to-foreign (value (type cv-size-type))
   (let ((plist ()))
     (setf (getf plist 'width) (size-width value)
           (getf plist 'height) (size-height value))
     (call-next-method plist type)))



 ;; CvSize cvGetSize(const CvArr* arr)
 (cffi:defcfun ("cvGetSize" get-size) (:struct cv-size)
   (arr (:pointer cv-arr)))


 ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
 (cffi:defcfun ("cvCreateImage" create-image) (:pointer (:struct  ipl-image))
   (size (:struct cv-size))
   (depth :int)
   (channels :int))


 STYLE-WARNING: redefining CL-OPENCV:GET-SIZE in DEFUN
 STYLE-WARNING: redefining CL-OPENCV:CREATE-IMAGE in DEFUN
 CREATE-IMAGE
 CL-OPENCV> (defparameter capture (create-camera-capture 0))
 (defparameter frame (query-frame capture))
 (defparameter img-size (get-size frame))
 (defparameter img (create-image img-size +ipl-depth-8u+ 3))

しかし、私はエラーが発生します

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION
    CFFI:TRANSLATE-INTO-FOREIGN-MEMORY (5)>
when called with arguments
  (#S(SIZE :WIDTH 640 :HEIGHT 480) #<CV-SIZE-TYPE CV-SIZE>
   #.(SB-SYS:INT-SAP #X7FFFE5427FF0)).
   [Condition of type SIMPLE-ERROR]

私が持っているtranslate-from-foreign関数は、cv-sizeからの出力を構造体に変換しているためです

CL-OPENCV> img-size
#S(SIZE :WIDTH 640 :HEIGHT 480)

translate-in-to-foreign 関数には感謝していますが、古い translate-from-foreign 関数では、make-size 部分のために機能しません... cvCreateImage がそれを満たすために必要なものを理解するのを手伝ってくれませんか ....これがリンク4です:

http://docs.opencv.org/modules/core/doc/old_basic_structures.html?highlight=eimage#createimage

以下のこのバージョンを取得して正しく実行できます(replセッションを表示します)

 5
 CL-OPENCV> ; TODO SIZE-WIDTH AND HEIGHT
 ;; CvSize cvGetSize(const CvArr* arr)
 (cffi:defcfun ("cvGetSize" get-size) (:pointer (:struct cv-size))
   (arr cv-arr))


 ;; IplImage* cvCreateImage(CvSize size, int depth, int channels)
 (cffi:defcfun ("cvCreateImage" create-image) (:pointer (:struct ipl-image))
   (size (:pointer (:struct cv-size)))
   (depth :int)
   (channels :int))

 STYLE-WARNING: redefining CL-OPENCV:GET-SIZE in DEFUN
 STYLE-WARNING: redefining CL-OPENCV:CREATE-IMAGE in DEFUN
 CREATE-IMAGE
 CL-OPENCV> (defparameter capture (create-camera-capture 0))
 (defparameter frame (query-frame capture))
 (defparameter img-size (get-size frame))
 (defparameter img (create-image img-size +ipl-depth-8u+ 3))
 IMG
 CL-OPENCV> (cffi:with-foreign-slots ((n-size id n-channels 
                           alpha-channel depth color-model 
                           channel-seq data-order origin  
                           align width height roi 
                           mask-roi image-id tile-info 
                           image-size image-data width-step 
                           border-mode border-const image-data-origin) 

                           img(:struct ipl-image))
                           (format t "n-size = ~a~%id = ~a~%n-channels = ~a~%alpha-channel = ~a~%depth = ~a~%color-model = ~a~%channel-seq = ~a~%data-order = ~a~%origin = ~a~%align = ~a~%width = ~a~%height = ~a~%roi = ~a~%mask-roi = ~a~%image-id = ~a~%tile-info = ~a~%image-size = ~a~%image-data = ~a~%width-step = ~a~%border-mode = ~a~%border-const = ~a~%image-data-origin = ~a~%" 
                           n-size id n-channels 
                           alpha-channel depth color-model 
                           channel-seq data-order origin  
                           align width height roi 
                           mask-rOI image-id tile-info 
                           image-size image-data width-step 
                           border-mode border-const image-data-origin))
 n-size = 144
 id = 0
 n-channels = 3
 alpha-channel = 0
 depth = 8
 color-model = 4343634
 channel-seq = 5392194
 data-order = 0
 origin = 0
 align = 4
 width = 640
 height = 480
 roi = #.(SB-SYS:INT-SAP #X00000000)
 mask-roi = #.(SB-SYS:INT-SAP #X00000000)
 image-id = #.(SB-SYS:INT-SAP #X00000000)
 tile-info = #.(SB-SYS:INT-SAP #X00000000)
 image-size = 921600
 image-data = 
 width-step = 1920
 border-mode = #.(SB-SYS:INT-SAP #X00000000)
 border-const = #.(SB-SYS:INT-SAP #X00000000)
 image-data-origin = NIL
 NIL

だから私はipl-imageのスロットからデータを取得しますが、idはget-sizeによってcv-size poiner出力を逆参照できる必要があるため、これは正しい方法のようには見えません

ここに cvGetSize 関数 im ラッピングに関するドキュメントがあります

http://docs.opencv.org/modules/core/doc/old_basic_structures.html?highlight=eimage#getsize

あなたが見ることができるように、それはポインタです

CL-OPENCV> img-size
#.(SB-SYS:INT-SAP #X1E000000280)

だから私がするとき:

  (cffi:with-foreign-object (img-size '(:pointer (:struct cv-size)))
            ;; Initialize the slots

            ;; Return a list with the coordinates
            (cffi:with-foreign-slots ((width height) img-size 

              (list width height)))

私は得る

 There is no applicable method for the generic function
   #<STANDARD-GENERIC-FUNCTION CFFI::SLOTS (1)>
 when called with arguments
   (#<CFFI::FOREIGN-POINTER-TYPE (:POINTER (:STRUCT CV-SIZE))>).
    [Condition of type SIMPLE-ERROR]     

そして私がするとき

 (cffi:with-foreign-object (img-size '(:struct cv-size))
      ;; Initialize the slots

      ;; Return a list with the coordinates
      (cffi:with-foreign-slots ((width height) img-size (:struct cv-size))
        (list width height)))

私は得る

(346539 0)

無意味な出力

ポインターを mem-refing および mem-arefing しようとすると、未処理のメモリ障害エラーが発生します

互換性のある書き込み方法を理解するのを手伝ってもらえれば

外国語からの翻訳

translate-to-foreign 関数私は非常に感謝しています =)。

しかし、make-size または size-width,height をそれらのどこでも使用する場合、create-image には size->int64 が含まれている必要があります。

4

3 に答える 3

1

2016-10-12 更新

これは、はるかに優れた非常にシンプルなデモです。

thenに追加するだけ:class xxxで、構造体を値で外部関数に自動的に渡します!! すばらしい!!cffi:defcstruct(cffi:defmethod translate-into-foreign-memory (object (type xxx) pointer) yyyy)

そして(cffi:defmethod translate-from-foreign (pointer (type xxx)) zzzz)、返された構造データを Lisp データに変換します。

OK、コードは次のとおりです。

(defcstruct (%CvSize :class cv-size)
  (width :int)
  (height :int))
(defmethod translate-into-foreign-memory (object (type cv-size) pointer)
  (with-foreign-slots ((width height) pointer (:struct %CvSize))
    ;; After this declare this method, you could just pass a two member
    ;;   list as a (:struct %CvSize)
    (setf width (nth 0 object))
    (setf height (nth 1 object))))
(defmethod translate-from-foreign (pointer (type cv-size))
  (with-foreign-slots ((width height) pointer (:struct %CvSize))
    ;; You can change this and get return value in other format
    ;; for example: (values width height)
    (list width height)))
(defcfun ("cvGetSize" %cvGetSize)
    (:struct %CvSize) ;; Here must use (:struct xxx)
  "C: CvSize cvGetSize(const CvArr* arr)"
  (arr :pointer))
(defcfun ("cvCreateImage" %cvCreateImage)
    %IplImage
  "C: IplImage* cvCreateImage(CvSize size, int depth, int channels)"
  (size (:struct %CvSize)) ;; Here must use (:struct xxx)
  (depth %IPL_DEPTH)
  (channels :int))

のテスト コード%cvGetSize:

(defmacro with-pointer-to-pointer ((var pointer) &body body)
  `(with-foreign-object (,var :pointer)
     (setf (mem-ref ,var :pointer)
           ,pointer)
     (progn ,@body)))
(defun release-image (image)
  (with-pointer-to-pointer (pointer image)
    (%cvReleaseImage pointer)))
(defmacro with-load-image ((var filename &optional (iscolor :%CV_LOAD_IMAGE_COLOR)) &body body)
  "Wrap %cvLoadImage and make sure %cvReleaseImage."
  (let ((result (gensym)))
    `(let ((,var (%cvLoadImage ,filename ,iscolor))
           ,result)
       (unwind-protect
            (setf ,result
                  (multiple-value-list (progn ,@body)))
         (release-image ,var))
       (values-list ,result))))
(defun image-width-height (filename)
  (with-load-image (image filename)
    (%cvGetSize image)))
(image-width-height "/path/to/image.jpg")
;;=>
;; (962 601)

注: 戻り値はもはやポインターや奇妙なものではなく、リストを返します (コードを変更して(cffi:defmethod translate-from-foreign () xxxx)、戻り値を他の型に変換することができます。

のテスト コード%cvCreateImage:

(%cvCreateImage (list 480 640)) 

注:ええ!リストを渡すだけで、自動的に (:struct %CvSize) に変換されます! いいですよね?もう他の奇妙なコードを使用する必要はありませmake-instanceん^_^

注:原因としてcffi:define-foreign-libraycffi:use-foreign-library最初に次のようにする必要があります:

(cffi:define-foreign-library opencv-highgui
  (:darwin (:or "libopencv_highgui.dylib"))
  (:linux (:or "libhighgui.so"
               "libopencv_highgui.so"))
  (t (:default "libhighgui")))

(cffi:use-foreign-library opencv-highgui)



以下の古い回答(この醜い解決策は無視してください!)

コードは次のとおりです。

(cffi:define-foreign-type cv-size ()
  ((width :reader width :initarg :width)
   (height :reader height :initarg :height))
  (:actual-type :int64)
  (:simple-parser %cv-size))
(defmethod translate-to-foreign (value (type cv-size))
  (+ (width value)
     (ash (height value) 32)))
(defmethod translate-from-foreign (value (type cv-size))
  (values (- value
             (ash (ash value -32) 32))
          (ash value -32)))
(cffi:defcfun ("cvGetSize" %cvGetSize)
    %cv-size
  "C: CvSize cvGetSize(const CvArr* arr)"
  (arr :pointer))
(cffi:defcfun ("cvCreateImage" %cvCreateImage)
    %IplImage
  "C: IplImage* cvCreateImage(CvSize size, int depth, int channels)"
  (size %cv-size)
  (depth %IPL_DEPTH)
  (channels :int))

注:(:actual-type :int64)の実際の型cv-size:int64(C int64) であることを意味します。

注:は、 do inのようにreturn-typeまたはparameter-type(:simple-parser %cv-size)に配置できることを意味します。宣言とをご覧ください。%cv-size:pointer :intcffi:defcfun%cvGetSize%cvCreateImage

のテスト コード%cvGetSize:

(defmacro with-pointer-to-pointer ((var pointer) &body body)
  `(with-foreign-object (,var :pointer)
     (setf (mem-ref ,var :pointer)
           ,pointer)
     (progn ,@body)))
(defun release-image (image)
  (with-pointer-to-pointer (pointer image)
    (%cvReleaseImage pointer)))
(defmacro with-load-image ((var filename &optional (iscolor :%CV_LOAD_IMAGE_COLOR)) &body body)
  "Wrap %cvLoadImage and make sure %cvReleaseImage."
  (let ((result (gensym)))
    `(let ((,var (%cvLoadImage ,filename ,iscolor))
           ,result)
       (unwind-protect
            (setf ,result
                  (multiple-value-list (progn ,@body)))
         (release-image ,var))
       (values-list ,result))))
(defun image-width-height (filename)
  (with-load-image (image filename)
    (%cvGetSize image)))
(image-width-height "/path/to/image.jpg")
;;=>
;; 962
;; 601

のテスト コード%cvCreateImage:

(%cvCreateImage (make-instance 'cv-size
                               :width 480
                               :height 640))

注:原因としてcffi:define-foreign-libraycffi:use-foreign-library最初に次のようにする必要があります:

(cffi:define-foreign-library opencv-highgui
  (:darwin (:or "libopencv_highgui.dylib"))
  (:linux (:or "libhighgui.so"
               "libopencv_highgui.so"))
  (t (:default "libhighgui")))

(cffi:use-foreign-library opencv-highgui)
于 2016-10-09T09:57:40.177 に答える
0

CFFI のコードで私が確認できることから、独自のtranslate-from-foreignand translate-into-foreign-memory(or translate-to-foreign)を定義する代わりに、トップレベルのフォームとして次を使用できます。

(cffi:translation-forms-for-class cv-size cv-size-type)

編集:あなたの s に関するいくつかのメモdefcfun

defcfunforはcvGetSize、引数を として宣言する必要がある(:pointer cv-arr)と思います。cv-arrどのように宣言されているかわかりません。

defcfunforはの代わりにcvCreateImagea を渡す必要があります。前者はすべてのプラットフォームで正しいと想定されていますが、後者は が32 ビットでない場所、フィールド アラインメントによって構造体がコンパクトにならない場所、および構造体の合計サイズが と異なる可能性がある場所では機能しない可能性があります。(:struct cv-size):int64intsizeof(int) + sizeof(int)

型が直接ではない場合、構造体が値またはポインターによって処理されるかどうかはわかりませんが、それでも をcvCreateImage返す必要があります。これについては、CFFI メーリング リストで確認するか、#lisp @ irc.freenode.net でチャットしてください。(:pointer ipl-image)(:struct <name>)

于 2013-10-02T13:05:39.607 に答える