1

好的,我尝试了这种从外部翻译的方法,它确实有效

(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 

但我喜欢翻译外国定义方法的想法

所以我想知道您是否可以向我展示如何将以下方法的翻译成外文版本,这真的会让我的图书馆很棒

(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 函数之外的另一种方法,因为这是 2 年前 cl-opencv https://github.com/ryepup/cl-opencv第一次问世时制作的,我想做比这更好的包装器...我已经使用 cl-opencv 添加了 100 个新函数 5000 行代码示例和文档以及一个新的 structs.lisp 文件,所以如果有人可以帮助我使用所有最新的 cffi 工具,我会很高兴所以我可以做除 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)

我很欣赏翻译成外来函数,但旧的从外来翻译函数不起作用,因为 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 指针输出

这是关于 cvGetSize 函数的文档,我正在包装

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 指针并得到未处理的内存故障错误

如果你能帮我弄清楚如何写兼容

外文翻译

翻译成外文功能我将非常感激=)。

但是如果我在其中的任何位置使用 make-size 或 size-width,height ,那么 create-image 必须在其中包含 size->int64 ,因为它们仅因为该功能而起作用。

4

3 回答 3

1

2016 年 10 月 12 日更新

这是一个更好且非常简单的演示!

您只需添加:class xxxthen cffi:defcstruct(cffi:defmethod translate-into-foreign-memory (object (type xxx) pointer) yyyy)它会自动将结构按值传递给外部函数!惊人的!!

并将(cffi:defmethod translate-from-foreign (pointer (type xxx)) zzzz)返回的结构数据转换为lisp数据。

好的,这里是代码:

(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)。

注意:(:simple-parser %cv-size)表示您可以将%cv-size返回类型参数类型:pointer :int置于cffi: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-foreigntranslate-into-foreign-memory(或translate-to-foreign):

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

编辑:关于您defcfun的 s 的一些注释。

defcfun我认为forcvGetSize应该将参数声明为(:pointer cv-arr)。我不知道如何cv-arr声明。

defcfunforcvCreateImage应该通过 a而(:struct cv-size)不是:int64。前者应该在所有平台上都是正确的,而后者可能在int非 32 位、字段对齐使结构不紧凑以及结构的总大小可能与sizeof(int) + sizeof(int).

仍然在cvCreateImage,它应该返回 a (:pointer ipl-image),虽然我不确定当类型不是直接时结构是按值处理还是按指针处理(:struct <name>)。最好在 CFFI 邮件列表中查看这一点,或者在#lisp @ irc.freenode.net 中聊天。

于 2013-10-02T13:05:39.607 回答
0

这应该与您的translate-from-foreign方法定义完全相反。我现在无法测试它,但你可能想试试它是否有效:

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

正如另一个答案正确指出的那样,您绝对必须更改from tosize中的类型,否则不会调用此方法。defcfun:int64(:struct cv-size)

于 2013-10-02T15:09:27.747 回答