这是一个非常具体的问题,但是困扰我好几天了。我正在尝试使用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,但是元素是四边形而不是检测形式的结构),我不了解。
由于我已经在此问题上花了几天的时间,任何帮助都将不胜感激!
问题可能是这样:
quad = ctypes.POINTER(_Quad)()
zarray_get(quads, i, ctypes.byref(quad))
第一行创建一个指向_Quad
类型的位置的指针。它是一个空指针。您真正想要的是执行此操作:
quad = _Quad()
zarray_get(quads, i, ctypes.byref(quad))