c - 我如何编写可比较的 cffi :translate-into foreign defmethod for this cffi:translate-from-foreign?

标签 c opencv struct common-lisp cffi

好的,我尝试了这种从外国翻译过来的方法,它确实有效 我在我的库中的 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 函数之外的另一种方法,因为它是 2 年前在 cl-opencv https://github.com/ryepup/cl-opencv 时制作的。第一次出来 我想制作一个比这更好的包装器...我已经使用 cl-opencv 添加了 100 个新函数 5000 行代码示例和文档以及一个新的 structs.lisp 文件所以如果有人可以帮助我我会很高兴所有最新的 cffi 工具,所以我可以做除 int64 之外的其他事情...加上如果我有一个函数来包装 int64 东西不起作用的地方我准备好

再次感谢 S.O. 上的所有回答者。你们真的对我的图书馆帮助很大。

编辑

好吧,我想我把一切都定义为你 Madeira 先生如下(我展示了 repl session )

 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]

因为我的外来翻译函数正在转换 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 session )

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

如果你能帮我弄清楚怎么写compatible

从国外翻译

翻译成外国函数我会非常感激=)。

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

最佳答案

2016-10-12更新

这里有一个更好而且非常简单的演示!

你只需要添加 :class xxxcffi: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 放置到 return-type 或 < strong>parameter-type like :pointer :int do in 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)

关于c - 我如何编写可比较的 cffi :translate-into foreign defmethod for this cffi:translate-from-foreign?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19133763/

相关文章:

c++ - 我们如何将嵌套的 if else 与 #define 预处理器一起使用

c++ - 如何调用模拟另一个用户而不是 SYSTEM 的函数

c++ - OpenCV c++ 示例到 iOS 项目

c - 通过函数传递结构时收到警告

c++ - 结构不可分配?

c - 如何将 "const char * "的内容写入文本文件?

c++ - 如何在 OpenCV 中读取 ".jpg"图像序列?

c++ - OpenCV 找不到图像

c - 如何使用 C 中的结构创建数据库

c++ - 美化 clang -v 输出