Skip to content

Commit

Permalink
finished sift, more test needed
Browse files Browse the repository at this point in the history
  • Loading branch information
liuliu committed Sep 24, 2010
1 parent 2b0d9df commit d8fab74
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 7 deletions.
10 changes: 10 additions & 0 deletions COPYING
@@ -0,0 +1,10 @@
Copyright (c) 2010, Liu Liu
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2 changes: 1 addition & 1 deletion bin/makefile
Expand Up @@ -2,7 +2,7 @@ CC = gcc
LDFLAGS = -L"../lib" -L"/opt/ati-stream-sdk/lib/x86_64" -pthread -lccv -ljpeg -lpng -lfftw3 -lz -lgsl -lblas -lm -lgomp -lOpenCL LDFLAGS = -L"../lib" -L"/opt/ati-stream-sdk/lib/x86_64" -pthread -lccv -ljpeg -lpng -lfftw3 -lz -lgsl -lblas -lm -lgomp -lOpenCL
CXXFLAGS = -O3 -msse2 -Wall -I"../lib" -fopenmp -D USE_OPENMP -D USE_OPENCL CXXFLAGS = -O3 -msse2 -Wall -I"../lib" -fopenmp -D USE_OPENMP -D USE_OPENCL


TARGETS = sgfdetect sgfcreate sgffmt sgfopt TARGETS = sgfdetect sgfcreate sgffmt sgfopt siftmatch


all: libccv.a $(TARGETS) all: libccv.a $(TARGETS)


Expand Down
78 changes: 78 additions & 0 deletions bin/siftmatch.c
@@ -0,0 +1,78 @@
#include "ccv.h"
#include <sys/time.h>

unsigned int get_current_time()
{
struct timeval tv;
gettimeofday(&tv, 0);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

int main(int argc, char** argv)
{
assert(argc == 3);
ccv_dense_matrix_t* object = 0;
ccv_dense_matrix_t* image = 0;
ccv_unserialize(argv[1], &object, CCV_SERIAL_GRAY | CCV_SERIAL_ANY_FILE);
ccv_unserialize(argv[2], &image, CCV_SERIAL_GRAY | CCV_SERIAL_ANY_FILE);
unsigned int elapsed_time = get_current_time();
ccv_sift_param_t param;
param.noctaves = 3;
param.nlevels = 6;
param.edge_threshold = 10;
param.norm_threshold = 0;
param.peak_threshold = 0;
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);
printf("elpased time : %d\n", get_current_time() - elapsed_time);
int i, j, k;
ccv_dense_matrix_t* imx = ccv_dense_matrix_new(image->rows, image->cols, CCV_8U | CCV_C1, 0, 0);
memset(imx->data.ptr, 0, imx->rows * imx->step);
for (i = 0; i < obj_keypoints->rnum; i++)
{
float* odesc = obj_desc->data.fl + i * 128;
int minj = -1;
double mind = 1e6, mind2 = 1e6;
for (j = 0; j < image_keypoints->rnum; j++)
{
float* idesc = image_desc->data.fl + 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.6)
{
ccv_keypoint_t* kp = (ccv_keypoint_t*)ccv_array_get(image_keypoints, minj);
int ix = (int)(kp->x + 0.5);
int iy = (int)(kp->y + 0.5);
imx->data.ptr[ix + iy * imx->step] = 255;
}
}
int len;
ccv_serialize(imx, "match.png", &len, CCV_SERIAL_PNG_FILE, 0);
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_garbage_collect();
return 0;
}

2 changes: 2 additions & 0 deletions lib/ccv.h
Expand Up @@ -365,6 +365,7 @@ enum {
}; };


double ccv_norm(ccv_matrix_t* mat, int type); double ccv_norm(ccv_matrix_t* mat, int type);
double ccv_normalize(ccv_matrix_t* a, ccv_matrix_t** b, int btype, int l_type);
double ccv_dot(ccv_matrix_t* a, ccv_matrix_t* b); double ccv_dot(ccv_matrix_t* a, ccv_matrix_t* b);
double ccv_sum(ccv_matrix_t* mat); double ccv_sum(ccv_matrix_t* mat);
void ccv_zero(ccv_matrix_t* mat); void ccv_zero(ccv_matrix_t* mat);
Expand Down Expand Up @@ -532,6 +533,7 @@ typedef struct {
int nlevels; int nlevels;
float edge_threshold; float edge_threshold;
float peak_threshold; float peak_threshold;
float norm_threshold;
} ccv_sift_param_t; } ccv_sift_param_t;


void ccv_sift(ccv_dense_matrix_t* a, ccv_array_t** keypoints, ccv_dense_matrix_t** desc, int type, ccv_sift_param_t params); void ccv_sift(ccv_dense_matrix_t* a, ccv_array_t** keypoints, ccv_dense_matrix_t** desc, int type, ccv_sift_param_t params);
Expand Down
42 changes: 42 additions & 0 deletions lib/ccv_algebra.c
Expand Up @@ -13,6 +13,48 @@ double ccv_norm(ccv_matrix_t* mat, int type)
return 0; return 0;
} }


double ccv_normalize(ccv_matrix_t* a, ccv_matrix_t** b, int btype, int l_type)
{
ccv_dense_matrix_t* da = ccv_get_dense_matrix(a);
assert(CCV_GET_CHANNEL(da->type) == CCV_C1);
char identifier[20];
memset(identifier, 0, 20);
snprintf(identifier, 20, "ccv_normalize(%d)", l_type);
uint64_t sig = (da->sig == 0) ? 0 : ccv_matrix_generate_signature(identifier, 20, da->sig, 0);
btype = (btype == 0) ? CCV_GET_DATA_TYPE(da->type) | CCV_C1 : CCV_GET_DATA_TYPE(btype) | CCV_C1;
ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, da->rows, da->cols, CCV_ALL_DATA_TYPE | CCV_C1, btype, sig);
ccv_cache_return(db, );
double sum = 0;
int i, j;
unsigned char* a_ptr = da->data.ptr;
unsigned char* b_ptr = db->data.ptr;
switch (l_type)
{
case CCV_L2_NORM:
#define for_block(__for_set, __for_get) \
for (i = 0; i < da->rows; i++) \
{ \
for (j = 0; j < da->cols; j++) \
sum += __for_get(a_ptr, j, 0) * __for_get(a_ptr, j, 0); \
a_ptr += da->step; \
} \
sum = sqrt(sum); \
double inv = 1.0 / sqrt(sum); \
a_ptr = da->data.ptr; \
for (i = 0; i < da->rows; i++) \
{ \
for (j = 0; j < da->cols; j++) \
__for_set(b_ptr, j, __for_get(a_ptr, j, 0) * inv, 0); \
a_ptr += da->step; \
b_ptr += db->step; \
}
ccv_matrix_setter(db->type, ccv_matrix_getter, da->type, for_block);
#undef for_block
break;
}
return sum;
}

