/* libpng v1.2 insists of loading setjmp.h itself and provides no
configuration to tell it that all will be OK :-((
Inline::C does not provide a way to unshift the #include either :-(((
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "INLINE_CCV.h"
#include "ccv-src/lib/ccv.h"
ccv_sift_param_t* myccv_pack_parameters(int noctaves, int nlevels, int up2x, int edge_threshold, int norm_threshold, int peak_threshold)
{
ccv_sift_param_t* res;
res = malloc(sizeof(*res));
res->noctaves = noctaves;
res->nlevels = nlevels;
res->up2x = up2x;
res->edge_threshold = edge_threshold;
res->norm_threshold = norm_threshold;
res->peak_threshold = peak_threshold;
return res;
}
/* Should this just become a tiearray interface?! */
void myccv_keypoints_to_list(ccv_array_t* keypoints)
{
Inline_Stack_Vars;
Inline_Stack_Reset;
AV* res = newAV();
int i;
for (i = 0; i < keypoints->rnum; i++) {
ccv_keypoint_t* kp = (ccv_keypoint_t*)ccv_array_get(keypoints, i);
AV* point = newAV();
av_push( point, newSVnv( kp->x ));
av_push( point, newSVnv( kp->y ));
};
Inline_Stack_Push(sv_2mortal(newRV_noinc((SV*) res)));
Inline_Stack_Done;
return;
}
void myccv_get_descriptor(char* file, ccv_sift_param_t* param)
{
Inline_Stack_Vars;
Inline_Stack_Reset;
ccv_dense_matrix_t* data = 0;
ccv_read(file, &data, CCV_IO_GRAY | CCV_IO_ANY_FILE);
assert(data);
ccv_array_t* keypoints = 0;
ccv_dense_matrix_t* descriptor = 0;
ccv_sift(data, &keypoints, &descriptor, 0, *param);
/* TODO We should blesss those into proper classes for automatic deallocation */
Inline_Stack_Push(sv_2mortal(newSVpv((void *)descriptor,0)));
Inline_Stack_Push(sv_2mortal(newSVpv((void *)keypoints,0)));
Inline_Stack_Done;
return;
}
void myccv_sift(char* object_file, char* scene_file, ccv_sift_param_t* param)
{
Inline_Stack_Vars;
Inline_Stack_Reset;
ccv_enable_default_cache();
ccv_dense_matrix_t* object = 0;
ccv_dense_matrix_t* image = 0;
ccv_read(object_file, &object, CCV_IO_GRAY | CCV_IO_ANY_FILE);
assert(object);
ccv_read(scene_file, &image, CCV_IO_GRAY | CCV_IO_ANY_FILE);
assert(image);
ccv_array_t* obj_keypoints = 0;
ccv_dense_matrix_t* obj_desc = 0;
ccv_sift(object, &obj_keypoints, &obj_desc, 0, *param);
ccv_array_t* image_keypoints = 0;
ccv_dense_matrix_t* image_desc = 0;
ccv_sift(image, &image_keypoints, &image_desc, 0, *param);
int i, j, k;
int match = 0;
for (i = 0; i < obj_keypoints->rnum; i++)
{
float* odesc = obj_desc->data.f32 + i * 128;
int minj = -1;
double mind = 1e6, mind2 = 1e6;
for (j = 0; j < image_keypoints->rnum; j++)
{
float* idesc = image_desc->data.f32 + j * 128;
double d = 0;
for (k = 0; k < 128; k++)
{
d += (odesc[k] - idesc[k]) * (odesc[k] - idesc[k]);
if (d > mind2)
break;
}
if (d < mind)
{
mind2 = mind;
mind = d;
minj = j;
} else if (d < mind2) {
mind2 = d;
}
}
if (mind < mind2 * 0.36)
{
ccv_keypoint_t* op = (ccv_keypoint_t*)ccv_array_get(obj_keypoints, i);
ccv_keypoint_t* kp = (ccv_keypoint_t*)ccv_array_get(image_keypoints, minj);
// Create the new 4-item array
AV* res = newAV();
av_push( res, newSVnv( op->x ));
av_push( res, newSVnv( op->y ));
av_push( res, newSVnv( kp->x ));
av_push( res, newSVnv( kp->y ));
Inline_Stack_Push(sv_2mortal(newRV_noinc((SV*) res)));
match++;
}
}
ccv_array_free(obj_keypoints);
ccv_array_free(image_keypoints);
ccv_matrix_free(obj_desc);
ccv_matrix_free(image_desc);
ccv_matrix_free(object);
ccv_matrix_free(image);
ccv_disable_cache();
Inline_Stack_Done;
return;
}
// 3
MODULE = Image::CCV PACKAGE = Image::CCV
PROTOTYPES: DISABLE
void
myccv_detect_faces (filename, training_data)
char * filename
char * training_data
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
Inline_Stack_Vars;
Inline_Stack_Reset;
int i;
ccv_enable_default_cache();
ccv_dense_matrix_t* image = 0;
/* TODO: Make the cascade accessible from the outside */
ccv_bbf_classifier_cascade_t* cascade = ccv_bbf_read_classifier_cascade(training_data);
ccv_read(filename, &image, CCV_IO_GRAY | CCV_IO_ANY_FILE);
if (image != 0)
{
/* TODO: Make the BBF parameters accessible from the outside */
ccv_bbf_param_t params = { .interval = 5, .min_neighbors = 2, .accurate = 1, .flags = 0, .size = ccv_size(24, 24) };
ccv_array_t* seq = ccv_bbf_detect_objects(image, &cascade, 1, params);
for (i = 0; i < seq->rnum; i++)
{
ccv_comp_t* comp = (ccv_comp_t*)ccv_array_get(seq, i);
/* Create the new 5-item array */
AV* res = newAV();
av_push( res, newSVnv( comp->rect.x ));
av_push( res, newSVnv( comp->rect.y ));
av_push( res, newSVnv( comp->rect.width ));
av_push( res, newSVnv( comp->rect.height ));
av_push( res, newSVnv( comp->confidence ));
Inline_Stack_Push(sv_2mortal(newRV_noinc((SV*) res)));
}
ccv_array_free(seq);
ccv_matrix_free(image);
}
ccv_bbf_classifier_cascade_free(cascade);
ccv_disable_cache();
Inline_Stack_Done;
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
ccv_sift_param_t *
myccv_pack_parameters (noctaves, nlevels, up2x, edge_threshold, norm_threshold, peak_threshold)
int noctaves
int nlevels
int up2x
int edge_threshold
int norm_threshold
int peak_threshold
void
myccv_keypoints_to_list (keypoints)
ccv_array_t * keypoints
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
myccv_keypoints_to_list(keypoints);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
myccv_get_descriptor (file, param)
char * file
ccv_sift_param_t * param
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
myccv_get_descriptor(file, param);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
void
myccv_sift (object_file, scene_file, param)
char * object_file
char * scene_file
ccv_sift_param_t * param
PREINIT:
I32* temp;
PPCODE:
temp = PL_markstack_ptr++;
myccv_sift(object_file, scene_file, param);
if (PL_markstack_ptr != temp) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = temp;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */