void ccv_flatten(ccv_matrix_t* a, ccv_matrix_t** b, int type, int flag) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_declare_derived_signature(sig, da->sig != 0, ccv_sign_with_format(64, "ccv_flatten(%d)", flag), da->sig, CCV_EOF_SIGN); int no_8u_type = (da->type & CCV_8U) ? CCV_32S : da->type; type = (type == 0) ? CCV_GET_DATA_TYPE(no_8u_type) | CCV_C1 : CCV_GET_DATA_TYPE(type) | CCV_C1; ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, da->rows, da->cols, CCV_ALL_DATA_TYPE | CCV_C1, type, sig); ccv_object_return_if_cached(, db); int i, j, k, ch = CCV_GET_CHANNEL(da->type); unsigned char* aptr = da->data.u8; unsigned char* bptr = db->data.u8; #define for_block(_for_get, _for_type, _for_set) \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols; j++) \ { \ _for_type sum = 0; \ for (k = 0; k < ch; k++) \ sum += _for_get(aptr, j * ch + k, 0); \ _for_set(bptr, j, sum, 0); \ } \ aptr += da->step; \ bptr += db->step; \ } ccv_matrix_getter(da->type, ccv_matrix_typeof_setter, db->type, for_block); #undef for_block }
void ccv_resample(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int btype, int rows, int cols, int type) { ccv_declare_matrix_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_resample(%d,%d,%d)", rows, cols, type), a->sig, 0); btype = (btype == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(btype) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), btype, sig); ccv_matrix_return_if_cached(, db); if (a->rows == db->rows && a->cols == db->cols) { if (CCV_GET_CHANNEL(a->type) == CCV_GET_CHANNEL(db->type) && CCV_GET_DATA_TYPE(db->type) == CCV_GET_DATA_TYPE(a->type)) memcpy(db->data.u8, a->data.u8, a->rows * a->step); else { ccv_shift(a, (ccv_matrix_t**)&db, 0, 0, 0); } return; } switch (type) { case CCV_INTER_AREA: if (a->rows > db->rows && a->cols > db->cols) { /* using the fast alternative (fix point scale, 0x100 to avoid overflow) */ if (CCV_GET_DATA_TYPE(a->type) == CCV_8U && CCV_GET_DATA_TYPE(db->type) == CCV_8U && a->rows * a->cols / (db->rows * db->cols) < 0x100) _ccv_resample_area_8u(a, db); else _ccv_resample_area(a, db); break; } case CCV_INTER_LINEAR: break; case CCV_INTER_CUBIC: break; case CCV_INTER_LANCZOS: break; } }
void ccv_slice(ccv_matrix_t* a, ccv_matrix_t** b, int btype, int y, int x, int rows, int cols) { int type = *(int*)a; if (type & CCV_MATRIX_DENSE) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_declare_derived_signature(sig, da->sig != 0, ccv_sign_with_format(128, "ccv_slice(%d,%d,%d,%d)", y, x, rows, cols), da->sig, CCV_EOF_SIGN); btype = (btype == 0) ? CCV_GET_DATA_TYPE(da->type) | CCV_GET_CHANNEL(da->type) : CCV_GET_DATA_TYPE(btype) | CCV_GET_CHANNEL(da->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(da->type), btype, sig); ccv_object_return_if_cached(, db); int i, j, ch = CCV_GET_CHANNEL(da->type); int dx = 0, dy = 0; if (!(y >= 0 && y + rows <= da->rows && x >= 0 && x + cols <= da->cols)) { ccv_zero(db); if (y < 0) { rows += y; dy = -y; y = 0; } if (y + rows > da->rows) rows = da->rows - y; if (x < 0) { cols += x; dx = -x; x = 0; } if (x + cols > da->cols) cols = da->cols - x; } unsigned char* a_ptr = da->data.u8 + x * ch * CCV_GET_DATA_TYPE_SIZE(da->type) + y * da->step; unsigned char* b_ptr = db->data.u8 + dx * ch * CCV_GET_DATA_TYPE_SIZE(db->type) + dy * db->step; #define for_block(_for_set, _for_get) \ for (i = 0; i < rows; i++) \ { \ for (j = 0; j < cols * ch; j++) \ { \ _for_set(b_ptr, j, _for_get(a_ptr, j, 0), 0); \ } \ a_ptr += da->step; \ b_ptr += db->step; \ } ccv_matrix_setter(db->type, ccv_matrix_getter, da->type, for_block); #undef for_block } else if (type & CCV_MATRIX_SPARSE) {
void ccv_saturation(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, double ds) { assert(CCV_GET_CHANNEL(a->type) == CCV_C3); // only works in RGB space ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_saturation(%la)", ds), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); int i, j; unsigned char* aptr = a->data.u8; unsigned char* bptr = db->data.u8; #define for_block(_for_get, _for_set) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ { \ double gs = _for_get(aptr, j * 3, 0) * 0.299 + _for_get(aptr, j * 3 + 1, 0) * 0.587 + _for_get(aptr, j * 3 + 2, 0) * 0.114; \ _for_set(bptr, j * 3, (_for_get(aptr, j * 3, 0) - gs) * ds + gs, 0); \ _for_set(bptr, j * 3 + 1, (_for_get(aptr, j * 3 + 1, 0) - gs) * ds + gs, 0); \ _for_set(bptr, j * 3 + 2, (_for_get(aptr, j * 3 + 2, 0) - gs) * ds + gs, 0); \ } \ aptr += a->step; \ bptr += db->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter, db->type, for_block); #undef for_block }
ccv_dense_matrix_t* ccv_dense_matrix_new(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t* mat; if (ccv_cache_opt && sig != 0 && !data && !(type & CCV_NO_DATA_ALLOC)) { uint8_t type; mat = (ccv_dense_matrix_t*)ccv_cache_out(&ccv_cache, sig, &type); if (mat) { assert(type == 0); mat->type |= CCV_GARBAGE; // set the flag so the upper level function knows this is from recycle-bin mat->refcount = 1; return mat; } } if (type & CCV_NO_DATA_ALLOC) { mat = (ccv_dense_matrix_t*)ccmalloc(sizeof(ccv_dense_matrix_t)); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC) & ~CCV_GARBAGE; mat->data.u8 = data; } else { mat = (ccv_dense_matrix_t*)(data ? data : ccmalloc(ccv_compute_dense_matrix_size(rows, cols, type))); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE) & ~CCV_GARBAGE; mat->type |= data ? CCV_UNMANAGED : CCV_REUSABLE; // it still could be reusable because the signature could be derived one. mat->data.u8 = (unsigned char*)(mat + 1); } mat->sig = sig; mat->rows = rows; mat->cols = cols; mat->step = (cols * CCV_GET_DATA_TYPE_SIZE(type) * CCV_GET_CHANNEL(type) + 3) & -4; mat->refcount = 1; return mat; }
void ccv_flip(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int btype, int type) { /* this is the special case where ccv_declare_derived_signature_* macros cannot handle properly */ uint64_t sig = a->sig; if (type & CCV_FLIP_Y) sig = (a->sig == 0) ? 0 : ccv_cache_generate_signature("ccv_flip_y", 10, sig, CCV_EOF_SIGN); if (type & CCV_FLIP_X) sig = (a->sig == 0) ? 0 : ccv_cache_generate_signature("ccv_flip_x", 10, sig, CCV_EOF_SIGN); ccv_dense_matrix_t* db; if (b == 0) { db = a; if (a->sig != 0) { btype = CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type); sig = ccv_cache_generate_signature((const char*)&btype, sizeof(int), sig, CCV_EOF_SIGN); a->sig = sig; } } else { btype = CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type); *b = db = ccv_dense_matrix_renew(*b, a->rows, a->cols, btype, btype, sig); ccv_object_return_if_cached(, db); memcpy(db->data.u8, a->data.u8, a->rows * a->step); } if (type & CCV_FLIP_Y) _ccv_flip_y_self(db); if (type & CCV_FLIP_X) _ccv_flip_x_self(db); }
void ccv_subtract(ccv_matrix_t* a, ccv_matrix_t* b, ccv_matrix_t** c, int type) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_dense_matrix_t* db = ccv_get_dense_matrix(b); assert(da->rows == db->rows && da->cols == db->cols && CCV_GET_DATA_TYPE(da->type) == CCV_GET_DATA_TYPE(db->type) && CCV_GET_CHANNEL(da->type) == CCV_GET_CHANNEL(db->type)); ccv_declare_derived_signature(sig, da->sig != 0 && db->sig != 0, ccv_sign_with_literal("ccv_subtract"), da->sig, db->sig, CCV_EOF_SIGN); int no_8u_type = (da->type & CCV_8U) ? CCV_32S : da->type; type = (type == 0) ? CCV_GET_DATA_TYPE(no_8u_type) | CCV_GET_CHANNEL(da->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(da->type); ccv_dense_matrix_t* dc = *c = ccv_dense_matrix_renew(*c, da->rows, da->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(da->type), type, sig); ccv_object_return_if_cached(, dc); int i, j, ch = CCV_GET_CHANNEL(da->type); unsigned char* aptr = da->data.u8; unsigned char* bptr = db->data.u8; unsigned char* cptr = dc->data.u8; #define for_block(_for_get, _for_set) \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols * ch; j++) \ _for_set(cptr, j, _for_get(aptr, j, 0) - _for_get(bptr, j, 0), 0); \ aptr += da->step; \ bptr += db->step; \ cptr += dc->step; \ } ccv_matrix_getter(da->type, ccv_matrix_setter, dc->type, for_block); #undef for_block }
int ccv_matrix_eq(ccv_matrix_t* a, ccv_matrix_t* b) { int a_type = *(int*)a; int b_type = *(int*)b; if ((a_type & CCV_MATRIX_DENSE) && (b_type & CCV_MATRIX_DENSE)) { ccv_dense_matrix_t* da = (ccv_dense_matrix_t*)a; ccv_dense_matrix_t* db = (ccv_dense_matrix_t*)b; if (CCV_GET_DATA_TYPE(da->type) != CCV_GET_DATA_TYPE(db->type)) return -1; if (CCV_GET_CHANNEL(da->type) != CCV_GET_CHANNEL(db->type)) return -1; if (da->rows != db->rows) return -1; if (da->cols != db->cols) return -1; int i, j, ch = CCV_GET_CHANNEL(da->type); unsigned char* a_ptr = da->data.u8; unsigned char* b_ptr = db->data.u8; #define for_block(_, _for_get) \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols * ch; j++) \ { \ if (fabs(_for_get(b_ptr, j, 0) - _for_get(a_ptr, j, 0)) > 1e-4) \ return -1; \ } \ a_ptr += da->step; \ b_ptr += db->step; \ } ccv_matrix_getter(da->type, for_block); #undef for_block } return 0; }
void ccv_sample_up(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int src_x, int src_y) { assert(src_x >= 0 && src_y >= 0); ccv_declare_matrix_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_sample_up(%d,%d)", src_x, src_y), a->sig, 0); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows * 2, a->cols * 2, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_matrix_return_if_cached(, db); int ch = CCV_GET_CHANNEL(a->type); int cols0 = a->cols - 1 - src_x; int y, x, sy = -1 + src_y, sx = src_x * ch, k; int* tab = (int*)alloca((a->cols + src_x + 2) * ch * sizeof(int)); for (x = 0; x < a->cols + src_x + 2; x++) for (k = 0; k < ch; k++) tab[x * ch + k] = ((x >= a->cols) ? a->cols * 2 - 1 - x : x) * ch + k; unsigned char* buf = (unsigned char*)alloca(3 * db->cols * ch * ccv_max(CCV_GET_DATA_TYPE_SIZE(db->type), sizeof(int))); int bufstep = db->cols * ch * ccv_max(CCV_GET_DATA_TYPE_SIZE(db->type), sizeof(int)); unsigned char* b_ptr = db->data.u8; /* why src_y * 2: the same argument as in ccv_sample_down */ #define for_block(_for_get_a, _for_set, _for_get, _for_set_b) \ for (y = 0; y < a->rows; y++) \ { \ for (; sy <= y + 1 + src_y; sy++) \ { \ unsigned char* row = buf + ((sy + src_y * 2 + 1) % 3) * bufstep; \ int _sy = (sy < 0) ? -1 - sy : (sy >= a->rows) ? a->rows * 2 - 1 - sy : sy; \ unsigned char* a_ptr = a->data.u8 + a->step * _sy; \ if (a->cols == 1) \ { \ for (k = 0; k < ch; k++) \ { \ _for_set(row, k, _for_get_a(a_ptr, k, 0) * (G025 + G075 + G125), 0); \ _for_set(row, k + ch, _for_get_a(a_ptr, k, 0) * (G025 + G075 + G125), 0); \ } \ continue; \ } \ if (sx == 0) \ { \ for (k = 0; k < ch; k++) \ { \ _for_set(row, k, _for_get_a(a_ptr, k + sx, 0) * (G025 + G075) + _for_get_a(a_ptr, k + sx + ch, 0) * G125, 0); \ _for_set(row, k + ch, _for_get_a(a_ptr, k + sx, 0) * (G125 + G025) + _for_get_a(a_ptr, k + sx + ch, 0) * G075, 0); \ } \ } \ /* some serious flaw in computing Gaussian weighting in previous version * specially, we are doing perfect upsampling (2x) so, it concerns a grid like: * XXYY * XXYY * in this case, to upsampling, the weight should be from distance 0.25 and 1.25, and 0.25 and 0.75 * previously, it was mistakingly be 0.0 1.0, 0.5 0.5 (imperfect upsampling (2x - 1)) */ \ for (x = (sx == 0) ? ch : 0; x < cols0 * ch; x += ch) \ { \ for (k = 0; k < ch; k++) \ { \ _for_set(row, x * 2 + k, _for_get_a(a_ptr, x + sx - ch + k, 0) * G075 + _for_get_a(a_ptr, x + sx + k, 0) * G025 + _for_get_a(a_ptr, x + sx + ch + k, 0) * G125, 0); \ _for_set(row, x * 2 + ch + k, _for_get_a(a_ptr, x + sx - ch + k, 0) * G125 + _for_get_a(a_ptr, x + sx + k, 0) * G025 + _for_get_a(a_ptr, x + sx + ch + k, 0) * G075, 0); \ } \ } \ x_block(_for_get_a, _for_set, _for_get, _for_set_b); \ } \
double ccv_normalize(ccv_matrix_t* a, ccv_matrix_t** b, int btype, int flag) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); assert(CCV_GET_CHANNEL(da->type) == CCV_C1); ccv_declare_derived_signature(sig, da->sig != 0, ccv_sign_with_format(20, "ccv_normalize(%d)", flag), da->sig, CCV_EOF_SIGN); 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); assert(db); ccv_object_return_if_cached(db->tag.f64, db); double sum = 0, inv; int i, j; unsigned char* a_ptr = da->data.u8; unsigned char* b_ptr = db->data.u8; switch (flag) { case CCV_L1_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); \ a_ptr += da->step; \ } \ inv = 1.0 / sum; \ a_ptr = da->data.u8; \ 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; 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); \ inv = 1.0 / sum; \ a_ptr = da->data.u8; \ 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 db->tag.f64 = sum; }
static void _ccv_resample_cubic_integer_only(ccv_dense_matrix_t* a, ccv_dense_matrix_t* b) { assert(CCV_GET_DATA_TYPE(b->type) == CCV_8U || CCV_GET_DATA_TYPE(b->type) == CCV_32S || CCV_GET_DATA_TYPE(b->type) == CCV_64S); int i, j, k, ch = CCV_GET_CHANNEL(a->type); int no_8u_type = (b->type & CCV_8U) ? CCV_32S : b->type; assert(b->cols > 0); ccv_cubic_integer_coeffs_t* xofs = (ccv_cubic_integer_coeffs_t*)alloca(sizeof(ccv_cubic_integer_coeffs_t) * b->cols); float scale_x = (float)a->cols / b->cols; for (i = 0; i < b->cols; i++) { float sx = (i + 0.5) * scale_x - 0.5; _ccv_init_cubic_integer_coeffs((int)sx, a->cols, sx, xofs + i); } float scale_y = (float)a->rows / b->rows; int bufstep = b->cols * ch * CCV_GET_DATA_TYPE_SIZE(no_8u_type); unsigned char* buf = (unsigned char*)alloca(bufstep * 4); #ifdef __clang_analyzer__ memset(buf, 0, bufstep * 4); #endif unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = b->data.u8; int psi = -1, siy = 0; #define for_block(_for_get_a, _for_set, _for_get, _for_set_b) \ for (i = 0; i < b->rows; i++) \ { \ ccv_cubic_integer_coeffs_t yofs; \ float sy = (i + 0.5) * scale_y - 0.5; \ _ccv_init_cubic_integer_coeffs((int)sy, a->rows, sy, &yofs); \ if (yofs.si[3] > psi) \ { \ for (; siy <= yofs.si[3]; siy++) \ { \ unsigned char* row = buf + (siy & 0x3) * bufstep; \ for (j = 0; j < b->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set(row, j * ch + k, _for_get_a(a_ptr, xofs[j].si[0] * ch + k, 0) * xofs[j].coeffs[0] + \ _for_get_a(a_ptr, xofs[j].si[1] * ch + k, 0) * xofs[j].coeffs[1] + \ _for_get_a(a_ptr, xofs[j].si[2] * ch + k, 0) * xofs[j].coeffs[2] + \ _for_get_a(a_ptr, xofs[j].si[3] * ch + k, 0) * xofs[j].coeffs[3], 0); \ a_ptr += a->step; \ } \ psi = yofs.si[3]; \ } \ unsigned char* row[4] = { \ buf + (yofs.si[0] & 0x3) * bufstep, \ buf + (yofs.si[1] & 0x3) * bufstep, \ buf + (yofs.si[2] & 0x3) * bufstep, \ buf + (yofs.si[3] & 0x3) * bufstep, \ }; \ for (j = 0; j < b->cols * ch; j++) \ _for_set_b(b_ptr, j, ccv_descale(_for_get(row[0], j, 0) * yofs.coeffs[0] + _for_get(row[1], j, 0) * yofs.coeffs[1] + \ _for_get(row[2], j, 0) * yofs.coeffs[2] + _for_get(row[3], j, 0) * yofs.coeffs[3], 12), 0); \ b_ptr += b->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter_getter_integer_only, no_8u_type, ccv_matrix_setter_integer_only, b->type, for_block); #undef for_block }
void ccv_sat(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int padding_pattern) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(20, "ccv_sat(%d)", padding_pattern), a->sig, CCV_EOF_SIGN); int safe_type = (a->type & CCV_8U) ? ((a->rows * a->cols >= 0x808080) ? CCV_64S : CCV_32S) : ((a->type & CCV_32S) ? CCV_64S : a->type); type = (type == 0) ? CCV_GET_DATA_TYPE(safe_type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); int ch = CCV_GET_CHANNEL(a->type); int i, j; unsigned char* a_ptr = a->data.u8; ccv_dense_matrix_t* db; unsigned char* b_ptr; switch (padding_pattern) { case CCV_NO_PADDING: db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); b_ptr = db->data.u8; #define for_block(_for_set_b, _for_get_b, _for_get) \ for (j = 0; j < ch; j++) \ _for_set_b(b_ptr, j, _for_get(a_ptr, j, 0), 0); \ for (j = ch; j < a->cols * ch; j++) \ _for_set_b(b_ptr, j, _for_get_b(b_ptr, j - ch, 0) + _for_get(a_ptr, j, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ for (i = 1; i < a->rows; i++) \ { \ for (j = 0; j < ch; j++) \ _for_set_b(b_ptr, j, _for_get_b(b_ptr - db->step, j, 0) + _for_get(a_ptr, j, 0), 0); \ for (j = ch; j < a->cols * ch; j++) \ _for_set_b(b_ptr, j, _for_get_b(b_ptr, j - ch, 0) - _for_get_b(b_ptr - db->step, j - ch, 0) + _for_get_b(b_ptr - db->step, j, 0) + _for_get(a_ptr, j, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } ccv_matrix_setter_getter(db->type, ccv_matrix_getter, a->type, for_block); #undef for_block break; case CCV_PADDING_ZERO: db = *b = ccv_dense_matrix_renew(*b, a->rows + 1, a->cols + 1, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); b_ptr = db->data.u8; #define for_block(_for_set_b, _for_get_b, _for_get) \ for (j = 0; j < db->cols * ch; j++) \ _for_set_b(b_ptr, j, 0, 0); \ b_ptr += db->step; \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < ch; j++) \ _for_set_b(b_ptr, j, 0, 0); \ for (j = ch; j < db->cols * ch; j++) \ _for_set_b(b_ptr, j, _for_get_b(b_ptr, j - ch, 0) - _for_get_b(b_ptr - db->step, j - ch, 0) + _for_get_b(b_ptr - db->step, j, 0) + _for_get(a_ptr, j - ch, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } ccv_matrix_setter_getter(db->type, ccv_matrix_getter, a->type, for_block); #undef for_block break; } }
void ccv_contrast(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, double ds) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_contrast(%la)", ds), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); int i, j, k, ch = CCV_GET_CHANNEL(a->type); double* ms = (double*)malloc(sizeof(double) * ch); memset(ms, 0, sizeof(double) * ch); unsigned char* aptr = a->data.u8; #define for_block(_, _for_get) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ ms[k] += _for_get(aptr, j * ch + k, 0); \ aptr += a->step; \ } ccv_matrix_getter(a->type, for_block); #undef for_block for (i = 0; i < ch; i++) ms[i] = ms[i] / (a->rows * a->cols); aptr = a->data.u8; unsigned char* bptr = db->data.u8; if (CCV_GET_DATA_TYPE(a->type) == CCV_8U && CCV_GET_DATA_TYPE(db->type) == CCV_8U) // specialize for 8U type { unsigned char* us = (unsigned char*)malloc(sizeof(unsigned char) * ch * 256); for (i = 0; i < 256; i++) for (j = 0; j < ch; j++) us[i * ch + j] = ccv_clamp((i - ms[j]) * ds + ms[j], 0, 255); for (i = 0; i < a->rows; i++) { for (j = 0; j < a->cols; j++) for (k = 0; k < ch; k++) bptr[j * ch + k] = us[(aptr[j * ch + k]) * ch + k]; aptr += a->step; bptr += db->step; } free(us); } else { #define for_block(_for_get, _for_set) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set(bptr, j * ch + k, (_for_get(aptr, j * ch + k, 0) - ms[k]) * ds + ms[k], 0); \ aptr += a->step; \ bptr += db->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter, db->type, for_block); #undef for_block } free(ms); }
// this method is a merely baseline implementation and has no optimization effort ever put into it, if at all void ccv_perspective_transform(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_perspective_transform(%a,%a,%a,%a,%a,%a,%a,%a,%a)", m00, m01, m02, m10, m11, m12, m20, m21, m22), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); // with default of bilinear interpolation int i, j, k, ch = CCV_GET_CHANNEL(a->type); unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = db->data.u8; // assume field of view is 60, modify the matrix value to reflect that // (basically, apply x / ccv_max(a->rows, a->cols), y / ccv_max(a->rows, a->cols) before hand m00 *= 1.0 / ccv_max(a->rows, a->cols); m01 *= 1.0 / ccv_max(a->rows, a->cols); m02 *= 1.0 / ccv_max(a->rows, a->cols); m10 *= 1.0 / ccv_max(a->rows, a->cols); m11 *= 1.0 / ccv_max(a->rows, a->cols); m12 *= 1.0 / ccv_max(a->rows, a->cols); m20 *= 1.0 / (ccv_max(a->rows, a->cols) * ccv_max(a->rows, a->cols)); m21 *= 1.0 / (ccv_max(a->rows, a->cols) * ccv_max(a->rows, a->cols)); m22 *= 1.0 / ccv_max(a->rows, a->cols); #define for_block(_for_set, _for_get) \ for (i = 0; i < db->rows; i++) \ { \ float cy = i - db->rows * 0.5; \ float crx = cy * m01 + m02; \ float cry = cy * m11 + m12; \ float crz = cy * m21 + m22; \ for (j = 0; j < db->cols; j++) \ { \ float cx = j - db->cols * 0.5; \ float wz = 1.0 / (cx * m20 + crz); \ float wx = a->cols * 0.5 + (cx * m00 + crx) * wz; \ float wy = a->rows * 0.5 + (cx * m10 + cry) * wz; \ int iwx = (int)wx; \ int iwy = (int)wy; \ wx = wx - iwx; \ wy = wy - iwy; \ if (iwx >= 0 && iwx < a->cols - 1 && iwy >= 0 && iwy < a->rows - 1) \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, _for_get(a_ptr + iwy * a->step, iwx * ch + k, 0) * (1 - wx) * (1 - wy) + \ _for_get(a_ptr + iwy * a->step, iwx * ch + ch + k, 0) * wx * (1 - wy) + \ _for_get(a_ptr + iwy * a->step + a->step, iwx * ch + k, 0) * (1 - wx) * wy + \ _for_get(a_ptr + iwy * a->step + a->step, iwx * ch + ch + k, 0) * wx * wy, 0); \ else \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, 0, 0); \ } \ b_ptr += db->step; \ } ccv_matrix_setter(db->type, ccv_matrix_getter, a->type, for_block); #undef for_block }
void ccv_matrix_free(ccv_matrix_t* mat) { int type = *(int*)mat; assert(!(type & CCV_UNMANAGED)); if (type & CCV_MATRIX_DENSE) { ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat; dmt->refcount = 0; if (!ccv_cache_opt || // e don't enable cache !(dmt->type & CCV_REUSABLE) || // or this is not a reusable piece dmt->sig == 0 || // or this doesn't have valid signature (dmt->type & CCV_NO_DATA_ALLOC)) // or this matrix is allocated as header-only, therefore we cannot cache it ccfree(dmt); else { assert(CCV_GET_DATA_TYPE(dmt->type) == CCV_8U || CCV_GET_DATA_TYPE(dmt->type) == CCV_32S || CCV_GET_DATA_TYPE(dmt->type) == CCV_32F || CCV_GET_DATA_TYPE(dmt->type) == CCV_64S || CCV_GET_DATA_TYPE(dmt->type) == CCV_64F); size_t size = ccv_compute_dense_matrix_size(dmt->rows, dmt->cols, dmt->type); ccv_cache_put(&ccv_cache, dmt->sig, dmt, size, 0 /* type 0 */); } } else if (type & CCV_MATRIX_SPARSE) { ccv_sparse_matrix_t* smt = (ccv_sparse_matrix_t*)mat; int i; for (i = 0; i < CCV_GET_SPARSE_PRIME(smt->prime); i++) if (smt->vector[i].index != -1) { ccv_dense_vector_t* iter = &smt->vector[i]; ccfree(iter->data.u8); iter = iter->next; while (iter != 0) { ccv_dense_vector_t* iter_next = iter->next; ccfree(iter->data.u8); ccfree(iter); iter = iter_next; } } ccfree(smt->vector); ccfree(smt); } else if ((type & CCV_MATRIX_CSR) || (type & CCV_MATRIX_CSC)) { ccv_compressed_sparse_matrix_t* csm = (ccv_compressed_sparse_matrix_t*)mat; csm->refcount = 0; ccfree(csm); } }
ccv_dense_matrix_t* ccv_dense_matrix_renew(ccv_dense_matrix_t* x, int rows, int cols, int types, int prefer_type, uint64_t sig) { if (x != 0) { assert(x->rows == rows && x->cols == cols && (CCV_GET_DATA_TYPE(x->type) & types) && (CCV_GET_CHANNEL(x->type) == CCV_GET_CHANNEL(types))); prefer_type = CCV_GET_DATA_TYPE(x->type) | CCV_GET_CHANNEL(x->type); } if (sig != 0) sig = ccv_cache_generate_signature((const char*)&prefer_type, sizeof(int), sig, CCV_EOF_SIGN); if (x == 0) { x = ccv_dense_matrix_new(rows, cols, prefer_type, 0, sig); } else { x->sig = sig; } return x; }
void ccv_resample(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int btype, int rows, int cols, int type) { assert(rows > 0 && cols > 0); ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_resample(%d,%d,%d)", rows, cols, type), a->sig, CCV_EOF_SIGN); btype = (btype == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(btype) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), btype, sig); ccv_object_return_if_cached(, db); if (a->rows == db->rows && a->cols == db->cols) { if (CCV_GET_CHANNEL(a->type) == CCV_GET_CHANNEL(db->type) && CCV_GET_DATA_TYPE(db->type) == CCV_GET_DATA_TYPE(a->type)) memcpy(db->data.u8, a->data.u8, a->rows * a->step); else { ccv_shift(a, (ccv_matrix_t**)&db, 0, 0, 0); } return; } if ((type & CCV_INTER_AREA) && a->rows >= db->rows && a->cols >= db->cols) { /* using the fast alternative (fix point scale, 0x100 to avoid overflow) */ if (CCV_GET_DATA_TYPE(a->type) == CCV_8U && CCV_GET_DATA_TYPE(db->type) == CCV_8U && a->rows * a->cols / (db->rows * db->cols) < 0x100) _ccv_resample_area_8u(a, db); else _ccv_resample_area(a, db); } else if (type & CCV_INTER_CUBIC) { if (CCV_GET_DATA_TYPE(db->type) == CCV_32F || CCV_GET_DATA_TYPE(db->type) == CCV_64F) _ccv_resample_cubic_float_only(a, db); else _ccv_resample_cubic_integer_only(a, db); } else if (type & CCV_INTER_LINEAR) { assert(0 && "CCV_INTER_LINEAR is not implemented"); } else if (type & CCV_INTER_LINEAR) { assert(0 && "CCV_INTER_LANCZOS is not implemented"); } }
ccv_dense_matrix_t ccv_dense_matrix(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t mat; mat.sig = sig; mat.type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC | CCV_UNMANAGED) & ~CCV_GARBAGE; mat.rows = rows; mat.cols = cols; mat.step = CCV_GET_STEP(cols, type); mat.refcount = 1; #if CCV_NNC_TENSOR_TFB mat.resides = CCV_TENSOR_CPU_MEMORY; mat.format = CCV_TENSOR_FORMAT_NHWC | CCV_GET_DATA_TYPE(type); mat.channels = CCV_GET_CHANNEL(type); mat.reserved = 0; #endif mat.data.u8 = (unsigned char*)data; return mat; }
void ccv_color_transform(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int flag) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_color_transform(%d)", flag), a->sig, CCV_EOF_SIGN); assert(flag == CCV_RGB_TO_YUV); switch (flag) { case CCV_RGB_TO_YUV: assert(CCV_GET_CHANNEL(a->type) == CCV_C3); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_C3 : CCV_GET_DATA_TYPE(type) | CCV_C3; break; } ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_C3, type, sig); ccv_object_return_if_cached(, db); switch (flag) { case CCV_RGB_TO_YUV: _ccv_rgb_to_yuv(a, db); break; } }
ccv_dense_matrix_t* ccv_dense_matrix_new(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t* mat; if (ccv_cache_opt && sig != 0 && !data && !(type & CCV_NO_DATA_ALLOC)) { uint8_t type; mat = (ccv_dense_matrix_t*)ccv_cache_out(&ccv_cache, sig, &type); if (mat) { assert(type == 0); mat->type |= CCV_GARBAGE; // set the flag so the upper level function knows this is from recycle-bin mat->refcount = 1; return mat; } } if (type & CCV_NO_DATA_ALLOC) { mat = (ccv_dense_matrix_t*)ccmalloc(sizeof(ccv_dense_matrix_t)); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_NO_DATA_ALLOC) & ~CCV_GARBAGE; mat->data.u8 = data; } else { const size_t hdr_size = (sizeof(ccv_dense_matrix_t) + 15) & -16; mat = (ccv_dense_matrix_t*)(data ? data : ccmalloc(ccv_compute_dense_matrix_size(rows, cols, type))); mat->type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE) & ~CCV_GARBAGE; mat->type |= data ? CCV_UNMANAGED : CCV_REUSABLE; // it still could be reusable because the signature could be derived one. mat->data.u8 = (unsigned char*)mat + hdr_size; } mat->sig = sig; #if CCV_NNC_TENSOR_TFB mat->resides = CCV_TENSOR_CPU_MEMORY; mat->format = CCV_TENSOR_FORMAT_NHWC; mat->datatype = CCV_GET_DATA_TYPE(type); mat->channels = CCV_GET_CHANNEL(type); mat->reserved = 0; #endif mat->rows = rows; mat->cols = cols; mat->step = CCV_GET_STEP(cols, type); mat->refcount = 1; return mat; }
ccv_dense_matrix_t ccv_dense_matrix(int rows, int cols, int type, void* data, uint64_t sig) { ccv_dense_matrix_t mat; mat.sig = sig; mat.type = (CCV_GET_CHANNEL(type) | CCV_GET_DATA_TYPE(type) | CCV_MATRIX_DENSE | CCV_UNMANAGED) & ~CCV_GARBAGE; mat.rows = rows; mat.cols = cols; mat.step = (cols * CCV_GET_DATA_TYPE_SIZE(type) * CCV_GET_CHANNEL(type) + 3) & -4; mat.refcount = 1; mat.data.u8 = (unsigned char*)data; return mat; }
void ccv_gemm(ccv_matrix_t* a, ccv_matrix_t* b, double alpha, ccv_matrix_t* c, double beta, int transpose, ccv_matrix_t** d, int type) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_dense_matrix_t* db = ccv_get_dense_matrix(b); ccv_dense_matrix_t* dc = (c == 0) ? 0 : ccv_get_dense_matrix(c); assert(CCV_GET_DATA_TYPE(da->type) == CCV_GET_DATA_TYPE(db->type) && CCV_GET_CHANNEL(da->type) == 1 && CCV_GET_CHANNEL(db->type) == 1 && ((transpose & CCV_A_TRANSPOSE) ? da->rows : da->cols) == ((transpose & CCV_B_TRANSPOSE) ? db->cols : db->rows)); if (dc != 0) assert(CCV_GET_DATA_TYPE(dc->type) == CCV_GET_DATA_TYPE(da->type) && CCV_GET_CHANNEL(dc->type) == 1 && ((transpose & CCV_A_TRANSPOSE) ? da->cols : da->rows) == dc->rows && ((transpose & CCV_B_TRANSPOSE) ? db->rows : db->cols) == dc->cols); ccv_declare_derived_signature_case(sig, ccv_sign_with_format(20, "ccv_gemm(%d)", transpose), ccv_sign_if(dc == 0 && da->sig != 0 && db->sig != 0, da->sig, db->sig, CCV_EOF_SIGN), ccv_sign_if(dc != 0 && da->sig != 0 && db->sig != 0 && dc->sig != 0, da->sig, db->sig, dc->sig, CCV_EOF_SIGN)); type = CCV_GET_DATA_TYPE(da->type) | CCV_GET_CHANNEL(da->type); ccv_dense_matrix_t* dd = *d = ccv_dense_matrix_renew(*d, (transpose & CCV_A_TRANSPOSE) ? da->cols : da->rows, (transpose & CCV_B_TRANSPOSE) ? db->rows : db->cols, type, type, sig); ccv_object_return_if_cached(, dd); if (dd != dc && dc != 0) memcpy(dd->data.u8, dc->data.u8, dc->step * dc->rows); else if (dc == 0) // clean up dd if dc is not provided memset(dd->data.u8, 0, dd->step * dd->rows); #if (defined HAVE_CBLAS || defined HAVE_ACCELERATE_FRAMEWORK) switch (CCV_GET_DATA_TYPE(dd->type)) { case CCV_32F: cblas_sgemm(CblasRowMajor, (transpose & CCV_A_TRANSPOSE) ? CblasTrans : CblasNoTrans, (transpose & CCV_B_TRANSPOSE) ? CblasTrans : CblasNoTrans, dd->rows, dd->cols, (transpose & CCV_A_TRANSPOSE) ? da->rows : da->cols, alpha, da->data.f32, da->cols, db->data.f32, db->cols, beta, dd->data.f32, dd->cols); break; case CCV_64F: cblas_dgemm(CblasRowMajor, (transpose & CCV_A_TRANSPOSE) ? CblasTrans : CblasNoTrans, (transpose & CCV_B_TRANSPOSE) ? CblasTrans : CblasNoTrans, dd->rows, dd->cols, (transpose & CCV_A_TRANSPOSE) ? da->rows : da->cols, alpha, da->data.f64, da->cols, db->data.f64, db->cols, beta, dd->data.f64, dd->cols); break; } #else assert(0 && "You need a BLAS compatible library for this function, e.g. libatlas."); #endif }
void ccv_matrix_free(ccv_matrix_t* mat) { int type = *(int*)mat; assert(!(type & CCV_UNMANAGED)); if (type & CCV_MATRIX_DENSE) { ccv_dense_matrix_t* dmt = (ccv_dense_matrix_t*)mat; dmt->refcount = 0; if (!ccv_cache_opt || // e don't enable cache !(dmt->type & CCV_REUSABLE) || // or this is not a reusable piece dmt->sig == 0 || // or this doesn't have valid signature (dmt->type & CCV_NO_DATA_ALLOC)) // or this matrix is allocated as header-only, therefore we cannot cache it ccfree(dmt); else { assert(CCV_GET_DATA_TYPE(dmt->type) == CCV_8U || CCV_GET_DATA_TYPE(dmt->type) == CCV_32S || CCV_GET_DATA_TYPE(dmt->type) == CCV_32F || CCV_GET_DATA_TYPE(dmt->type) == CCV_64S || CCV_GET_DATA_TYPE(dmt->type) == CCV_64F); size_t size = ccv_compute_dense_matrix_size(dmt->rows, dmt->cols, dmt->type); ccv_cache_put(&ccv_cache, dmt->sig, dmt, size, 0 /* type 0 */); } } else if (type & CCV_MATRIX_SPARSE) { ccv_sparse_matrix_t* smt = (ccv_sparse_matrix_t*)mat; int i; for (i = 0; i < smt->size; i++) { if (smt->index[i].ifbit > 1) ccfree(smt->vector[i].index); // It is a union of index / data, can just free them. } ccfree(smt->index); ccfree(smt->vector); ccfree(smt); } else if ((type & CCV_MATRIX_CSR) || (type & CCV_MATRIX_CSC)) { ccv_compressed_sparse_matrix_t* csm = (ccv_compressed_sparse_matrix_t*)mat; csm->refcount = 0; ccfree(csm); } }
void ccv_shift(ccv_matrix_t* a, ccv_matrix_t** b, int type, int lr, int rr) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_declare_derived_signature(sig, da->sig != 0, ccv_sign_with_format(64, "ccv_shift(%d,%d)", lr, rr), da->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(da->type) | CCV_GET_CHANNEL(da->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(da->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, da->rows, da->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(da->type), type, sig); ccv_object_return_if_cached(, db); int i, j, ch = CCV_GET_CHANNEL(da->type); unsigned char* aptr = da->data.u8; unsigned char* bptr = db->data.u8; #define for_block(_for_get, _for_set) \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols * ch; j++) \ { \ _for_set(bptr, j, _for_get(aptr, j, lr), rr); \ } \ aptr += da->step; \ bptr += db->step; \ } ccv_matrix_getter(da->type, ccv_matrix_setter, db->type, for_block); #undef for_block }
void ccv_close_outline(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type) { assert((CCV_GET_CHANNEL(a->type) == CCV_C1) && ((a->type & CCV_8U) || (a->type & CCV_32S) || (a->type & CCV_64S))); ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_literal("ccv_close_outline"), a->sig, CCV_EOF_SIGN); type = ((type == 0) || (type & CCV_32F) || (type & CCV_64F)) ? CCV_GET_DATA_TYPE(a->type) | CCV_C1 : CCV_GET_DATA_TYPE(type) | CCV_C1; ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_C1 | CCV_ALL_DATA_TYPE, type, sig); ccv_object_return_if_cached(, db); int i, j; unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = db->data.u8; ccv_zero(db); #define for_block(_for_get, _for_set_b, _for_get_b) \ for (i = 0; i < a->rows - 1; i++) \ { \ for (j = 0; j < a->cols - 1; j++) \ { \ if (!_for_get_b(b_ptr, j, 0)) \ _for_set_b(b_ptr, j, _for_get(a_ptr, j, 0), 0); \ if (_for_get(a_ptr, j, 0) && _for_get(a_ptr + a->step, j + 1, 0)) \ { \ _for_set_b(b_ptr + a->step, j, 1, 0); \ _for_set_b(b_ptr, j + 1, 1, 0); \ } \ if (_for_get(a_ptr + a->step, j, 0) && _for_get(a_ptr, j + 1, 0)) \ { \ _for_set_b(b_ptr, j, 1, 0); \ _for_set_b(b_ptr + a->step, j + 1, 1, 0); \ } \ } \ if (!_for_get_b(b_ptr, a->cols - 1, 0)) \ _for_set_b(b_ptr, a->cols - 1, _for_get(a_ptr, a->cols - 1, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } \ for (j = 0; j < a->cols; j++) \ { \ if (!_for_get_b(b_ptr, j, 0)) \ _for_set_b(b_ptr, j, _for_get(a_ptr, j, 0), 0); \ } ccv_matrix_getter_integer_only(a->type, ccv_matrix_setter_getter_integer_only, db->type, for_block); #undef for_block }
void ccv_decimal_slice(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, float y, float x, int rows, int cols) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_decimal_slice(%a,%a,%d,%d)", y, x, rows, cols), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, rows, cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); int i, j, ch = CCV_GET_CHANNEL(a->type); int ix = (int)x, iy = (int)y; float xd = x - ix, yd = y - iy; float w00 = (1 - xd) * (1 - yd); float w01 = xd * (1 - yd); float w10 = (1 - xd) * yd; float w11 = xd * yd; int dx = 0, dy = 0; int rows_1 = 0, cols_1 = 0; // it is going to be hard to deal with border efficiently, since this is used for tld, will ignore border for now if (!(iy >= 0 && iy + rows < a->rows && ix >= 0 && ix + cols < a->cols)) { ccv_zero(db); if (iy < 0) { rows += iy; dy = -iy; iy = 0; } if (iy + rows >= a->rows) { rows = a->rows - iy - 1; if (iy + rows > a->rows) rows_1 = 1; // we need to do our best to padding the last row } if (ix < 0) { cols += ix; dx = -ix; ix = 0; } if (x + cols >= a->cols) { cols = a->cols - ix - 1; if (x + cols > a->cols) cols_1 = 1; // we need to do our best to padding the last col } } unsigned char* a_ptr = (unsigned char*)ccv_get_dense_matrix_cell(a, iy, ix, 0); unsigned char* b_ptr = (unsigned char*)ccv_get_dense_matrix_cell(db, dy, dx, 0); #define for_block(_for_set, _for_get) \ for (i = 0; i < rows; i++) \ { \ for (j = 0; j < cols * ch; j++) \ { \ _for_set(b_ptr, j, (_for_get(a_ptr, j, 0) * G00 + _for_get(a_ptr, j + ch, 0) * G01 + _for_get(a_ptr + a->step, j, 0) * G10 + _for_get(a_ptr + a->step, j + ch, 0) * G11) / GALL, 0); \ } \ if (cols_1) \ _for_set(b_ptr, j, (_for_get(a_ptr, j, 0) * (G00 + G01) + _for_get(a_ptr + a->step, j, 0) * G10 + _for_get(a_ptr + a->step, j + ch, 0) * G11) / GALL, 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } \ if (rows_1) \ { \ for (j = 0; j < cols * ch; j++) \ { \ _for_set(b_ptr, j, (_for_get(a_ptr, j, 0) * (G00 + G10) + _for_get(a_ptr, j + ch, 0) * (G01 + G11)) / GALL, 0); \ } \ if (cols_1) \ _for_set(b_ptr, j, _for_get(a_ptr, j, 0), 0); \ } /* unswitch in the manual way so that we can use integer interpolation */ if ((a->type & CCV_8U) || (a->type & CCV_32S) || (a->type & CCV_64S)) { const int W_BITS14 = 14; int iw00 = (int)(w00 * (1 << W_BITS14) + 0.5); int iw01 = (int)(w01 * (1 << W_BITS14) + 0.5); int iw10 = (int)(w10 * (1 << W_BITS14) + 0.5); int iw11 = (1 << W_BITS14) - iw00 - iw01 - iw10; #define G00 (iw00) #define G01 (iw01) #define G10 (iw10) #define G11 (iw11) #define GCOM (1 << (W_BITS14 - 1)) #define GALL (1 << (W_BITS14)) ccv_matrix_setter(db->type, ccv_matrix_getter_integer_only, a->type, for_block); #undef G00 #undef G01 #undef G10 #undef G11 #undef GCOM #undef GALL } else { #define G00 (w00) #define G01 (w01) #define G10 (w10) #define G11 (w11) #define GCOM (0) #define GALL (1) ccv_matrix_setter(db->type, ccv_matrix_getter_float_only, a->type, for_block); #undef G00 #undef G01 #undef G10 #undef G11 #undef GCOM #undef GALL } #undef for_block }
/* the following code is adopted from OpenCV cvPyrDown */ void ccv_sample_down(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int src_x, int src_y) { assert(src_x >= 0 && src_y >= 0); ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_sample_down(%d,%d)", src_x, src_y), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows / 2, a->cols / 2, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); int ch = CCV_GET_CHANNEL(a->type); int cols0 = db->cols - 1 - src_x; int dy, sy = -2 + src_y, sx = src_x * ch, dx, k; int* tab = (int*)alloca((a->cols + src_x + 2) * ch * sizeof(int)); for (dx = 0; dx < a->cols + src_x + 2; dx++) for (k = 0; k < ch; k++) tab[dx * ch + k] = ((dx >= a->cols) ? a->cols * 2 - 1 - dx : dx) * ch + k; unsigned char* buf = (unsigned char*)alloca(5 * db->cols * ch * ccv_max(CCV_GET_DATA_TYPE_SIZE(db->type), sizeof(int))); int bufstep = db->cols * ch * ccv_max(CCV_GET_DATA_TYPE_SIZE(db->type), sizeof(int)); #ifdef __clang_analyzer__ memset(buf, 0, 5 * bufstep); #endif unsigned char* b_ptr = db->data.u8; /* why is src_y * 4 in computing the offset of row? * Essentially, it means sy - src_y but in a manner that doesn't result negative number. * notice that we added src_y before when computing sy in the first place, however, * it is not desirable to have that offset when we try to wrap it into our 5-row buffer ( * because in later rearrangement, we have no src_y to backup the arrangement). In * such micro scope, we managed to stripe 5 addition into one shift and addition. */ #define for_block(_for_get_a, _for_set, _for_get, _for_set_b) \ for (dy = 0; dy < db->rows; dy++) \ { \ for(; sy <= dy * 2 + 2 + src_y; sy++) \ { \ unsigned char* row = buf + ((sy + src_y * 4 + 2) % 5) * bufstep; \ int _sy = (sy < 0) ? -1 - sy : (sy >= a->rows) ? a->rows * 2 - 1 - sy : sy; \ unsigned char* a_ptr = a->data.u8 + a->step * _sy; \ for (k = 0; k < ch; k++) \ _for_set(row, k, _for_get_a(a_ptr, sx + k, 0) * 10 + _for_get_a(a_ptr, ch + sx + k, 0) * 5 + _for_get_a(a_ptr, 2 * ch + sx + k, 0), 0); \ for(dx = ch; dx < cols0 * ch; dx += ch) \ for (k = 0; k < ch; k++) \ _for_set(row, dx + k, _for_get_a(a_ptr, dx * 2 + sx + k, 0) * 6 + (_for_get_a(a_ptr, dx * 2 + sx + k - ch, 0) + _for_get_a(a_ptr, dx * 2 + sx + k + ch, 0)) * 4 + _for_get_a(a_ptr, dx * 2 + sx + k - ch * 2, 0) + _for_get_a(a_ptr, dx * 2 + sx + k + ch * 2, 0), 0); \ x_block(_for_get_a, _for_set, _for_get, _for_set_b); \ } \ unsigned char* rows[5]; \ for(k = 0; k < 5; k++) \ rows[k] = buf + ((dy * 2 + k) % 5) * bufstep; \ for(dx = 0; dx < db->cols * ch; dx++) \ _for_set_b(b_ptr, dx, (_for_get(rows[2], dx, 0) * 6 + (_for_get(rows[1], dx, 0) + _for_get(rows[3], dx, 0)) * 4 + _for_get(rows[0], dx, 0) + _for_get(rows[4], dx, 0)) / 256, 0); \ b_ptr += db->step; \ } int no_8u_type = (a->type & CCV_8U) ? CCV_32S : a->type; if (src_x > 0) { #define x_block(_for_get_a, _for_set, _for_get, _for_set_b) \ for (dx = cols0 * ch; dx < db->cols * ch; dx += ch) \ for (k = 0; k < ch; k++) \ _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); ccv_matrix_getter_a(a->type, ccv_matrix_setter_getter, no_8u_type, ccv_matrix_setter_b, db->type, for_block); #undef x_block } else { #define x_block(_for_get_a, _for_set, _for_get, _for_set_b) \ for (k = 0; k < ch; k++) \ _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); ccv_matrix_getter_a(a->type, ccv_matrix_setter_getter, no_8u_type, ccv_matrix_setter_b, db->type, for_block); #undef x_block } #undef for_block }
/* sobel filter is fundamental to many other high-level algorithms, * here includes 2 special case impl (for 1x3/3x1, 3x3) and one general impl */ void ccv_sobel(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, int dx, int dy) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_sobel(%d,%d)", dx, dy), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_32S | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_GET_CHANNEL(a->type) | CCV_ALL_DATA_TYPE, type, sig); ccv_object_return_if_cached(, db); int i, j, k, c, ch = CCV_GET_CHANNEL(a->type); unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = db->data.u8; if (dx == 1 || dy == 1) { /* special case 1: 1x3 or 3x1 window */ if (dx > dy) { #define for_block(_for_get, _for_set) \ for (i = 0; i < a->rows; i++) \ { \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, k, _for_get(a_ptr, ch + k, 0) - _for_get(a_ptr, k, 0), 0); \ for (j = 1; j < a->cols - 1; j++) \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, 2 * (_for_get(a_ptr, (j + 1) * ch + k, 0) - _for_get(a_ptr, (j - 1) * ch + k, 0)), 0); \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, (a->cols - 1) * ch + k, _for_get(a_ptr, (a->cols - 1) * ch + k, 0) - _for_get(a_ptr, (a->cols - 2) * ch + k, 0), 0); \ b_ptr += db->step; \ a_ptr += a->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter, db->type, for_block); #undef for_block } else { #define for_block(_for_get, _for_set) \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, _for_get(a_ptr + a->step, j * ch + k, 0) - _for_get(a_ptr, j * ch + k, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ for (i = 1; i < a->rows - 1; i++) \ { \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, 2 * (_for_get(a_ptr + a->step, j * ch + k, 0) - _for_get(a_ptr - a->step, j * ch + k, 0)), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set(b_ptr, j * ch + k, _for_get(a_ptr, j * ch + k, 0) - _for_get(a_ptr - a->step, j * ch + k, 0), 0); ccv_matrix_getter(a->type, ccv_matrix_setter, db->type, for_block); #undef for_block } } else if (dx > 3 || dy > 3) { /* general case: in this case, I will generate a separable filter, and do the convolution */ int fsz = ccv_max(dx, dy); assert(fsz % 2 == 1); int hfz = fsz / 2; unsigned char* df = (unsigned char*)alloca(sizeof(double) * fsz); unsigned char* gf = (unsigned char*)alloca(sizeof(double) * fsz); /* the sigma calculation is linear derviation of 3x3 - 0.85, 5x5 - 1.32 */ double sigma = ((fsz - 1) / 2) * 0.47 + 0.38; double sigma2 = (2.0 * sigma * sigma); /* 2.5 is the factor to make the kernel "visible" in integer setting */ double psigma3 = 2.5 / sqrt(sqrt(2 * CCV_PI) * sigma * sigma * sigma); for (i = 0; i < fsz; i++) { ((double*)df)[i] = (i - hfz) * exp(-((i - hfz) * (i - hfz)) / sigma2) * psigma3; ((double*)gf)[i] = exp(-((i - hfz) * (i - hfz)) / sigma2) * psigma3; } if (db->type & CCV_32S) { for (i = 0; i < fsz; i++) { // df could be negative, thus, (int)(x + 0.5) shortcut will not work ((int*)df)[i] = (int)round(((double*)df)[i] * 256.0); ((int*)gf)[i] = (int)(((double*)gf)[i] * 256.0 + 0.5); } } else { for (i = 0; i < fsz; i++) { ccv_set_value(db->type, df, i, ((double*)df)[i], 0); ccv_set_value(db->type, gf, i, ((double*)gf)[i], 0); } } if (dx < dy) { unsigned char* tf = df; df = gf; gf = tf; } unsigned char* buf = (unsigned char*)alloca(sizeof(double) * ch * (fsz + ccv_max(a->rows, a->cols))); #define for_block(_for_get, _for_type_b, _for_set_b, _for_get_b) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < hfz; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + k, _for_get(a_ptr, k, 0), 0); \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (j + hfz) * ch + k, _for_get(a_ptr, j * ch + k, 0), 0); \ for (j = a->cols; j < a->cols + hfz; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (j + hfz) * ch + k, _for_get(a_ptr, (a->cols - 1) * ch + k, 0), 0); \ for (j = 0; j < a->cols; j++) \ { \ for (c = 0; c < ch; c++) \ { \ _for_type_b sum = 0; \ for (k = 0; k < fsz; k++) \ sum += _for_get_b(buf, (j + k) * ch + c, 0) * _for_get_b(df, k, 0); \ _for_set_b(b_ptr, j * ch + c, sum, 8); \ } \ } \ a_ptr += a->step; \ b_ptr += db->step; \ } \ b_ptr = db->data.u8; \ for (i = 0; i < a->cols; i++) \ { \ for (j = 0; j < hfz; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + k, _for_get_b(b_ptr, i * ch + k, 0), 0); \ for (j = 0; j < a->rows; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (j + hfz) * ch + k, _for_get_b(b_ptr + j * db->step, i * ch + k, 0), 0); \ for (j = a->rows; j < a->rows + hfz; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (j + hfz) * ch + k, _for_get_b(b_ptr + (a->rows - 1) * db->step, i * ch + k, 0), 0); \ for (j = 0; j < a->rows; j++) \ { \ for (c = 0; c < ch; c++) \ { \ _for_type_b sum = 0; \ for (k = 0; k < fsz; k++) \ sum += _for_get_b(buf, (j + k) * ch + c, 0) * _for_get_b(gf, k, 0); \ _for_set_b(b_ptr + j * db->step, i * ch + c, sum, 8); \ } \ } \ } ccv_matrix_getter(a->type, ccv_matrix_typeof_setter_getter, db->type, for_block); #undef for_block } else { /* special case 2: 3x3 window, corresponding sigma = 0.85 */ unsigned char* buf = (unsigned char*)alloca(db->step); if (dx > dy) { #define for_block(_for_get, _for_set_b, _for_get_b) \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, _for_get(a_ptr + a->step, j * ch + k, 0) + 3 * _for_get(a_ptr, j * ch + k, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ for (i = 1; i < a->rows - 1; i++) \ { \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, _for_get(a_ptr + a->step, j * ch + k, 0) + 2 * _for_get(a_ptr, j * ch + k, 0) + _for_get(a_ptr - a->step, j * ch + k, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, 3 * _for_get(a_ptr, j * ch + k, 0) + _for_get(a_ptr - a->step, j * ch + k, 0), 0); \ b_ptr = db->data.u8; \ for (i = 0; i < a->rows; i++) \ { \ for (k = 0; k < ch; k++) \ _for_set_b(buf, k, _for_get_b(b_ptr, ch + k, 0) - _for_get_b(b_ptr, k, 0), 0); \ for (j = 1; j < a->cols - 1; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + k, _for_get_b(b_ptr, (j + 1) * ch + k, 0) - _for_get_b(b_ptr, (j - 1) * ch + k, 0), 0); \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (a->cols - 1) * ch + k, _for_get_b(b_ptr, (a->cols - 1) * ch + k, 0) - _for_get_b(b_ptr, (a->cols - 2) * ch + k, 0), 0); \ memcpy(b_ptr, buf, db->step); \ b_ptr += db->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter_getter, db->type, for_block); #undef for_block } else { #define for_block(_for_get, _for_set_b, _for_get_b) \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, _for_get(a_ptr + a->step, j * ch + k, 0) - _for_get(a_ptr, j * ch + k, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ for (i = 1; i < a->rows - 1; i++) \ { \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, _for_get(a_ptr + a->step, j * ch + k, 0) - _for_get(a_ptr - a->step, j * ch + k, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } \ for (j = 0; j < a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(b_ptr, j * ch + k, _for_get(a_ptr, j * ch + k, 0) - _for_get(a_ptr - a->step, j * ch + k, 0), 0); \ b_ptr = db->data.u8; \ for (i = 0; i < a->rows; i++) \ { \ for (k = 0; k < ch; k++) \ _for_set_b(buf, k, _for_get_b(b_ptr, ch + k, 0) + 3 * _for_get_b(b_ptr, k, 0), 0); \ for (j = 1; j < a->cols - 1; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + k, _for_get_b(b_ptr, (j + 1) * ch + k, 0) + 2 * _for_get_b(b_ptr, j * ch + k, 0) + _for_get_b(b_ptr, (j - 1) * ch + k, 0), 0); \ for (k = 0; k < ch; k++) \ _for_set_b(buf, (a->cols - 1) * ch + k, _for_get_b(b_ptr, (a->cols - 2) * ch + k, 0) + 3 * _for_get_b(b_ptr, (a->cols - 1) * ch + k, 0), 0); \ memcpy(b_ptr, buf, db->step); \ b_ptr += db->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter_getter, db->type, for_block); #undef for_block } } }
void ccv_blur(ccv_dense_matrix_t* a, ccv_dense_matrix_t** b, int type, double sigma) { ccv_declare_derived_signature(sig, a->sig != 0, ccv_sign_with_format(64, "ccv_blur(%la)", sigma), a->sig, CCV_EOF_SIGN); type = (type == 0) ? CCV_GET_DATA_TYPE(a->type) | CCV_GET_CHANNEL(a->type) : CCV_GET_DATA_TYPE(type) | CCV_GET_CHANNEL(a->type); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, a->rows, a->cols, CCV_ALL_DATA_TYPE | CCV_GET_CHANNEL(a->type), type, sig); ccv_object_return_if_cached(, db); int fsz = ccv_max(1, (int)(4.0 * sigma + 1.0 - 1e-8)) * 2 + 1; int hfz = fsz / 2; unsigned char* buf = (unsigned char*)alloca(sizeof(double) * ccv_max(fsz + a->rows, (fsz + a->cols) * CCV_GET_CHANNEL(a->type))); unsigned char* filter = (unsigned char*)alloca(sizeof(double) * fsz); double tw = 0; int i, j, k, ch = CCV_GET_CHANNEL(a->type); for (i = 0; i < fsz; i++) tw += ((double*)filter)[i] = exp(-((i - hfz) * (i - hfz)) / (2.0 * sigma * sigma)); int no_8u_type = (db->type & CCV_8U) ? CCV_32S : db->type; if (no_8u_type & CCV_32S) { tw = 256.0 / tw; for (i = 0; i < fsz; i++) ((int*)filter)[i] = (int)(((double*)filter)[i] * tw + 0.5); } else { tw = 1.0 / tw; for (i = 0; i < fsz; i++) ccv_set_value(db->type, filter, i, ((double*)filter)[i] * tw, 0); } /* horizontal */ unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = db->data.u8; #define for_block(_for_type, _for_set_b, _for_get_b, _for_set_a, _for_get_a) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < hfz; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + k, _for_get_a(a_ptr, k, 0), 0); \ for (j = 0; j < a->cols * ch; j++) \ _for_set_b(buf, j + hfz * ch, _for_get_a(a_ptr, j, 0), 0); \ for (j = a->cols; j < hfz + a->cols; j++) \ for (k = 0; k < ch; k++) \ _for_set_b(buf, j * ch + hfz * ch + k, _for_get_a(a_ptr, (a->cols - 1) * ch + k, 0), 0); \ for (j = 0; j < a->cols * ch; j++) \ { \ _for_type sum = 0; \ for (k = 0; k < fsz; k++) \ sum += _for_get_b(buf, k * ch + j, 0) * _for_get_b(filter, k, 0); \ _for_set_b(buf, j, sum, 8); \ } \ for (j = 0; j < a->cols * ch; j++) \ _for_set_a(b_ptr, j, _for_get_b(buf, j, 0), 0); \ a_ptr += a->step; \ b_ptr += db->step; \ } ccv_matrix_typeof_setter_getter(no_8u_type, ccv_matrix_setter, db->type, ccv_matrix_getter, a->type, for_block); #undef for_block /* vertical */ b_ptr = db->data.u8; #define for_block(_for_type, _for_set_b, _for_get_b, _for_set_a, _for_get_a) \ for (i = 0; i < a->cols * ch; i++) \ { \ for (j = 0; j < hfz; j++) \ _for_set_b(buf, j, _for_get_a(b_ptr, i, 0), 0); \ for (j = 0; j < a->rows; j++) \ _for_set_b(buf, j + hfz, _for_get_a(b_ptr + j * db->step, i, 0), 0); \ for (j = a->rows; j < hfz + a->rows; j++) \ _for_set_b(buf, j + hfz, _for_get_a(b_ptr + (a->rows - 1) * db->step, i, 0), 0); \ for (j = 0; j < a->rows; j++) \ { \ _for_type sum = 0; \ for (k = 0; k < fsz; k++) \ sum += _for_get_b(buf, k + j, 0) * _for_get_b(filter, k, 0); \ _for_set_b(buf, j, sum, 8); \ } \ for (j = 0; j < a->rows; j++) \ _for_set_a(b_ptr + j * db->step, i, _for_get_b(buf, j, 0), 0); \ } ccv_matrix_typeof_setter_getter(no_8u_type, ccv_matrix_setter_getter, db->type, for_block); #undef for_block }
void ccv_compress_sparse_matrix(ccv_sparse_matrix_t* mat, ccv_compressed_sparse_matrix_t** csm) { int i, j; int nnz = 0; int length = CCV_GET_SPARSE_PRIME(mat->prime); for (i = 0; i < length; i++) { ccv_dense_vector_t* vector = &mat->vector[i]; #define while_block(_, _while_get) \ while (vector != 0) \ { \ if (vector->index != -1) \ { \ if (mat->type & CCV_DENSE_VECTOR) \ { \ for (j = 0; j < vector->length; j++) \ if (_while_get(vector->data.u8, j, 0) != 0) \ nnz++; \ } else { \ nnz += vector->load_factor; \ } \ } \ vector = vector->next; \ } ccv_matrix_getter(mat->type, while_block); #undef while_block } ccv_compressed_sparse_matrix_t* cm = *csm = (ccv_compressed_sparse_matrix_t*)ccmalloc(sizeof(ccv_compressed_sparse_matrix_t) + nnz * sizeof(int) + nnz * CCV_GET_DATA_TYPE_SIZE(mat->type) + (((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows) + 1) * sizeof(int)); cm->type = (mat->type & ~CCV_MATRIX_SPARSE & ~CCV_SPARSE_VECTOR & ~CCV_DENSE_VECTOR) | ((mat->major == CCV_SPARSE_COL_MAJOR) ? CCV_MATRIX_CSC : CCV_MATRIX_CSR); cm->nnz = nnz; cm->rows = mat->rows; cm->cols = mat->cols; cm->index = (int*)(cm + 1); cm->offset = cm->index + nnz; cm->data.i32 = cm->offset + ((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows) + 1; unsigned char* m_ptr = cm->data.u8; int* idx = cm->index; cm->offset[0] = 0; for (i = 0; i < ((mat->major == CCV_SPARSE_COL_MAJOR) ? mat->cols : mat->rows); i++) { ccv_dense_vector_t* vector = ccv_get_sparse_matrix_vector(mat, i); if (vector == 0) cm->offset[i + 1] = cm->offset[i]; else { if (mat->type & CCV_DENSE_VECTOR) { int k = 0; #define for_block(_, _for_set, _for_get) \ for (j = 0; j < vector->length; j++) \ if (_for_get(vector->data.u8, j, 0) != 0) \ { \ _for_set(m_ptr, k, _for_get(vector->data.u8, j, 0), 0); \ idx[k] = j; \ k++; \ } ccv_matrix_setter_getter(mat->type, for_block); #undef for_block cm->offset[i + 1] = cm->offset[i] + k; idx += k; m_ptr += k * CCV_GET_DATA_TYPE_SIZE(mat->type); } else { int k = 0; #define for_block(_, _for_set, _for_get) \ for (j = 0; j < vector->length; j++) \ if (vector->indice[j] != -1) \ { \ _for_set(m_ptr, k, _for_get(vector->data.u8, j, 0), 0); \ idx[k] = vector->indice[j]; \ k++; \ } ccv_matrix_setter_getter(mat->type, for_block); #undef for_block switch (CCV_GET_DATA_TYPE(mat->type)) { case CCV_8U: _ccv_indice_uchar_sort(idx, vector->load_factor, (unsigned char*)m_ptr); break; case CCV_32S: _ccv_indice_int_sort(idx, vector->load_factor, (int*)m_ptr); break; case CCV_32F: _ccv_indice_float_sort(idx, vector->load_factor, (float*)m_ptr); break; case CCV_64F: _ccv_indice_double_sort(idx, vector->load_factor, (double*)m_ptr); break; } cm->offset[i + 1] = cm->offset[i] + vector->load_factor; idx += vector->load_factor; m_ptr += vector->load_factor * CCV_GET_DATA_TYPE_SIZE(mat->type); } } } }