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); }
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 }
double ccv_sum(ccv_matrix_t* mat, int flag) { ccv_dense_matrix_t* dmt = ccv_get_dense_matrix(mat); double sum = 0; unsigned char* m_ptr = dmt->data.u8; int i, j, ch = CCV_GET_CHANNEL(dmt->type); #define for_block(_, _for_get) \ switch (flag) \ { \ case CCV_UNSIGNED: \ for (i = 0; i < dmt->rows; i++) \ { \ for (j = 0; j < dmt->cols * ch; j++) \ sum += fabs((double)(_for_get(m_ptr, j, 0))); \ m_ptr += dmt->step; \ } \ break; \ case CCV_SIGNED: \ default: \ for (i = 0; i < dmt->rows; i++) \ { \ for (j = 0; j < dmt->cols * ch; j++) \ sum += _for_get(m_ptr, j, 0); \ m_ptr += dmt->step; \ } \ } ccv_matrix_getter(dmt->type, for_block); #undef for_block return sum; }
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 }
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_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 }
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 }
int ccv_otsu(ccv_dense_matrix_t* a, double* outvar, int range) { assert((a->type & CCV_32S) || (a->type & CCV_8U)); int* histogram = (int*)malloc(range * sizeof(int)); memset(histogram, 0, sizeof(int) * range); int i, j; unsigned char* a_ptr = a->data.u8; #define for_block(_, _for_get) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ histogram[ccv_clamp((int)_for_get(a_ptr, j, 0), 0, range - 1)]++; \ a_ptr += a->step; \ } ccv_matrix_getter(a->type, for_block); #undef for_block double sum = 0, sumB = 0; for (i = 0; i < range; i++) sum += i * histogram[i]; int wB = 0, wF = 0, total = a->rows * a->cols; double maxVar = 0; int threshold = 0; for (i = 0; i < range; i++) { wB += histogram[i]; if (wB == 0) continue; wF = total - wB; if (wF == 0) break; sumB += i * histogram[i]; double mB = sumB / wB; double mF = (sum - sumB) / wF; double var = wB * wF * (mB - mF) * (mB - mF); if (var > maxVar) { maxVar = var; threshold = i; } } if (outvar != 0) *outvar = maxVar / total / total; free(histogram); return threshold; }
static void _ccv_rgb_to_yuv(ccv_dense_matrix_t* a, ccv_dense_matrix_t* b) { unsigned char* a_ptr = a->data.u8; unsigned char* b_ptr = b->data.u8; int i, j; #define for_block(_for_get, _for_set_b, _for_get_b) \ for (i = 0; i < a->rows; i++) \ { \ for (j = 0; j < a->cols; j++) \ { \ _for_set_b(b_ptr, j * 3, (_for_get(a_ptr, j * 3, 0) * 1225 + _for_get(a_ptr, j * 3 + 1, 0) * 2404 + _for_get(a_ptr, j * 3 + 2, 0) * 467) / 4096, 0); \ _for_set_b(b_ptr, j * 3 + 1, (_for_get(a_ptr, j * 3 + 2, 0) - _for_get_b(b_ptr, j * 3, 0)) * 2015 / 4096 + 128, 0); \ _for_set_b(b_ptr, j * 3 + 2, (_for_get(a_ptr, j * 3, 0) - _for_get_b(b_ptr, j * 3, 0)) * 3592 / 4096 + 128, 0); \ } \ a_ptr += a->step; \ b_ptr += b->step; \ } ccv_matrix_getter(a->type, ccv_matrix_setter_getter, b->type, for_block); #undef for_block }
double ccv_variance(ccv_matrix_t* mat) { ccv_dense_matrix_t* dmt = ccv_get_dense_matrix(mat); double mean = 0, variance = 0; unsigned char* m_ptr = dmt->data.u8; int i, j, ch = CCV_GET_CHANNEL(dmt->type); #define for_block(_, _for_get) \ for (i = 0; i < dmt->rows; i++) \ { \ for (j = 0; j < dmt->cols * ch; j++) \ { \ mean += _for_get(m_ptr, j, 0); \ variance += _for_get(m_ptr, j, 0) * _for_get(m_ptr, j, 0); \ } \ m_ptr += dmt->step; \ } ccv_matrix_getter(dmt->type, for_block); #undef for_block mean = mean / (dmt->rows * dmt->cols * ch); variance = variance / (dmt->rows * dmt->cols * ch); return variance - mean * mean; }
void ccv_visualize(ccv_matrix_t* a, ccv_dense_matrix_t** b, int type) { ccv_dense_matrix_t* da = ccv_get_dense_matrix(a); ccv_declare_derived_signature(sig, da->sig != 0, ccv_sign_with_literal("ccv_visualize"), da->sig, CCV_EOF_SIGN); ccv_dense_matrix_t* db = *b = ccv_dense_matrix_renew(*b, da->rows, da->cols, CCV_8U | CCV_C1, CCV_8U | CCV_C1, sig); ccv_object_return_if_cached(, db); ccv_dense_matrix_t* dc = 0; if (CCV_GET_CHANNEL(da->type) > CCV_C1) { ccv_flatten(da, (ccv_matrix_t**)&dc, 0, 0); da = dc; } int i, j; double minval = DBL_MAX, maxval = -DBL_MAX; unsigned char* aptr = da->data.u8; unsigned char* bptr = db->data.u8; #define for_block(_, _for_get) \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols; j++) \ { \ minval = ccv_min(minval, _for_get(aptr, j, 0)); \ maxval = ccv_max(maxval, _for_get(aptr, j, 0)); \ } \ aptr += da->step; \ } \ aptr = da->data.u8; \ for (i = 0; i < da->rows; i++) \ { \ for (j = 0; j < da->cols; j++) \ bptr[j] = ccv_clamp((_for_get(aptr, j, 0) - minval) * 255.0 / (maxval - minval), 0, 255); \ aptr += da->step; \ bptr += db->step; \ } ccv_matrix_getter(da->type, for_block); #undef for_block if (dc != 0) ccv_matrix_free(dc); }
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 }
static void _ccv_resample_area(ccv_dense_matrix_t* a, ccv_dense_matrix_t* b) { assert(a->cols > 0 && b->cols > 0); ccv_area_alpha_t* xofs = (ccv_area_alpha_t*)alloca(sizeof(ccv_area_alpha_t) * a->cols * 2); int ch = CCV_GET_CHANNEL(a->type); double scale_x = (double)a->cols / b->cols; double scale_y = (double)a->rows / b->rows; double scale = 1.f / (scale_x * scale_y); int dx, dy, sx, sy, i, k; for (dx = 0, k = 0; dx < b->cols; dx++) { double fsx1 = dx * scale_x, fsx2 = fsx1 + scale_x; int sx1 = (int)(fsx1 + 1.0 - 1e-6), sx2 = (int)(fsx2); sx1 = ccv_min(sx1, a->cols - 1); sx2 = ccv_min(sx2, a->cols - 1); if (sx1 > fsx1) { xofs[k].di = dx * ch; xofs[k].si = (sx1 - 1) * ch; xofs[k++].alpha = (float)((sx1 - fsx1) * scale); } for (sx = sx1; sx < sx2; sx++) { xofs[k].di = dx * ch; xofs[k].si = sx * ch; xofs[k++].alpha = (float)scale; } if (fsx2 - sx2 > 1e-3) { xofs[k].di = dx * ch; xofs[k].si = sx2 * ch; xofs[k++].alpha = (float)((fsx2 - sx2) * scale); } } int xofs_count = k; float* buf = (float*)alloca(b->cols * ch * sizeof(float)); float* sum = (float*)alloca(b->cols * ch * sizeof(float)); for (dx = 0; dx < b->cols * ch; dx++) buf[dx] = sum[dx] = 0; dy = 0; #define for_block(_for_get, _for_set) \ for (sy = 0; sy < a->rows; sy++) \ { \ unsigned char* a_ptr = a->data.u8 + a->step * sy; \ for (k = 0; k < xofs_count; k++) \ { \ int dxn = xofs[k].di; \ float alpha = xofs[k].alpha; \ for (i = 0; i < ch; i++) \ buf[dxn + i] += _for_get(a_ptr, xofs[k].si + i, 0) * alpha; \ } \ if ((dy + 1) * scale_y <= sy + 1 || sy == a->rows - 1) \ { \ float beta = ccv_max(sy + 1 - (dy + 1) * scale_y, 0.f); \ float beta1 = 1 - beta; \ unsigned char* b_ptr = b->data.u8 + b->step * dy; \ if (fabs(beta) < 1e-3) \ { \ for (dx = 0; dx < b->cols * ch; dx++) \ { \ _for_set(b_ptr, dx, sum[dx] + buf[dx], 0); \ sum[dx] = buf[dx] = 0; \ } \ } else { \ for (dx = 0; dx < b->cols * ch; dx++) \ { \ _for_set(b_ptr, dx, sum[dx] + buf[dx] * beta1, 0); \ sum[dx] = buf[dx] * beta; \ buf[dx] = 0; \ } \ } \ dy++; \ } \ else \ { \ for(dx = 0; dx < b->cols * ch; dx++) \ { \ sum[dx] += buf[dx]; \ buf[dx] = 0; \ } \ } \ } ccv_matrix_getter(a->type, ccv_matrix_setter, b->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); } } } }
/* 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 } } }