double ccv_sum(ccv_matrix_t* mat) double ccv_sum(ccv_matrix_t* mat)
{ {
ccv_dense_matrix_t* dmt = ccv_get_dense_matrix(mat); ccv_dense_matrix_t* dmt = ccv_get_dense_matrix(mat);
Expand Down
49 changes: 45 additions & 4 deletions lib/ccv_sift.c
@@ -1,4 +1,13 @@
/* The code is adopted from VLFeat, which is licenced under GPLv2 */ /* The code is adopted from VLFeat with heavily rewrite.
* The original code is licenced under GPLv2, should be compatible
* with New BSD Licence used by ccv. The original Copyright:
*
* AUTORIGHTS
* Copyright (C) 2007-10 Andrea Vedaldi and Brian Fulkerson
*
* This file is part of VLFeat, available under the terms of the
* GNU GPLv2, or (at your option) any later version.
*/


#include "ccv.h" #include "ccv.h"


Expand Down Expand Up @@ -362,7 +371,8 @@ void ccv_sift(ccv_dense_matrix_t* a, ccv_array_t** _keypoints, ccv_dense_matrix_
float dy = kp->y / ds; float dy = kp->y / ds;
int ix = (int)(dx + 0.5); int ix = (int)(dx + 0.5);
int iy = (int)(dy + 0.5); int iy = (int)(dy + 0.5);
int wz = ccv_max((int)(3.0 * kp->regular.scale + 0.5), 1); double SBP = 3.0 * kp->regular.scale;
int wz = ccv_max((int)(SBP * sqrt(2.0) * 2.5 + 0.5), 1);
ccv_dense_matrix_t* tho = th[kp->octave * (params.nlevels - 3) + kp->level - 1]; ccv_dense_matrix_t* tho = th[kp->octave * (params.nlevels - 3) + kp->level - 1];
ccv_dense_matrix_t* mdo = md[kp->octave * (params.nlevels - 3) + kp->level - 1]; ccv_dense_matrix_t* mdo = md[kp->octave * (params.nlevels - 3) + kp->level - 1];
assert(tho->rows == mdo->rows && tho->cols == mdo->cols); assert(tho->rows == mdo->rows && tho->cols == mdo->cols);
Expand All @@ -371,16 +381,47 @@ void ccv_sift(ccv_dense_matrix_t* a, ccv_array_t** _keypoints, ccv_dense_matrix_
float* magnitude = mdo->data.fl + ccv_max(iy - wz, 0) * mdo->cols; float* magnitude = mdo->data.fl + ccv_max(iy - wz, 0) * mdo->cols;
float ca = cos(kp->regular.angle); float ca = cos(kp->regular.angle);
float sa = sin(kp->regular.angle); float sa = sin(kp->regular.angle);
float sigmaw = 2.0;
/* sidenote: NBP = 4, NBO = 8 */
for (y = ccv_max(iy - wz, 0); y <= ccv_min(iy + wz, tho->rows - 1); y++) for (y = ccv_max(iy - wz, 0); y <= ccv_min(iy + wz, tho->rows - 1); y++)
{ {
for (x = ccv_max(ix - wz, 0); x <= ccv_min(ix + wz, tho->cols - 1); x++) for (x = ccv_max(ix - wz, 0); x <= ccv_min(ix + wz, tho->cols - 1); x++)
{ {
float nx = (ca * (x - dx) + sa * (y - dy)) / wz; float nx = (ca * (x - dx) + sa * (y - dy)) / SBP;
float ny = (-sa * (x - dx) + ca * (y - dy)) / wz; float ny = (-sa * (x - dx) + ca * (y - dy)) / SBP;
float nt = 8.0 * __ccv_mod_2pi(theta[x] * CCV_PI / 180.0 - kp->regular.angle) / (2.0 * CCV_PI);
float weight = __ccv_expn((nx * nx + ny * ny) / (2.0 * sigmaw * sigmaw));
int binx = __ccv_floor(nx - 0.5);
int biny = __ccv_floor(ny - 0.5);
int bint = __ccv_floor(nt);
float rbinx = nx - (binx + 0.5);
float rbiny = ny - (biny + 0.5);
float rbint = nt - bint;
int dbinx, dbiny, dbint;
/* Distribute the current sample into the 8 adjacent bins*/
for(dbinx = 0; dbinx < 2; dbinx++)
for(dbiny = 0; dbiny < 2; dbiny++)
for(dbint = 0; dbint < 2; dbint++)
if (binx + dbinx >= -2 && binx + dbinx < 2 && biny + dbiny >= -2 && biny + dbiny < 2)
fdesc[(2 + biny + dbiny) * 32 + (2 + binx + dbinx) * 8 + (bint + dbint) % 8] += weight * magnitude[x] * fabs(1 - dbinx - rbinx) * fabs(1 - dbiny - rbiny) * fabs(1 - dbint - rbint);
} }
theta += tho->cols; theta += tho->cols;
magnitude += mdo->cols; magnitude += mdo->cols;
} }
ccv_dense_matrix_t tm = ccv_dense_matrix(1, 128, CCV_32F | CCV_C1, fdesc, 0);
ccv_dense_matrix_t* tmp = &tm;
double norm = ccv_normalize(&tm, &tmp, 0, CCV_L2_NORM);
int num = (ccv_min(iy + wz, tho->rows - 1) - ccv_max(iy - wz, 0) + 1) * (ccv_min(ix + wz, tho->cols - 1) - ccv_max(ix - wz, 0) + 1);
if (params.norm_threshold && norm < params.norm_threshold * num)
{
for (j = 0; j < 128; j++)
fdesc[j] = 0;
} else {
for (j = 0; j < 128; j++)
if (fdesc[j] > 0.2)
fdesc[j] = 0.2;
ccv_normalize(&tm, &tmp, 0, CCV_L2_NORM);
}
fdesc += 128; fdesc += 128;
} }
} }
Expand Down
2 changes: 1 addition & 1 deletion test/makefile
Expand Up @@ -2,7 +2,7 @@ CC = clang
LDFLAGS = -L"../lib" -pthread -static -lccv -ljpeg -lpng -lfftw3 -lz -lgsl -lblas -lm # -lgslcblas LDFLAGS = -L"../lib" -pthread -static -lccv -ljpeg -lpng -lfftw3 -lz -lgsl -lblas -lm # -lgslcblas
CXXFLAGS = -O3 -msse2 -Wall -I"../lib" CXXFLAGS = -O3 -msse2 -Wall -I"../lib"


