ctypes结构访问元素中的段错误

问题描述 投票:-3回答:1

这是一个非常具体的问题,但是困扰我好几天了。我正在尝试使用ctypes库从python访问C函数apriltag_quad_detector_detect的返回值,但是遇到了问题。返回值为zarray_t,其中包含quad结构的数组。每个四边形定义为

struct quad
{
float p[4][2]; // corners

bool reversed_border;

// H: tag coordinates ([-1,1] at the black corners) to pixels
// Hinv: pixels to tag
matd_t *H, *Hinv;
};

现在可以访问它,我正在执行以下操作:

class _Quad(ctypes.Structure):
    '''Wraps quad C struct.'''
    _fields_ = [
    ('p', (ctypes.c_float*2)*4),
    ('reversed_border', ctypes.c_bool),
    ('H', ctypes.POINTER(_Matd)),
    ('Hinv', ctypes.POINTER(_Matd))
    ]

def detect_quads(self, img, estimate_tag_pose=False, camera_params=None, tag_size=None):
    '''Run detectons on the provided image. The image must be a grayscale
    image of type numpy.uint8.'''

    assert len(img.shape) == 2
    assert img.dtype == numpy.uint8

    c_img = self._convert_image(img)

    return_info = []

    #detect apriltags in the image
    self.libc.apriltag_quad_detector_detect.restype = ctypes.POINTER(_ZArray)
    quads = self.libc.apriltag_quad_detector_detect(self.tag_detector_ptr, c_img)

    # Declare a pointer to a quad
    quad = ctypes.POINTER(_Quad)()

    for i in range(0, quads.contents.size):

        # extract the data for each apriltag that was identified
        zarray_get(quads, i, ctypes.byref(quad))
        quad_res = quad.contents
        print(quad_res.reversed_border) # Throws a SetFault
        print(quad_res.p[0][0]) # Also throws a SegFault

我正在调用的C函数在这里:

