Skip to content

Commit 5fe7f83

Browse files
committed
added ccv_distance_transform which implements generalized squared
euclidean distance transform in linear time. added test cases for ccv_convolve and ccv_distane_transform
1 parent eb1483b commit 5fe7f83

File tree

15 files changed

+450
-266
lines changed

15 files changed

+450
-266
lines changed

bin/dpmdetect.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ int main(int argc, char** argv)
2222
unsigned int elapsed_time = get_current_time();
2323
ccv_dpm_param_t params = { .interval = 5, .min_neighbors = 2, .flags = 0, .size = ccv_size(root_classifier->root.size.width * 8, root_classifier->root.size.height * 8) };
2424
ccv_array_t* seq = ccv_dpm_detect_objects(image, &root_classifier, 1, params);
25-
/*
2625
elapsed_time = get_current_time() - elapsed_time;
2726
for (i = 0; i < seq->rnum; i++)
2827
{
@@ -31,7 +30,6 @@ int main(int argc, char** argv)
3130
}
3231
printf("total : %d in time %dms\n", seq->rnum, elapsed_time);
3332
ccv_array_free(seq);
34-
*/
3533
ccv_matrix_free(image);
3634
}
3735
ccv_drain_cache();

bin/makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ CC = clang
22
LDFLAGS = -L"../lib" -lccv -pthread -ljpeg -lpng -lfftw3 -lz -lgsl -lblas -lm # -lgomp # -lOpenCL -L"/opt/ati-stream-sdk/lib/x86_64"
33
CXXFLAGS = -O3 -msse2 -Wall -I"../lib" # -fopenmp -D USE_OPENMP # -D USE_OPENCL
44

5-
TARGETS = bbffmt siftmatch bbfcreate bbfdetect swtdetect swtcreate convert distance blur
5+
TARGETS = bbffmt siftmatch bbfcreate bbfdetect swtdetect swtcreate convert
66

77
all: libccv.a $(TARGETS)
88

lib/ccv.h

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <stdlib.h>
1515
#include <stdarg.h>
1616
#include <string.h>
17+
#include <float.h>
1718
#include <math.h>
1819
#include <xmmintrin.h>
1920
#include <assert.h>
@@ -81,6 +82,7 @@ typedef struct {
8182
float fl;
8283
int64_t l;
8384
double db;
85+
void* ptr;
8486
} tag;
8587
ccv_matrix_cell_t data;
8688
} ccv_dense_matrix_t;
@@ -337,15 +339,7 @@ void ccv_enable_cache(size_t size);
337339
case CCV_64F: ((double*)(ptr))[(i)] = (double)value; break; \
338340
default: ((unsigned char*)(ptr))[(i)] = ccv_clamp((int)(value) >> factor, 0, 255); }
339341