TARGETS = sobel_test hog_test cache_test sparse_matrix_test io_test filter_test algebra_test compress_matrix_test atan2_test resample_test sample_down_test daisy_test array_test group_test slice_test flip_test minimize_test gc_test blur_test sift_test TARGETS = sobel_test hog_test cache_test sparse_matrix_test io_test filter_test algebra_test compress_matrix_test atan2_test resample_test sample_down_test daisy_test array_test group_test slice_test flip_test minimize_test gc_test blur_test sift_test normalize_test sift_match


all: $(TARGETS) all: $(TARGETS)


Expand Down
17 changes: 17 additions & 0 deletions test/normalize_test.c
@@ -0,0 +1,17 @@
#include "ccv.h"
#include <assert.h>

int main(int argc, char** argv)
{
int i;
ccv_dense_matrix_t* dmt = ccv_dense_matrix_new(1, 10, CCV_32F | CCV_C1, 0, 0);
for (i = 0; i < 10; i++)
dmt->data.fl[i] = i;
ccv_normalize(dmt, &dmt, 0, CCV_L2_NORM);
for (i = 0; i < 10; i++)
printf("%f ", dmt->data.fl[i]);
printf("\n");
ccv_matrix_free(dmt);
ccv_garbage_collect();
return 0;
}
3 changes: 2 additions & 1 deletion test/sift_test.c
Expand Up @@ -26,13 +26,14 @@ int main(int argc, char** argv)
param.noctaves = 3; param.noctaves = 3;
param.nlevels = 6; param.nlevels = 6;
param.edge_threshold = 10; param.edge_threshold = 10;
param.norm_threshold = 0;
param.peak_threshold = 0; param.peak_threshold = 0;
ccv_array_t* keypoints = 0; ccv_array_t* keypoints = 0;
ccv_sift(image, &keypoints, 0, 0, param); ccv_sift(image, &keypoints, 0, 0, param);
printf("%d\n", keypoints->rnum); printf("%d\n", keypoints->rnum);
ccv_dense_matrix_t* imx = ccv_dense_matrix_new(image->rows, image->cols, CCV_8U | CCV_C1, 0, 0); ccv_dense_matrix_t* imx = ccv_dense_matrix_new(image->rows, image->cols, CCV_8U | CCV_C1, 0, 0);
memset(imx->data.ptr, 0, imx->rows * imx->step); memset(imx->data.ptr, 0, imx->rows * imx->step);
int i; int i, j;
for (i = 0; i < keypoints->rnum; i++) for (i = 0; i < keypoints->rnum; i++)
{ {
ccv_keypoint_t* kp = (ccv_keypoint_t*)ccv_array_get(keypoints, i); ccv_keypoint_t* kp = (ccv_keypoint_t*)ccv_array_get(keypoints, i);
Expand Down

0 comments on commit d8fab74

Please sign in to comment.