zarray_t *apriltag_quad_detector_detect(apriltag_detector_t *td, image_u8_t *im_orig)
{
if (zarray_size(td->tag_families) == 0) {
    zarray_t *s = zarray_create(sizeof(apriltag_detection_t*));
    printf("apriltag.c: No tag families enabled.");
    return s;
}

if (td->wp == NULL || td->nthreads != workerpool_get_nthreads(td->wp))         {
    workerpool_destroy(td->wp);
    td->wp = workerpool_create(td->nthreads);
}

timeprofile_clear(td->tp);
timeprofile_stamp(td->tp, "init");

///////////////////////////////////////////////////////////
// Step 1. Detect quads according to requested image decimation
// and blurring parameters.
image_u8_t *quad_im = im_orig;
if (td->quad_decimate > 1) {
    quad_im = image_u8_decimate(im_orig, td->quad_decimate);

    timeprofile_stamp(td->tp, "decimate");
}

if (td->quad_sigma != 0) {
    // compute a reasonable kernel width by figuring that the
    // kernel should go out 2 std devs.
    //
    // max sigma          ksz
    // 0.499              1  (disabled)
    // 0.999              3
    // 1.499              5
    // 1.999              7

    float sigma = fabsf((float) td->quad_sigma);

    int ksz = 4 * sigma; // 2 std devs in each direction
    if ((ksz & 1) == 0)
        ksz++;

    if (ksz > 1) {

        if (td->quad_sigma > 0) {
            // Apply a blur
            image_u8_gaussian_blur(quad_im, sigma, ksz);
        } else {
            // SHARPEN the image by subtracting the low frequency components.
            image_u8_t *orig = image_u8_copy(quad_im);
            image_u8_gaussian_blur(quad_im, sigma, ksz);

            for (int y = 0; y < orig->height; y++) {
                for (int x = 0; x < orig->width; x++) {
                    int vorig = orig->buf[y*orig->stride + x];
                    int vblur = quad_im->buf[y*quad_im->stride + x];

                    int v = 2*vorig - vblur;
                    if (v < 0)
                        v = 0;
                    if (v > 255)
                        v = 255;

                    quad_im->buf[y*quad_im->stride + x] = (uint8_t) v;
                }
            }
            image_u8_destroy(orig);
        }
    }
}

timeprofile_stamp(td->tp, "blur/sharp");

if (td->debug)
    image_u8_write_pnm(quad_im, "debug_preprocess.pnm");

zarray_t *quads = apriltag_quad_thresh(td, quad_im);

// adjust centers of pixels so that they correspond to the
// original full-resolution image.
if (td->quad_decimate > 1) {
    for (int i = 0; i < zarray_size(quads); i++) {
        struct quad *q;
        zarray_get_volatile(quads, i, &q);

        for (int j = 0; j < 4; j++) {
            if (td->quad_decimate == 1.5) {
                q->p[j][0] *= td->quad_decimate;
                q->p[j][1] *= td->quad_decimate;
            } else {
                q->p[j][0] = (q->p[j][0] - 0.5)*td->quad_decimate + 0.5;
                q->p[j][1] = (q->p[j][1] - 0.5)*td->quad_decimate + 0.5;
            }
        }
    }
}

if (quad_im != im_orig)
    image_u8_destroy(quad_im);

zarray_t *detections = zarray_create(sizeof(apriltag_detection_t*));

td->nquads = zarray_size(quads);

timeprofile_stamp(td->tp, "quads");

if (td->debug) {
    image_u8_t *im_quads = image_u8_copy(im_orig);
    image_u8_darken(im_quads);
    image_u8_darken(im_quads);

    srandom(0);

    for (int i = 0; i < zarray_size(quads); i++) {
        struct quad *quad;
        zarray_get_volatile(quads, i, &quad);

        const int bias = 100;
        int color = bias + (random() % (255-bias));

        image_u8_draw_line(im_quads, quad->p[0][0], quad->p[0][1], quad->p[1][0], quad->p[1][1], color, 1);
        image_u8_draw_line(im_quads, quad->p[1][0], quad->p[1][1], quad->p[2][0], quad->p[2][1], color, 1);
        image_u8_draw_line(im_quads, quad->p[2][0], quad->p[2][1], quad->p[3][0], quad->p[3][1], color, 1);
        image_u8_draw_line(im_quads, quad->p[3][0], quad->p[3][1], quad->p[0][0], quad->p[0][1], color, 1);
    }

    image_u8_write_pnm(im_quads, "debug_quads_raw.pnm");
    image_u8_destroy(im_quads);
}
printf("Testing. \n");
printf("Size: %d \n", quads->size);
printf("Element Size: %lu \n", quads->el_sz);
printf("Alloc: %d \n", quads->alloc);
for (int i = 0; i < zarray_size(quads); i++) {
    struct quad *quad;
    zarray_get_volatile(quads, i, &quad);
    printf("%d", quad->reversed_border);
    printf("p1: [%f, %f]\n", quad->p[0][0], quad->p[0][1]);
    printf("p2: [%f, %f]\n", quad->p[1][0], quad->p[1][1]);
    printf("p3: [%f, %f]\n", quad->p[2][0], quad->p[2][1]);
    printf("p4: [%f, %f]\n", quad->p[3][0], quad->p[3][1]);
    printf("reversed_border: %i \n", quad->reversed_border);
}
return quads;
}

我正在构建的代码在这里:https://github.com/duckietown/apriltags3-py。我正在尝试基本上复制它们如何与detections中的apriltags3.py对象交互(请查看它们的函数detect以查看我要复制的内容),但是相同的策略似乎不适用于四边形(它也是一个zarray,但是元素是四边形而不是检测形式的结构),我不了解。

由于我已经在此问题上花了几天的时间,任何帮助都将不胜感激!

python c ctypes
1个回答
0
投票

问题可能是这样:

quad = ctypes.POINTER(_Quad)()
zarray_get(quads, i, ctypes.byref(quad))

第一行创建一个指向_Quad类型的位置的指针。它是一个空指针。您真正想要的是执行此操作:

quad = _Quad()
zarray_get(quads, i, ctypes.byref(quad))
© www.soinside.com 2019 - 2024. All rights reserved.