340-
341-
/* unswitch for loop macros */
342-
/* the new added macro in order to do for loop expansion in a way that, you can
343-
* expand a for loop by inserting different code snippet */
344-
#define ccv_unswitch_block(param, block, ...) { block(__VA_ARGS__, param); }
345-
#define ccv_unswitch_block_a(param, block, ...) { block(__VA_ARGS__, param); }
346-
#define ccv_unswitch_block_b(param, block, ...) { block(__VA_ARGS__, param); }
347-
/* the factor used to provide higher accuracy in integer type (all integer
348-
* computation in some cases) */
342+
/* the factor used to provide higher accuracy in integer type (all integer computation in some cases) */
349343
#define _ccv_get_32s_value(ptr, i, factor) (((int*)(ptr))[(i)] << factor)
350344
#define _ccv_get_32f_value(ptr, i, factor) ((float*)(ptr))[(i)]
351345
#define _ccv_get_64s_value(ptr, i, factor) (((int64_t*)(ptr))[(i)] << factor)
@@ -533,8 +527,11 @@ int ccv_write(ccv_dense_matrix_t* mat, char* out, int* len, int type, void* conf
533527
double ccv_trace(ccv_matrix_t* mat);
534528

535529
enum {
536-
CCV_L2_NORM = 0x01,
537-
CCV_L1_NORM = 0x02,
530+
CCV_L2_NORM = 0x01, // |dx| + |dy|
531+
CCV_L1_NORM = 0x02, // sqrt(dx^2 + dy^2)
532+
CCV_GSEDT = 0x04, // Generalized Squared Euclidean Distance Transform:
533+
// a * dx + b * dy + c * dx^2 + d * dy^2, when combined with CCV_L1_NORM:
534+
// a * |dx| + b * |dy| + c * dx^2 + d * dy^2
538535
};
539536

540537
enum {
@@ -676,20 +673,21 @@ typedef double(*ccv_convolve_kernel_f)(double x, double y, void*);
676673
void ccv_convolve_kernel(ccv_dense_matrix_t* x, ccv_convolve_kernel_f func, void* data);
677674

678675
/* modern numerical algorithms */
676+
void ccv_distance_transform(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, double dx, double dy, double dxx, double dyy, int flag);
679677
void ccv_sparse_coding(ccv_matrix_t* x, int k, ccv_matrix_t** A, int typeA, ccv_matrix_t** y, int typey);
680678
void ccv_compressive_sensing_reconstruct(ccv_matrix_t* a, ccv_matrix_t* x, ccv_matrix_t** y, int type);
681679

682680
/* basic computer vision algorithms / or build blocks */
683681
void ccv_sobel(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int dx, int dy);
684682
void ccv_gradient(ccv_dense_matrix_t* a, ccv_dense_matrix_t** theta, int ttype, ccv_dense_matrix_t** m, int mtype, int dx, int dy);
685-
void ccv_hog(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int size);
683+
void ccv_hog(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int b_type, int sbin, int size);
686684
void ccv_canny(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int size, double low_thresh, double high_thresh);
687685

688686
enum {
689-
CCV_INTER_AREA = 0x01,
690-
CCV_INTER_LINEAR = 0X02,
691-
CCV_INTER_CUBIC = 0X03,
692-
CCV_INTER_LACZOS = 0X04,
687+
CCV_INTER_AREA = 0x01,
688+
CCV_INTER_LINEAR = 0X02,
689+
CCV_INTER_CUBIC = 0X03,
690+
CCV_INTER_LANCZOS = 0X04,
693691
};
694692

695693
void ccv_resample(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int btype, int rows, int cols, int type);

lib/ccv_basic.c

Lines changed: 154 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ static void _ccv_atan2(float* x, float* y, float* angle, float* mag, int len)
244244

245245
void ccv_gradient(ccv_dense_matrix_t* a, ccv_dense_matrix_t** theta, int ttype, ccv_dense_matrix_t** m, int mtype, int dx, int dy)
246246
{
247-
assert(a->type & CCV_C1);
247+
assert(CCV_GET_CHANNEL(a->type) == CCV_C1);
248248
ccv_declare_matrix_signature(tsig, a->sig != 0, ccv_sign_with_literal("ccv_gradient_theta"), a->sig, 0);
249249
ccv_declare_matrix_signature(msig, a->sig != 0, ccv_sign_with_literal("ccv_gradient_m"), a->sig, 0);
250250
ccv_dense_matrix_t* dtheta = *theta = ccv_dense_matrix_renew(*theta, a->rows, a->cols, CCV_32F | CCV_C1, CCV_32F | CCV_C1, tsig);
@@ -260,53 +260,164 @@ void ccv_gradient(ccv_dense_matrix_t* a, ccv_dense_matrix_t** theta, int ttype,
260260
ccv_matrix_free(ty);
261261
}
262262

263-
void ccv_hog(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int size)
263+
void ccv_hog(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int b_type, int sbin, int size)
264264
{
265-
assert(a->type & CCV_C1);
266-
int border_size = size / 2;
267-
ccv_declare_matrix_signature(sig, a->sig != 0, ccv_sign_with_literal("ccv_hog"), a->sig, 0);
268-
type = (type == 0) ? CCV_32S | CCV_C1 : CCV_GET_DATA_TYPE(type) | CCV_C1;
269-
ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows - border_size * 2, (a->cols - border_size * 2) * 8, CCV_C1 | CCV_ALL_DATA_TYPE, type, sig);
265+
assert(CCV_GET_CHANNEL(a->type) == CCV_C1);
266+
int rows = a->rows / size;
267+
int cols = a->cols / size;
268+
ccv_declare_matrix_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_hog(%d,%d)", sbin, size), a->sig, 0);
269+
ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_64F | (4 + sbin * 3), CCV_64F | (4 + sbin * 3), sig);
270270
ccv_matrix_return_if_cached(, db);
271271
ccv_dense_matrix_t* ag = 0;
272272
ccv_dense_matrix_t* mg = 0;
273-
ccv_gradient(a, &ag, 0, &mg, 0, 3, 3);
274-
int i, j, x, y;
275-
ag->type = (ag->type & ~CCV_32F) | CCV_32S;
276-
for (i = 0; i < a->rows * a->cols; i++)
277-
ag->data.i[i] = ((int)(ag->data.fl[i] / 45 + 0.5)) & 0x7;
278-
int* agi = ag->data.i;
279-
float* mgfl = mg->data.fl;
280-
int* bi = db->data.i;
281-
for (y = 0; y <= a->rows - size; y++)
273+
ccv_gradient(a, &ag, 0, &mg, 0, 1, 1);
274+
float* agp = ag->data.fl;
275+
float* mgp = mg->data.fl;
276+
int i, j, k;
277+
ccv_dense_matrix_t* cn = ccv_dense_matrix_new(rows, cols, CCV_64F | (sbin * 2), 0, 0);
278+
ccv_dense_matrix_t* ca = ccv_dense_matrix_new(rows, cols, CCV_64F | CCV_C1, 0, 0);
279+
ccv_zero(cn);
280+
double* cnp = cn->data.db;
281+
int sizec = 0;
282+
for (i = 0; i < rows * size; i++)
282283
{
283-
float hog[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
284-
for (i = 0; i < size; i++)
285-
for (j = 0; j < size; j++)
286-
hog[agi[i * a->cols + j]] += mgfl[i * a->cols + j];
287-
for (i = 0; i < 8; i++)
288-
bi[i] = (int)hog[i];
289-
bi += 8;
290-
mgfl++;
291-
agi++;
292-
for (x = 1; x <= a->cols - size; x++)
284+
for (j = 0; j < cols; j++)
293285
{
294-
for (i = 0; i < size; i++)
286+
for (k = j * size; k < j * size + size; k++)
295287
{
296-
hog[agi[i * a->cols - 1]] -= mgfl[i * a->cols - 1];
297-
hog[agi[i * a->cols - 1 + size]] += mgfl[i * a->cols - 1 + size];
288+
int ag0, ag1;
289+
double agr;
290+
agr = (agp[k] / 360.0) * (sbin * 2);
291+
ag0 = (int)agr;
292+
ag1 = (ag0 + 1 < sbin * 2) ? ag0 + 1 : 0;
293+
agr = agr - ag0;
294+
cnp[ag0] += (1.0 - agr) * mgp[k] / 255.0;
295+
cnp[ag1] += agr * mgp[k] / 255.0;
298296
}
299-
for (i = 0; i < 8; i++)
300-
bi[i] = (int)hog[i];
301-
bi += 8;
302-
mgfl++;
303-
agi++;
297+
cnp += 2 * sbin;
304298
}
305-
agi += border_size * 2;
306-
mgfl += border_size * 2;
299+
agp += a->cols;
300+
mgp += a->cols;
301+
if (++sizec < size)
302+
cnp -= cn->cols;
303+
else
304+
sizec = 0;
307305
}
308306
ccv_matrix_free(ag);
309307
ccv_matrix_free(mg);
308+
cnp = cn->data.db;
309+
double* cap = ca->data.db;
310+
for (i = 0; i < rows; i++)
311+
{
312+
for (j = 0; j < cols; j++)
313+
{
314+
*cap = 0;
315+
for (k = 0; k < sbin * 2; k++)
316+
{
317+
*cap += (*cnp) * (*cnp);
318+
cnp++;
319+
}
320+
cap++;
321+
}
322+
}
323+
cnp = cn->data.db;
324+
cap = ca->data.db;
325+
ccv_zero(db);
326+
double* dbp = db->data.db;
327+
// normalize sbin direction-sensitive and sbin * 2 insensitive over 4 normalization factor
328+
// accumulating them over sbin * 2 + sbin + 4 channels
329+
// TNA - truncation - normalization - accumulation
330+
#define TNA(idx, a, b, c, d) \
331+
{ \
332+
double norm = 1.0 / sqrt(cap[a] + cap[b] + cap[c] + cap[d] + 1e-4); \
333+
for (k = 0; k < sbin * 2; k++) \
334+
{ \
335+
double v = 0.5 * ccv_min(cnp[k] * norm, 0.2); \
336+
dbp[5 + sbin + k] += v; \
337+
dbp[1 + idx] += v; \
338+
} \
339+
dbp[sbin * 3 + idx] *= 0.2357; \
340+
for (k = 0; k < sbin; k++) \
341+
{ \
342+
double v = 0.5 * ccv_min((cnp[k] + cnp[k + sbin]) * norm, 0.2); \
343+
dbp[5 + k] += v; \
344+
} \
345+
}
346+
TNA(0, 0, 0, 0, 0);
347+
TNA(1, 1, 1, 0, 0);
348+
TNA(2, 0, ca->cols, ca->cols, 0);
349+
TNA(3, 1, ca->cols + 1, ca->cols, 0);
350+
cnp += 2 * sbin;
351+
dbp += 3 * sbin + 4;
352+
cap++;
353+
for (j = 1; j < cols - 1; j++)
354+
{
355+
TNA(0, -1, -1, 0, 0);
356+
TNA(1, 1, 1, 0, 0);
357+
TNA(2, -1, ca->cols - 1, ca->cols, 0);
358+
TNA(3, 1, ca->cols + 1, ca->cols, 0);
359+
cnp += 2 * sbin;
360+
dbp += 3 * sbin + 4;
361+
cap++;
362+
}
363+
TNA(0, -1, -1, 0, 0);
364+
TNA(1, 0, 0, 0, 0);
365+
TNA(2, -1, ca->cols - 1, ca->cols, 0);
366+
TNA(3, 0, ca->cols, ca->cols, 0);
367+
cnp += 2 * sbin;
368+
dbp += 3 * sbin + 4;
369+
cap++;
370+
for (i = 1; i < rows - 1; i++)
371+
{
372+
TNA(0, 0, -ca->cols, -ca->cols, 0);
373+
TNA(1, 1, -ca->cols + 1, -ca->cols, 0);
374+
TNA(2, 0, ca->cols, ca->cols, 0);
375+
TNA(3, 1, ca->cols + 1, ca->cols, 0);
376+
cnp += 2 * sbin;
377+
dbp += 3 * sbin + 4;
378+
cap++;
379+
for (j = 1; j < cols - 1; j++)
380+
{
381+
TNA(0, -1, -ca->cols - 1, -ca->cols, 0);
382+
TNA(1, 1, -ca->cols + 1, -ca->cols, 0);
383+
TNA(2, -1, ca->cols - 1, ca->cols, 0);
384+
TNA(3, 1, ca->cols + 1, ca->cols, 0);
385+
cnp += 2 * sbin;
386+
dbp += 3 * sbin + 4;
387+
cap++;
388+
}
389+
TNA(0, -1, -ca->cols - 1, -ca->cols, 0);
390+
TNA(1, 0, -ca->cols, -ca->cols, 0);
391+
TNA(2, -1, ca->cols - 1, ca->cols, 0);
392+
TNA(3, 0, ca->cols, ca->cols, 0);
393+
cnp += 2 * sbin;
394+
dbp += 3 * sbin + 4;
395+
cap++;
396+
}
397+
TNA(0, 0, -ca->cols, -ca->cols, 0);
398+
TNA(1, 1, -ca->cols + 1, -ca->cols, 0);
399+
TNA(2, 0, 0, 0, 0);
400+
TNA(3, 1, 1, 0, 0);
401+
cnp += 2 * sbin;
402+
dbp += 3 * sbin + 4;
403+
cap++;
404+
for (j = 1; j < cols - 1; j++)
405+
{
406+
TNA(0, -1, -ca->cols - 1, -ca->cols, 0);
407+
TNA(1, 1, -ca->cols + 1, -ca->cols, 0);
408+
TNA(2, -1, -1, 0, 0);
409+
TNA(3, 1, 1, 0, 0);
410+
cnp += 2 * sbin;
411+
dbp += 3 * sbin + 4;
412+
cap++;
413+
}
414+
TNA(0, -1, -ca->cols - 1, -ca->cols, 0);
415+
TNA(1, 0, -ca->cols, -ca->cols, 0);
416+
TNA(2, -1, -1, 0, 0);
417+
TNA(3, 0, 0, 0, 0);
418+
#undef TNA
419+
ccv_matrix_free(cn);
420+
ccv_matrix_free(ca);
310421
}
311422

312423
/* it is a supposely cleaner and faster implementation than original OpenCV (ccv_canny_deprecated,
@@ -678,7 +789,7 @@ void ccv_resample(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int btype, int
678789
break;
679790
case CCV_INTER_CUBIC:
680791
break;
681-
case CCV_INTER_LACZOS:
792+
case CCV_INTER_LANCZOS:
682793
break;
683794
}
684795
}
@@ -707,7 +818,7 @@ void ccv_sample_down(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, in
707818
* it is not desirable to have that offset when we try to wrap it into our 5-row buffer (
708819
* because in later rearrangement, we have no src_y to backup the arrangement). In
709820
* such micro scope, we managed to stripe 5 addition into one shift and addition. */
710-
#define for_block(x_block, _for_get_a, _for_get, _for_set, _for_set_b) \
821+
#define for_block(_for_get_a, _for_get, _for_set, _for_set_b) \
711822
for (dy = 0; dy < db->rows; dy++) \
712823
{ \
713824
for(; sy <= dy * 2 + 2 + src_y; sy++) \
@@ -730,20 +841,19 @@ void ccv_sample_down(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, in
730841
b_ptr += db->step; \
731842
}
732843
int no_8u_type = (a->type & CCV_8U) ? CCV_32S : a->type;
733-
/* here is the new technique to expand for loop with condition in manual way */
734844
if (src_x > 0)
735845
{
736846
#define x_block(_for_get_a, _for_get, _for_set, _for_set_b) \
737847
for (dx = cols0 * ch; dx < db->cols * ch; dx += ch) \
738848
for (k = 0; k < ch; k++) \
739849
_for_set(row, dx + k, _for_get_a(a_ptr, tab[dx * 2 + sx + k], 0) * 6 + (_for_get_a(a_ptr, tab[dx * 2 + sx + k - ch], 0) + _for_get_a(a_ptr, tab[dx * 2 + sx + k + ch], 0)) * 4 + _for_get_a(a_ptr, tab[dx * 2 + sx + k - ch * 2], 0) + _for_get_a(a_ptr, tab[dx * 2 + sx + k + ch * 2], 0), 0);
740-
ccv_unswitch_block(x_block, ccv_matrix_getter_a, a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
850+
ccv_matrix_getter_a(a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
741851
#undef x_block
742852
} else {
743853
#define x_block(_for_get_a, _for_get, _for_set, _for_set_b) \
744854
for (k = 0; k < ch; k++) \
745855
_for_set(row, (db->cols - 1) * ch + k, _for_get_a(a_ptr, a->cols * ch + sx - ch + k, 0) * 10 + _for_get_a(a_ptr, (a->cols - 2) * ch + sx + k, 0) * 5 + _for_get_a(a_ptr, (a->cols - 3) * ch + sx + k, 0), 0);
746-
ccv_unswitch_block(x_block, ccv_matrix_getter_a, a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
856+
ccv_matrix_getter_a(a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
747857
#undef x_block
748858
}
749859
#undef for_block
@@ -767,7 +877,7 @@ void ccv_sample_up(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int
767877
int bufstep = db->cols * ch * ccv_max(CCV_GET_DATA_TYPE_SIZE(db->type), sizeof(int));
768878
unsigned char* b_ptr = db->data.ptr;
769879
/* why src_y * 2: the same argument as in ccv_sample_down */
770-
#define for_block(x_block, _for_get_a, _for_get, _for_set, _for_set_b) \
880+
#define for_block(_for_get_a, _for_get, _for_set, _for_set_b) \
771881
for (y = 0; y < a->rows; y++) \
772882
{ \
773883
for (; sy <= y + 1 + src_y; sy++) \
@@ -820,7 +930,7 @@ void ccv_sample_up(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int
820930
_for_set(row, x * 2 + k, _for_get_a(a_ptr, tab[x + sx - ch + k], 0) + _for_get_a(a_ptr, tab[x + sx + k], 0) * 6 + _for_get_a(a_ptr, tab[x + sx + ch + k], 0), 0); \
821931
_for_set(row, x * 2 + ch + k, (_for_get_a(a_ptr, tab[x + sx + k], 0) + _for_get_a(a_ptr, tab[x + sx + ch + k], 0)) * 4, 0); \
822932
}
823-
ccv_unswitch_block(x_block, ccv_matrix_getter_a, a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
933+
ccv_matrix_getter_a(a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
824934
#undef x_block
825935
} else {
826936
#define x_block(_for_get_a, _for_get, _for_set, _for_set_b) \
@@ -829,7 +939,7 @@ void ccv_sample_up(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int
829939
_for_set(row, (a->cols - 1) * 2 * ch + k, _for_get_a(a_ptr, (a->cols - 2) * ch + k, 0) + _for_get_a(a_ptr, (a->cols - 1) * ch + k, 0) * 7, 0); \
830940
_for_set(row, (a->cols - 1) * 2 * ch + ch + k, _for_get_a(a_ptr, (a->cols - 1) * ch + k, 0) * 4, 0); \
831941
}
832-
ccv_unswitch_block(x_block, ccv_matrix_getter_a, a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
942+
ccv_matrix_getter_a(a->type, ccv_matrix_getter, no_8u_type, ccv_matrix_setter, no_8u_type, ccv_matrix_setter_b, db->type, for_block);
833943
#undef x_block
834944
}
835945
#undef for_block

0 commit comments

Comments
 (0)