Need help accessing nested struct pointers in CFFI?

Discussion of Common Lisp
Post Reply
joeish80829
Posts: 153
Joined: Tue Sep 03, 2013 5:32 am

Need help accessing nested struct pointers in CFFI?

Post by joeish80829 » Mon Oct 07, 2013 8:27 am

I do apoligize if i added to much code on this....it just seems difficult to explain without showing all the code involve. pls let me know if this isnt worded right to community guidelines and i'll edit it....pls be precise so i know what to change..

here is how the struct CvSeq is defined

Code: Select all

[#define CV_TREE_NODE_FIELDS(node_type)                               \
    int       flags;             /* Miscellaneous flags.     */      \
    int       header_size;       /* Size of sequence header. */      \
    struct    node_type* h_prev; /* Previous sequence.       */      \
    struct    node_type* h_next; /* Next sequence.           */      \
    struct    node_type* v_prev; /* 2nd previous sequence.   */      \
    struct    node_type* v_next  /* 2nd next sequence.       */

/*
   Read/Write sequence.
   Elements can be dynamically inserted to or deleted from the sequence.
*/
#define CV_SEQUENCE_FIELDS()                                              \
    CV_TREE_NODE_FIELDS(CvSeq);                                           \
    int       total;          /* Total number of elements.            */  \
    int       elem_size;      /* Size of sequence element in bytes.   */  \
    schar*    block_max;      /* Maximal bound of the last block.     */  \
    schar*    ptr;            /* Current write pointer.               */  \
    int       delta_elems;    /* Grow seq this many at a time.        */  \
    CvMemStorage* storage;    /* Where the seq is stored.             */  \
    CvSeqBlock* free_blocks;  /* Free blocks list.                    */  \
    CvSeqBlock* first;        /* Pointer to the first sequence block. */

typedef struct CvSeq
{
    CV_SEQUENCE_FIELDS()
}
CvSeq;
and here is how i ended up wrapping it.


Code: Select all

[;; (cffi:foreign-type-size '(:struct cv-seq)) = 96
(cffi:defcstruct cv-seq
    (flags :int)
    (header-size :int)
    (h-prev :pointer)
    (h-next :pointer)
    (v-prev :pointer)
    (v-next :pointer)
    (total :int)
    (elem-size :int)
    (block-max :pointer)
    (ptr :pointer)
    (delta-elems :int)
    (storage :pointer)
    (free-blocks :pointer)
    (first :pointer))
I was curious what to do with the h_next h_prev and v_prev and v_next, they seem to be recursive and they are not working or i am not using them right normally when a struct contains a member like CvMemStorage* storage; I wrap it like this (:pointer (:struct cv-mem-storage)) and it works but h_next i/e seems to point back to itself


this is the way the h_next struct member works in c. in the below code while contours is not null it iterates though a while loop and through every iteration it sets the variable contours to the next pointer stored in h_next which is set by the cvFindContours function. the cvFindContours fubction in c adds a pointer to the h_next member of the CvSeq struct for every item in the picture it finds...pls see below link for more details and example picture (trying 2 keep this short) ...

the code i got the below snippet from is the first program on this page.....http://opencv-srf.blogspot.com/2011/09/ ... tours.html (i broke it down so it would be easier to understand)


Code: Select all

[int main()
{

IplImage* img =  cvLoadImage("/home/w/quicklisp/dists/quicklisp/software/cl-opencv-master/images/FindingContours.png");
//converting the original image into grayscale
IplImage* imgGrayScale = cvCreateImage(cvGetSize(img), 8, 1);
CvMemStorage *storage = cvCreateMemStorage(0); //storage area for all contours
 CvSeq* contours= cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
//finding all contours in the image
cvFindContours(imgGrayScale, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
//iterating through each contour
while(contours)
{cout << "contours = " << endl << " " << contours << endl << endl;
//obtain a sequence of points of contour, pointed by the variable 'contour'
contours = contours->h_next;
}
cout << "contours end = " << endl << " " << contours << endl << endl;
return 0;
}
when i convert to lisp(below ...i didnt add while loop because h-next is null), i use nested with-foreign-slots to access the h-next member for debugging. it is a null pointer where in the c code above the h_next member is full of data...the function does work though....it works as good as it does in c

Code: Select all

[(let* ((img (load-image "/home/w/quicklisp/dists/quicklisp/software/cl-opencv-master/images/FindingContours.png" 1))
       (img-size (get-size img))            
       (img-grayscale (create-image img-size +ipl-depth-8u+ 1))
       (storage (create-mem-storage 0))
       ( contours (create-seq +seq-eltype-point+ (cffi:foreign-type-size '(:struct cv-seq))
                 (cffi:foreign-type-size '(:struct cv-point)) storage)))
      (find-contours img-grayscale  storage contours
             (cffi:foreign-type-size '(:struct cv-contour)) +retr-list+
             +chain-approx-simple+ (make-cv-point :x 0 :y 0))
    
      (cffi:with-foreign-slots ((h-next)
                  contours   (:struct cv-seq))
   
    (cffi:with-foreign-slots ((h-next)
                  h-next (:struct cv-seq))
     
            h-next)
   
          ))

just outputs a null-pointer>> #.(SB-SYS:INT-SAP #X00000000)

any help on this would be appreciated?

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: Need help accessing nested struct pointers in CFFI?

Post by Goheeca » Mon Oct 07, 2013 9:09 am

As far as i know, there is no clear way how to do it. I'd approach it in this sense:

Code: Select all

(cffi:defcstruct linked-list
  (element :pointer)
  (next :pointer))

;; struct redefining
(cffi:defcstruct linked-list
  (element :pointer)
  (next (:pointer (:struct linked-list))))
It is theoretically bad, if a size of pointer depends on the shape of struct (on a very obscure platform, but I don't know any case of this and one iteration of redefining is sufficient).
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

joeish80829
Posts: 153
Joined: Tue Sep 03, 2013 5:32 am

Re: Need help accessing nested struct pointers in CFFI?

Post by joeish80829 » Mon Oct 07, 2013 9:39 am

I'm still kind of new to cffi ....could you show me an example based on the code i uploaded

I added wrong struct.btw before..i've been using this

Code: Select all

(cffi:defcstruct cv-seq
	(flags :int)
	(header-size :int)
	(h-prev (:pointer (:struct cv-seq)))
	(h-next (:pointer (:struct cv-seq)))
	(v-prev (:pointer (:struct cv-seq)))
	(v-next (:pointer (:struct cv-seq)))
	(total :int)
	(elem-size :int)
	(block-max schar-ptr)
	(ptr schar-ptr)
	(delta-elems :int)
	(storage (:pointer (:struct cv-mem-storage)))
	(free-blocks (:pointer (:struct cv-seq-block)))
	(first (:pointer (:struct cv-seq-block))))

just still keep getting null-pointer for h-next

Goheeca
Posts: 271
Joined: Thu May 10, 2012 12:54 pm
Contact:

Re: Need help accessing nested struct pointers in CFFI?

Post by Goheeca » Mon Oct 07, 2013 10:28 am

The problem is that you can't use an identifier of struct which is being defined right now so I ilustrated how to approach to this problem. The null-pointer is another one and anyone can't say why it's happening. As I stated earlier, without possibility to try your code hardly someone answers it.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

joeish80829
Posts: 153
Joined: Tue Sep 03, 2013 5:32 am

Re: Need help accessing nested struct pointers in CFFI?

Post by joeish80829 » Mon Oct 07, 2013 10:35 am

i found the answer thx anyway 4 your help....here is how i ended up calling it

Code: Select all

;; (cffi:foreign-type-size '(:struct cv-seq)) = 96
(cffi:defcstruct cv-seq
	(flags :int)
	(header-size :int)
	(h-prev :pointer)
	(h-next :pointer)
	(v-prev :pointer)
	(v-next :pointer)
	(total :int)
	(elem-size :int)
	(block-max :pointer)
	(ptr :pointer)
	(delta-elems :int)
	(storage :pointer)
	(free-blocks :pointer)
	(first :pointer))

(cffi:defcfun ("cvFindContours" %find-contours) :int
  (image cv-arr)
  (storage (:pointer (:struct cv-mem-storage)))
  (first-contour (:pointer (:pointer (:struct cv-seq))))
  (header-size :int)
  (mode :int)
  (method :int)
  (offset :int64))

(defun find-contours (image storage first-contour &optional (header-size (cffi:foreign-type-size '(:struct cv-contour))) 
		      (mode +retr-list+) (method +chain-approx-simple+) (offset (make-cv-point :x 0 :y 0)))
  (let ((noffset (cv-point->int64 offset)))
    (%find-contours image storage first-contour header-size mode method noffset)))

Post Reply