Пример #1
0
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
}
Пример #2
0
static void _ccv_set_union_mser(ccv_dense_matrix_t* a, ccv_dense_matrix_t* h, ccv_dense_matrix_t* b, ccv_array_t* seq, ccv_mser_param_t params)
{
	assert(params.direction == CCV_BRIGHT_TO_DARK || params.direction == CCV_DARK_TO_BRIGHT);
	int v, i, j;
	ccv_mser_node_t* node = (ccv_mser_node_t*)ccmalloc(sizeof(ccv_mser_node_t) * a->rows * a->cols);
	ccv_mser_node_t** rnode = (ccv_mser_node_t**)ccmalloc(sizeof(ccv_mser_node_t*) * a->rows * a->cols);
	if (params.range <= 0)
		params.range = 255;
	// put it in a block so that the memory allocated can be released in the end
	int* buck = (int*)alloca(sizeof(int) * (params.range + 2));
	memset(buck, 0, sizeof(int) * (params.range + 2));
	ccv_mser_node_t* pnode = node;
	// this for_block is the only computation that can be shared between dark to bright and bright to dark
	// two MSER alternatives, and it only occupies 10% of overall time, we won't share this computation
	// at all (also, we need to reinitialize node for the two passes anyway).
	if (h != 0)
	{
		unsigned char* aptr = a->data.u8;
		unsigned char* hptr = h->data.u8;
#define for_block(_for_get_a, _for_get_h) \
		for (i = 0; i < a->rows; i++) \
		{ \
			for (j = 0; j < a->cols; j++) \
				if (!_for_get_h(hptr, j, 0)) \
					++buck[_for_get_a(aptr, j, 0)]; \
			aptr += a->step; \
			hptr += h->step; \
		} \
		for (i = 1; i <= params.range; i++) \
			buck[i] += buck[i - 1]; \
		buck[params.range + 1] = buck[params.range]; \
		aptr = a->data.u8; \
		hptr = h->data.u8; \
		for (i = 0; i < a->rows; i++) \
		{ \
			for (j = 0; j < a->cols; j++) \
			{ \
				_ccv_mser_init_node(pnode, j, i); \
				if (!_for_get_h(hptr, j, 0)) \
					rnode[--buck[_for_get_a(aptr, j, 0)]] = pnode; \
				else \
					pnode->shortcut = 0; /* this means the pnode is not available */ \
				++pnode; \
			} \
			aptr += a->step; \
			hptr += h->step; \
		}
		ccv_matrix_getter_integer_only_a(a->type, ccv_matrix_getter_integer_only, h->type, for_block);
#undef for_block
	} else {
		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++) \
				++buck[_for_get(aptr, j, 0)]; \
			aptr += a->step; \
		} \
		for (i = 1; i <= params.range; i++) \
			buck[i] += buck[i - 1]; \
		buck[params.range + 1] = buck[params.range]; \
		aptr = a->data.u8; \
		for (i = 0; i < a->rows; i++) \
		{ \
			for (j = 0; j < a->cols; j++) \
			{ \
				_ccv_mser_init_node(pnode, j, i); \
				rnode[--buck[_for_get(aptr, j, 0)]] = pnode; \
				++pnode; \
			} \
			aptr += a->step; \
		}
		ccv_matrix_getter_integer_only(a->type, for_block);
#undef for_block
	}
	ccv_array_t* history_list = ccv_array_new(sizeof(ccv_mser_history_t), 64, 0);
	for (v = 0; v <= params.range; v++)
	{
		int range_segment = buck[params.direction == CCV_DARK_TO_BRIGHT ? v : params.range - v];
		int range_segment_cap = buck[params.direction == CCV_DARK_TO_BRIGHT ? v + 1 : params.range - v + 1];
		for (i = range_segment; i < range_segment_cap; i++)
		{
			pnode = rnode[i];
			// try to merge pnode with its neighbors
			static int dx[] = {-1, 0, 1, -1, 1, -1, 0, 1};
			static int dy[] = {-1, -1, -1, 0, 0, 1, 1, 1};
			ccv_mser_node_t* node0 = _ccv_mser_find_root(pnode);
			for (j = 0; j < 8; j++)
			{
				int x = dx[j] + pnode->point.x;
				int y = dy[j] + pnode->point.y;
				if (x >= 0 && x < a->cols && y >= 0 && y < a->rows)
				{
					ccv_mser_node_t* nnode = pnode + dx[j] + dy[j] * a->cols;
					if (nnode->shortcut == 0) // this is a void node, skip
						continue;
					ccv_mser_node_t* node1 = _ccv_mser_find_root(nnode);
					if (node0 != node1)
					{
						// grep the extended root information
						ccv_mser_history_t* root0 = (node0->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node0->root) : 0;
						ccv_mser_history_t* root1 = (node1->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node1->root) : 0;
						// swap the node if root1 has higher rank, or larger in size, or root0 is non-existent
						if ((root0 && root1 && (root1->value > root0->value
												|| (root1->value == root0->value && root1->rank > root0->rank)
												|| (root1->value == root0->value && root1->rank == root0->rank && root1->size > root0->size)))
							|| (root1 && !root0))
						{
							ccv_mser_node_t* exnode = node0;
							node0 = node1;
							node1 = exnode;
							ccv_mser_history_t* root = root0;
							root0 = root1;
							root1 = root;
						}
						if (!root0)
						{
							ccv_mser_history_t root = {
								.rank = 0,
								.size = 1,
								.value = v,
								.shortcut = history_list->rnum,
								.parent = history_list->rnum,
								.head = node0,
								.tail = node1
							};
							node0->root = history_list->rnum;
							ccv_array_push(history_list, &root);
							root0 = (ccv_mser_history_t*)ccv_array_get(history_list, history_list->rnum - 1);
							assert(node1->root == -1);
						} else if (root0->value < v) {
							// conceal the old root as history (er), making a new one and pointing to it
							root0->shortcut = root0->parent = history_list->rnum;
							ccv_mser_history_t root = *root0;
							root.value = v;
							node0->root = history_list->rnum;
							ccv_array_push(history_list, &root);
							root0 = (ccv_mser_history_t*)ccv_array_get(history_list, history_list->rnum - 1);
							root1 = (node1->root >= 0) ? (ccv_mser_history_t*)ccv_array_get(history_list, node1->root) : 0; // the memory may be reallocated
							root0->rank = ccv_max(root0->rank, (root1 ? root1->rank : 0)) + 1;
						}
						if (root1)
						{
							if (root1->value < root0->value) // in this case, root1 is sealed as well
								root1->parent = node0->root;
							// thus, if root1->parent == itself && root1->shortcut != itself
							// it is voided, and not sealed
							root1->shortcut = node0->root;
						}
						// merge the two
						node1->shortcut = node0;
						root0->size += root1 ? root1->size : 1;
						/* insert one endless double link list to another, see illustration:
						 * 0->1->2->3->4->5->0
						 * a->b->c->d->a
						 * set 5.next (0.prev.next) point to a
						 * set 0.prev point to d
						 * set d.next (a.prev.next) point to 0
						 * set a.prev point to 5
						 * the result endless double link list will be:
						 * 0->1->2->3->4->5->a->b->c->d->0 */
						node0->prev->next = node1;
						ccv_mser_node_t* prev = node0->prev;
						node0->prev = node1->prev;
						node1->prev->next = node0; // consider self-referencing
						node1->prev = prev;
						root0->head = node0;
						root0->tail = node0->prev;
					}
				}
			}