void Stack_Draw_Voxel_C(Stack *stack, int x, int y, int z, int conn, uint8 r, uint8 g, uint8 b) { ASSERT(stack->kind == COLOR, "color stack only"); color_t *array = (color_t *) stack->array; int index = Stack_Util_Offset(x, y, z, stack->width, stack->height, stack->depth); array[index][0] = r; array[index][1] = g; array[index][2] = b; if (conn > 0) { int neighbor[26]; int is_in_bound[26]; Stack_Neighbor_Offset(conn, stack->width, stack->height, neighbor); int nbound = Stack_Neighbor_Bound_Test(conn, stack->width - 1, stack->height - 1, stack->depth - 1, x, y, z, is_in_bound); if (nbound == conn) { int i; for (i = 0; i < conn; i++) { array[index + neighbor[i]][0] = r; array[index + neighbor[i]][1] = g; array[index + neighbor[i]][2] = b; } } else { int i; for (i = 0; i < conn; i++) { if (is_in_bound[i]) { array[index + neighbor[i]][0] = r; array[index + neighbor[i]][1] = g; array[index + neighbor[i]][2] = b; } } } } }
Stack* Stack_Boundary_Code(Stack *stack, Stack *code, Objlabel_Workspace *ow) { STACK_OBJLABEL_OPEN_WORKSPACE(stack, ow); int nvoxel = Stack_Voxel_Number(stack); int i; if (ow->init_chord == TRUE) { for (i = 0; i < nvoxel; i++) { ow->chord->array[i] = -1; } } if (code == NULL) { code = Make_Stack(GREY16, stack->width, stack->height, stack->depth); } Zero_Stack(code); int neighbor[26]; int is_in_bound[26]; int nbound; BOOL is_boundary = FALSE; Stack_Neighbor_Offset(ow->conn, stack->width, stack->height, neighbor); int prev_seed = -1; int offset = 0; int x, y, z; cwidth = stack->width - 1; cheight = stack->height - 1; cdepth = stack->depth - 1; uint16 *code_array = (uint16 *) code->array; for (z = 0; z < stack->depth; z++) { for (y = 0; y < stack->height; y++) { for (x = 0; x < stack->width; x++) { is_boundary = FALSE; if (stack->array[offset] == 1) { nbound = Stack_Neighbor_Bound_Test(ow->conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); if (nbound < ow->conn) { is_boundary = TRUE; } else { for (i = 0; i < ow->conn; i++) { if (stack->array[offset + neighbor[i]] == 0) { is_boundary = TRUE; break; } } } } if (is_boundary == TRUE) { code_array[offset] = 1; ow->chord->array[offset] = prev_seed; prev_seed = offset; } offset++; } } } int entrance = prev_seed; int area = stack->width * stack->height; int c; int prev; int nb; int *link = ow->chord->array; /* generate level field */ while (entrance > 0) { c = entrance; prev = -1; do { if (code_array[c] == 1) { Stack_Util_Coord_A(c, stack->width, area, &x, &y, &z); nbound = Stack_Neighbor_Bound_Test(ow->conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); if (nbound < ow->conn) { for (i = 0; i < ow->conn; i++) { if (is_in_bound[i]) { nb = c + neighbor[i]; if (stack->array[nb] && !code_array[nb]) { code_array[nb] = 2; link[nb] = prev; prev = nb; } } } } else { for (i = 0; i < nbound; i++) { nb = c + neighbor[i]; if (stack->array[nb] && !code_array[nb]) { code_array[nb] = 2; link[nb] = prev; prev = nb; } } } } else { for (i = 0; i < ow->conn; i++) { nb = c + neighbor[i]; if (stack->array[nb] && !code_array[nb]) { code_array[nb] = code_array[c] + 1; link[nb] = prev; prev = nb; } } } c = link[c]; } while (c >= 0); entrance = prev; } STACK_OBJLABEL_CLOSE_WORKSPACE(ow); return code; }
Int_Arraylist* Stack_Sp_Grow(const Stack *stack, const size_t *seeds, int nseed, const size_t *targets, int ntarget, Sp_Grow_Workspace *sgw) { size_t nvoxel = Stack_Voxel_Number(stack); sgw->width = stack->width; sgw->height = stack->height; sgw->depth = stack->depth; /* allocate workspace */ if (sgw->size < nvoxel) { sgw->dist = (double*) Guarded_Realloc(sgw->dist, sizeof(double) * nvoxel, "Stack_Sp_Grow"); sgw->path = (int*) Guarded_Realloc(sgw->path, sizeof(int) * nvoxel, "Stack_Sp_Grow"); sgw->checked = (int*) Guarded_Realloc(sgw->checked, sizeof(int) * nvoxel, "Stack_Sp_Grow"); sgw->flag = (uint8_t*) Guarded_Realloc(sgw->flag, sizeof(uint8_t) * nvoxel, "Stack_Sp_Grow"); if (sgw->lengthBufferEnabled) { sgw->length = (double*) Guarded_Realloc( sgw->length, sizeof(double) * nvoxel, "Stack_Sp_Grow"); } } else { if (sgw->dist == NULL) { sgw->dist = (double*) Guarded_Malloc(sizeof(double) * nvoxel, "Stack_Sp_Grow"); } if (sgw->path == NULL) { sgw->path = (int*) Guarded_Malloc(sizeof(int) * nvoxel, "Stack_Sp_Grow"); } if (sgw->checked == NULL) { sgw->checked = (int*) Guarded_Malloc(sizeof(int) * nvoxel, "Stack_Sp_Grow"); } if (sgw->flag == NULL) { sgw->flag = (uint8_t*) Guarded_Malloc(sizeof(uint8_t) * nvoxel, "Stack_Sp_Grow"); } if (sgw->lengthBufferEnabled) { if (sgw->length == NULL) { sgw->length = (double*) Guarded_Malloc( sizeof(double) * nvoxel, "Stack_Sp_Grow"); } } } sgw->size = nvoxel; /* initialize */ size_t s; for (s = 0; s < nvoxel; s++) { sgw->dist[s] = Infinity; if (sgw->length != NULL) { sgw->length[s] = 0.0; } sgw->path[s] = -1; sgw->checked[s] = 0; sgw->flag[s] = 0; } if (sgw->mask != NULL) { memcpy(sgw->flag, sgw->mask, nvoxel); } /* Recruit seeds (source) */ int i; for (i = 0; i < nseed; i++) { if (sgw->sp_option == 1) { sgw->dist[seeds[i]] = -Stack_Array_Value(stack, seeds[i]); } else { sgw->dist[seeds[i]] = 0.0; } sgw->checked[seeds[i]] = 1; sgw->flag[seeds[i]] = SP_GROW_SOURCE; } if (sgw->mask != NULL) { for (s = 0; s < nvoxel; s++) { if (sgw->flag[s] == SP_GROW_SOURCE) { if (sgw->sp_option == 1) { sgw->dist[s] = -Stack_Array_Value(stack, s); } else { sgw->dist[s] = 0.0; } sgw->checked[s] = 1; } } } Int_Arraylist *result = New_Int_Arraylist(); for (i = 0; i < ntarget; i++) { if (sgw->flag[targets[i]] == 2) { /* overlap of source and target */ Int_Arraylist_Add(result, targets[i]); sgw->value = 0.0; return result; } sgw->flag[targets[i]] = SP_GROW_TARGET; } int width = Stack_Width(stack); int height = Stack_Height(stack); int depth = Stack_Depth(stack); double dist[26]; Stack_Neighbor_Dist_R(sgw->conn, sgw->resolution, dist); int is_in_bound[26]; int neighbors[26]; Stack_Neighbor_Offset(sgw->conn, Stack_Width(stack), Stack_Height(stack), neighbors); BOOL stop = FALSE; /* Check neighbors of seeds */ int j; // for (i = 0; i < nseed; i++) { // size_t r = seeds[i]; /* alloc <heap> */ Int_Arraylist *heap = New_Int_Arraylist(); size_t r; for (r = 0; r < nvoxel; r++) { if (sgw->flag[r] == SP_GROW_SOURCE) { /* seeds */ int nbound = Stack_Neighbor_Bound_Test_I(sgw->conn, width, height, depth, r, is_in_bound); if (nbound == sgw->conn) { /* all neighbors are in bound */ for (j = 0; j < sgw->conn; j++) { size_t nbr_index = r + neighbors[j]; if (sgw->checked[nbr_index] != 1) { update_waiting(stack, r, nbr_index, dist[j], heap, result, sgw); } } } else if (nbound > 0) { for (j = 0; j < sgw->conn; j++) { if (is_in_bound[j]) { size_t nbr_index = r + neighbors[j]; if (sgw->checked[nbr_index] != 1) { update_waiting(stack, r, nbr_index, dist[j], heap, result, sgw); } } } } } } //Verify_Int_Heap_I(heap, sgw->dist); ssize_t last_r = -1; while (stop == FALSE) { ssize_t r = extract_min(sgw->dist, sgw->checked, sgw->size, heap); if (r >= 0) { last_r = r; if (sgw->flag[r] == 0) { /* normal voxel */ int nbound = Stack_Neighbor_Bound_Test_I(sgw->conn, width, height, depth, r, is_in_bound); if (nbound == sgw->conn) { /* all neighbors are in bound */ for (j = 0; j < sgw->conn; j++) { size_t nbr_index = r + neighbors[j]; if (sgw->checked[nbr_index] != 1) { update_waiting(stack, r, nbr_index, dist[j], heap, result, sgw); } } } else if (nbound > 0) { for (j = 0; j < sgw->conn; j++) { if (is_in_bound[j]) { size_t nbr_index = r + neighbors[j]; if (sgw->checked[nbr_index] != 1) { update_waiting(stack, r, nbr_index, dist[j], heap, result, sgw); } } } } //Print_Int_Heap(heap, "%d"); //Verify_Int_Heap_I(heap, sgw->dist); } else if (sgw->flag[r] == SP_GROW_TARGET) { /* target reached */ //Int_Arraylist_Add(result, r); stop = TRUE; } else if (sgw->flag[r] == SP_GROW_CONDUCTOR) { /* 0-distance region (super conductor) */ int nbound = Stack_Neighbor_Bound_Test_I(sgw->conn, width, height, depth, r, is_in_bound); size_t tail_index = r; size_t old_tail_index = tail_index; size_t cur_index = r; #ifdef _DEBUG_2 printf("r: %lu\n", r); #endif #define UPDATE_SUPER_CONDUCTOR \ size_t nbr_index = cur_index + neighbors[j]; \ if (sgw->flag[nbr_index] == 4) { \ if (sgw->checked[nbr_index] > 1) { \ Int_Heap_Remove_I_At(heap, nbr_index, sgw->dist, \ sgw->checked); \ } \ tail_index = update_neighbor(cur_index, tail_index, nbr_index,sgw); \ } else { \ update_waiting(stack, cur_index, nbr_index, dist[j], heap, result,sgw); \ } if (nbound == sgw->conn) { /* all neighbors are in bound */ for (j = 0; j < sgw->conn; j++) { UPDATE_SUPER_CONDUCTOR } } else if (nbound > 0) { for (j = 0; j < sgw->conn; j++) { if (is_in_bound[j]) { UPDATE_SUPER_CONDUCTOR } } } int count = 0; while (tail_index != old_tail_index) { old_tail_index = tail_index; size_t cur_index = tail_index; while (sgw->checked[cur_index] != 1) { int nbound = Stack_Neighbor_Bound_Test_I(sgw->conn, width, height, depth, cur_index, is_in_bound); if (nbound == sgw->conn) { /* all neighbors are in bound */ for (j = 0; j < sgw->conn; j++) { UPDATE_SUPER_CONDUCTOR } } else if (nbound > 0) { for (j = 0; j < sgw->conn; j++) { if (is_in_bound[j]) { UPDATE_SUPER_CONDUCTOR } } } sgw->checked[cur_index] = 1; size_t tmp_index = cur_index; cur_index = sgw->path[cur_index]; sgw->path[tmp_index] = r; count++; } }
ZSwcTree* ZSwcGenerator::createSurfaceSwc(const ZStack &stack, int sparseLevel) { if (stack.kind() != GREY) { return NULL; } ZSwcTree *tree = NULL; if (stack.hasData()) { int width = stack.width(); int height = stack.height(); int depth = stack.depth(); int cwidth = width - 1; int cheight = height - 1; int cdepth = depth - 1; const uint8_t* in_array = stack.array8(); int conn = 6; size_t offset = 0; int neighbor[26]; int is_in_bound[26]; int n_in_bound; int count = 0; tree = new ZSwcTree(); tree->forceVirtualRoot(); Swc_Tree_Node *root = tree->root(); Stack_Neighbor_Offset(conn, width, height, neighbor); for (int k = 0; k <= cdepth; k++) { for (int j = 0; j <= cheight; j++) { for (int i = 0; i <= cwidth; i++) { // out_array[offset] = 0; if (in_array[offset] > 0) { n_in_bound = Stack_Neighbor_Bound_Test_S( conn, cwidth, cheight, cdepth, i, j, k, is_in_bound); bool isSurface = false; if (n_in_bound == conn) { for (int n = 0; n < n_in_bound; n++) { if (in_array[offset + neighbor[n]] != in_array[offset]) { isSurface = true; break; } } } else { isSurface = true; } if (isSurface) { if (count++ % sparseLevel == 0) { SwcTreeNode::makePointer(i + stack.getOffset().getX(), j + stack.getOffset().getY(), k + stack.getOffset().getZ(), sparseLevel * 0.7, root); } } } offset++; } } } } #if 0 Stack *surface = Stack_Perimeter(stack.c_stack(), NULL, 6); #ifdef _DEBUG_2 C_Stack::write(GET_DATA_DIR + "/test.tif", surface); #endif if (surface != NULL) { tree = new ZSwcTree(); tree->forceVirtualRoot(); Swc_Tree_Node *root = tree->root(); int width = C_Stack::width(surface); int height = C_Stack::height(surface); int depth = C_Stack::depth(surface); size_t offset = 0; int count = 0; for (int z = 0; z < depth; ++z) { for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { if ((surface->array[offset++]) > 0) { if (count++ % sparseLevel == 0) { SwcTreeNode::makePointer(x + stack.getOffset().getX(), y + stack.getOffset().getY(), z + stack.getOffset().getZ(), sparseLevel * 0.7, root); } } } } } C_Stack::kill(surface); } #endif return tree; }
void Stack_Grow_Object_S(Stack *seed, Stack *mask, Objlabel_Workspace *ow) { ASSERT(seed->kind = GREY, "GREY stack only"); ASSERT(mask->kind = GREY, "GREY stack only"); STACK_OBJLABEL_OPEN_WORKSPACE(seed, ow); int i; int nvoxel = Stack_Voxel_Number(seed); if (ow->init_chord == TRUE) { for (i = 0; i < nvoxel; i++) { ow->chord->array[i] = -1; } } int neighbor[26]; int nbound; int is_in_bound[26]; int x, y, z; int offset = 0; int qbot = -1; int qtop = -1; int cwidth = seed->width - 1; int cheight = seed->height - 1; int cdepth = seed->depth - 1; int *queue = ow->chord->array; int nidx; int conn = ow->conn; PROGRESS_BEGIN("Oject growing"); Stack_Neighbor_Offset(conn, seed->width, seed->height, neighbor); for (z = 0; z < seed->depth; z++) { PROGRESS_STATUS(z * 90 / seed->depth); for (y = 0; y < seed->height; y++) { for (x = 0; x < seed->width; x++) { if (seed->array[offset] == 1) { mask->array[offset] = 0; nbound = Stack_Neighbor_Bound_Test(conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); if (nbound < conn) { for (i = 0; i < conn; i++) { if (is_in_bound[i]) { if (seed->array[offset + neighbor[i]] == 0) { STACK_GROW_OBJECT_ENQUEUE(queue, offset); break; } } } } else { for (i = 0; i < conn; i++) { if (seed->array[offset + neighbor[i]] == 0) { STACK_GROW_OBJECT_ENQUEUE(queue, offset); break; } } } } offset++; } } PROGRESS_REFRESH; } int area = seed->width * seed->height; while (qtop >= 0) { STACK_GROW_OBJECT_DEQUEUE(queue, offset); STACK_UTIL_COORD(offset, seed->width, area, x, y, z); nbound = Stack_Neighbor_Bound_Test(conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); if (nbound < conn) { STACK_GROW_OBJECT_ENQUEUE_NEIGHBORS(queue, offset, (is_in_bound[i] && mask->array[nidx] == 1)); } else { STACK_GROW_OBJECT_ENQUEUE_NEIGHBORS(queue, offset, (mask->array[nidx] == 1)); } } PROGRESS_END("done"); STACK_OBJLABEL_CLOSE_WORKSPACE(ow); }
void Stack_Build_Seed_Graph(Stack *stack, int *seed, int nseed, uint8_t **connmat, Objlabel_Workspace *ow) { if (stack->kind != GREY16) { PRINT_EXCEPTION("Unsupported stack kind", "The stack must be GREY16"); return; } STACK_OBJLABEL_OPEN_WORKSPACE(stack, ow); int i, j, k; int nvoxel = Stack_Voxel_Number(stack); if (ow->init_chord == TRUE) { for (i = 0; i < nvoxel; i++) { ow->chord->array[i] = -1; } } uint16 *mask = (uint16 *) stack->array; const int conn = 26; /* each seed has a queue */ int *queue_head = iarray_malloc(nseed); /* queue_head malloced */ int *queue_tail = iarray_malloc(nseed); /* queue_head malloced */ int *queue_length = iarray_malloc(nseed); /* queue_length malloced */ /* At the beginning, each queue has one element, the corresponding seed */ iarraycpy(queue_head, seed, 0, nseed); iarraycpy(queue_tail, seed, 0, nseed); for (i = 0; i < nseed; i++) { queue_length[i] = 1; } int neighbor[26]; int bound[26]; int nbound; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; BOOL stop = FALSE; int x, y, z; Stack_Neighbor_Offset(conn, stack->width, stack->height, neighbor); #define STACK_SEED_GRAPH_UPDATE_QUEUE(test) \ for (k = 0; k < conn; k++) { \ if (test) { \ int checking_voxel = queue_head[i] + neighbor[k]; \ if ((mask[checking_voxel] > 0) && (mask[checking_voxel] != label)) { \ if (mask[checking_voxel] == 1) { \ ow->chord->array[queue_tail[i]] = checking_voxel; \ queue_tail[i] = checking_voxel; \ mask[checking_voxel] = label; \ queue_length[i]++; \ } else { \ if (mask[checking_voxel] > label) { \ connmat[i][mask[checking_voxel] - 2] = 1; \ } else { \ connmat[mask[checking_voxel] - 2][i] = 1; \ } \ } \ } \ } \ } while (stop == FALSE) { stop = TRUE; for (i = 0; i < nseed; i++) { if (queue_length[i] > 0) { int label = i + 2; for (j = 0; j < queue_length[i]; j++) { Stack_Util_Coord(queue_head[i], stack->width, stack->height, &x, &y, &z); nbound = Stack_Neighbor_Bound_Test(conn, cwidth, cheight, cdepth, x, y, z, bound); if (nbound == conn) { STACK_SEED_GRAPH_UPDATE_QUEUE(1); /* for (k = 0; k < conn; k++) { if (1) { int checking_voxel = queue_head[i] + neighbor[k]; if ((mask[checking_voxel] > 0) && (mask[checking_voxel] != label)) { if (mask[checking_voxel] == 1) { ow->chord->array[queue_tail[i]] = checking_voxel; queue_tail[i] = checking_voxel; mask[checking_voxel] = label; queue_length[i]++; } else { if (mask[checking_voxel] > label) { connmat[mask[checking_voxel] - 2][i] = 1; } else { connmat[i][mask[checking_voxel] - 2] = 1; } } } } } */ } else { STACK_SEED_GRAPH_UPDATE_QUEUE(bound[k]); } } queue_head[i] = ow->chord->array[queue_head[i]]; queue_length[i]--; stop = FALSE; } } } free(queue_head); /* queue_head freed */ free(queue_tail); /* queue_head freed */ free(queue_length); /* queue_length freed */ STACK_OBJLABEL_CLOSE_WORKSPACE(ow); }
int Stack_Label_Object_Level_Nw(Stack *stack, int seed, int flag, int label, Stack *code, int max, Objlabel_Workspace *ow) { STACK_OBJLABEL_OPEN_WORKSPACE(stack, ow); if (stack->array[seed] != flag) { TZ_WARN(ERROR_OTHER); fprintf(stderr, "The seed does not have the right flag.\n"); return 0; } IMatrix *chord = ow->chord; int npixel = Get_Stack_Size(stack); int i; int c = seed; /* center pixel */ int nb; /* neighobr pixel */ for (i = 0; i < npixel; i++) { chord->array[i] = -1; } int obj_size = 0; int next = c; uint16 *code_array = NULL; BOOL do_label = TRUE; if (code != NULL) { code_array = (uint16 *)code->array; } stack->array[seed] = label; int n_nbr = ow->conn; int neighbor[26]; Stack_Neighbor_Offset(n_nbr, stack->width, stack->height, neighbor); int x, y, z; int is_in_bound[26]; int n_in_bound = 0; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; do { Stack_Util_Coord(c, stack->width, stack->height, &x, &y, &z); n_in_bound = Stack_Neighbor_Bound_Test(n_nbr, cwidth, cheight, cdepth, x, y, z, is_in_bound); /* add all unlabeled neighbors to the queue*/ if (n_in_bound == n_nbr) { /* no boundary check required */ for (i = 0; i < n_nbr; i++) { STACK_LABEL_OBJECT_CONSTRAINT_N_UPDATE_QUEUE(stack->array); } } else { for (i = 0; i < n_nbr; i++) { if (is_in_bound[i]) { STACK_LABEL_OBJECT_CONSTRAINT_N_UPDATE_QUEUE(stack->array); } } } c = chord->array[c]; /* move to next voxel */ obj_size++; if (code == NULL) { if (obj_size >= max) { break; } } } while (c >= 0); STACK_OBJLABEL_CLOSE_WORKSPACE(ow); return obj_size; }
int Stack_Label_Object_Dist_N(Stack *stack, IMatrix *chord, int seed, int flag, int label, double max_dist, int n_nbr) { BOOL is_owner = FALSE; if (chord == NULL) { chord = Make_3d_IMatrix(stack->width, stack->height, stack->depth); is_owner = TRUE; } else { if (chord->ndim != 3) { THROW(ERROR_DATA_TYPE); } if ((stack->width != chord->dim[0]) || (stack->height != chord->dim[1]) || (stack->depth != chord->dim[2])) { THROW(ERROR_DATA_COMPTB); } } if (flag >= 0) { if (stack->array[seed] != flag) { TZ_WARN(ERROR_OTHER); fprintf(stderr, "The seed does not have the right flag.\n"); return 0; } } int npixel = Get_Stack_Size(stack); int i; int c = seed; /* center pixel */ int nb; /* neighobr pixel */ for (i = 0; i < npixel; i++) { chord->array[i] = -1; } int obj_size = 0; int next = c; BOOL do_label = TRUE; double max_dist_square = max_dist * max_dist; stack->array[seed] = label; int neighbor[26]; Stack_Neighbor_Offset(n_nbr, stack->width, stack->height, neighbor); #define STACK_LABEL_OBJECT_DIST_N_UPDATE_QUEUE \ { \ nb = c + neighbor[i]; \ Stack_Util_Coord(nb, stack->width, stack->height, &nx, &ny, &nz); \ /*process unlabeled white neighbors*/ \ dx = nx - cx; \ dy = ny - cy; \ dz = nz - cz; \ if (dx * dx + dy * dy + dz * dz > max_dist_square) { \ do_label = FALSE; \ } else { \ do_label = TRUE; \ } \ \ if ((((flag < 0) && (stack->array[nb] != label)) || \ (stack->array[nb] == flag)) && \ (chord->array[nb] == -1) && (do_label == TRUE)) { \ chord->array[next] = nb; \ next = nb; \ stack->array[nb] = label; \ } \ } int x, y, z; int cx, cy, cz; int nx, ny, nz; int dx, dy, dz; int is_in_bound[26]; int n_in_bound = 0; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; Stack_Util_Coord(seed, stack->width, stack->height, &cx, &cy, &cz); do { Stack_Util_Coord(c, stack->width, stack->height, &x, &y, &z); n_in_bound = Stack_Neighbor_Bound_Test(n_nbr, cwidth, cheight, cdepth, x, y, z, is_in_bound); /* add all unlabeled neighbors to the queue*/ if (n_in_bound == n_nbr) { /* no boundary check required */ for (i = 0; i < n_nbr; i++) { STACK_LABEL_OBJECT_DIST_N_UPDATE_QUEUE; } } else { for (i = 0; i < n_nbr; i++) { if (is_in_bound[i]) { STACK_LABEL_OBJECT_DIST_N_UPDATE_QUEUE; } } } c = chord->array[c]; /* move to next voxel */ obj_size++; } while (c >= 0); if (is_owner == TRUE) { Kill_IMatrix(chord); } return obj_size; }
Graph* Stack_Label_Field_Neighbor_Graph(Stack *stack, int threshold, Objlabel_Workspace *ow) { TZ_ASSERT(stack->kind == GREY16, "Invalid stack kind"); STACK_OBJLABEL_OPEN_WORKSPACE(stack, ow); Graph *graph = Make_Graph(0, 1, TRUE); graph->nvertex = Stack_Max(stack, NULL) + 1; Graph_Workspace *gw = New_Graph_Workspace(); uint16_t *signal_array = (uint16_t*) stack->array; int neighbor_offset[26]; int is_in_bound[26]; Stack_Neighbor_Offset(ow->conn, stack->width, stack->height, neighbor_offset); /* Identify number of objects */ int object_number = 0; int width = stack->width; int height = stack->height; int depth = stack->depth; size_t voxelNumber = Stack_Voxel_Number(stack); size_t index; //Stack *mask = Make_Stack(GREY, width, height, depth); for (index = 0; index < voxelNumber; ++index) { if (object_number < signal_array[index]) { object_number = signal_array[index]; } if (ow->init_chord == TRUE) { ow->chord->array[index] = -1; } //mask->array[index] = 0; } //uint8_t *visited = mask->array; Int_Arraylist *seed_head = Make_Int_Arraylist(object_number + 1, 0); Int_Arraylist *seed_tail = Make_Int_Arraylist(object_number + 1, 0); Int_Arraylist *seed_point = Make_Int_Arraylist(object_number + 1, 0); int i; for (i = 0; i < seed_head->length; ++i) { seed_head->array[i] = -1; seed_point->array[i] = -1; seed_tail->array[i] = -1; } int *seed_queue = ow->chord->array; /* Initialize the seeds for each object */ for (index = 0; index < voxelNumber; ++index) { uint16_t object_label = signal_array[index]; int *current_seed_head = seed_head->array + object_label; int *current_seed_tail = seed_tail->array + object_label; int *current_seed_point = seed_point->array + object_label; int nbound = Stack_Neighbor_Bound_Test_I(ow->conn, width, height, depth, index, is_in_bound); if (is_border_voxel(signal_array, index, ow->conn, neighbor_offset, is_in_bound, nbound) == TRUE) { //visited[index] = 1; if (*current_seed_head < 0) { *current_seed_head = index; *current_seed_tail = index; *current_seed_point = *current_seed_head; } else { seed_queue[*current_seed_point] = index; *current_seed_point = index; } } } int current_level = 0; /* While the current growing level is below the threshold */ while (current_level < threshold) { /* Grow each object */ uint16_t object_label; for (object_label = 1; object_label <= object_number; ++object_label) { int current_tail = seed_tail->array[object_label]; int new_tail = current_tail; int seed = seed_head->array[object_label]; while (seed >= 0) { int nbound = Stack_Neighbor_Bound_Test_I(ow->conn, width, height, depth, seed, is_in_bound); int j; for (j = 0; j < ow->conn; ++j) { if (nbound == ow->conn || is_in_bound[j]) { int neighbor_index = seed + neighbor_offset[j]; uint16_t neighbor_label = signal_array[neighbor_index]; if (neighbor_label == 0) { seed_queue[new_tail] = neighbor_index; new_tail = neighbor_index; signal_array[neighbor_index] = object_label; //visited[neighbor_index] = 1; } else if (neighbor_label != object_label) { /* If x-y does not exist */ if (Graph_Edge_Index_U(object_label, neighbor_label, gw) < 0) { double weight = current_level * 2; if (object_label > neighbor_label) { weight += 1.0; } Graph_Add_Weighted_Edge(graph, object_label, neighbor_label, weight); Graph_Expand_Edge_Table(object_label, neighbor_label, graph->nedge - 1, gw); } } } } if (seed == current_tail) { break; } seed = seed_queue[seed]; } if (current_tail >= 0) { seed_head->array[object_label] = seed_queue[current_tail]; seed_tail->array[object_label] = new_tail; } } ++current_level; } Kill_Int_Arraylist(seed_head); Kill_Int_Arraylist(seed_tail); Kill_Int_Arraylist(seed_point); Kill_Graph_Workspace(gw); STACK_OBJLABEL_CLOSE_WORKSPACE(ow); //Kill_Stack(mask); return graph; }
int Stack_Label_Object_Level_N(Stack *stack, IMatrix *chord, int seed, int flag, int label, Stack *code, int max, int n_nbr) { BOOL is_owner = FALSE; if (chord == NULL) { chord = Make_3d_IMatrix(stack->width, stack->height, stack->depth); is_owner = TRUE; } else { if (chord->ndim != 3) { THROW(ERROR_DATA_TYPE); } if ((stack->width != chord->dim[0]) || (stack->height != chord->dim[1]) || (stack->depth != chord->dim[2])) { THROW(ERROR_DATA_COMPTB); } } if (stack->array[seed] != flag) { TZ_WARN(ERROR_OTHER); fprintf(stderr, "The seed does not have the right flag.\n"); return 0; } int npixel = Get_Stack_Size(stack); int i; int c = seed; /* center pixel */ int nb; /* neighobr pixel */ for (i = 0; i < npixel; i++) { chord->array[i] = -1; } int obj_size = 0; int next = c; uint16 *code_array = NULL; BOOL do_label = TRUE; if (code != NULL) { code_array = (uint16 *)code->array; } stack->array[seed] = label; int neighbor[26]; Stack_Neighbor_Offset(n_nbr, stack->width, stack->height, neighbor); int x, y, z; int is_in_bound[26]; int n_in_bound = 0; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; do { Stack_Util_Coord(c, stack->width, stack->height, &x, &y, &z); n_in_bound = Stack_Neighbor_Bound_Test(n_nbr, cwidth, cheight, cdepth, x, y, z, is_in_bound); /* add all unlabeled neighbors to the queue*/ if (n_in_bound == n_nbr) { /* no boundary check required */ for (i = 0; i < n_nbr; i++) { STACK_LABEL_OBJECT_CONSTRAINT_N_UPDATE_QUEUE(stack->array); } } else { for (i = 0; i < n_nbr; i++) { if (is_in_bound[i]) { STACK_LABEL_OBJECT_CONSTRAINT_N_UPDATE_QUEUE(stack->array); } } } c = chord->array[c]; /* move to next voxel */ obj_size++; if (code == NULL) { if (obj_size >= max) { break; } } } while (c >= 0); if (is_owner == TRUE) { Kill_IMatrix(chord); } return obj_size; }
int Stack_Label_Object_W(Stack *stack, int seed, int flag, int label, Objlabel_Workspace *ow) { TZ_ASSERT(stack->kind == GREY || stack->kind == GREY16, "Unsupported kind."); STACK_OBJLABEL_OPEN_WORKSPACE(stack, ow); ow->seed = seed; uint16_t* array16 = (uint16_t*) stack->array; uint8_t* array8 = (uint8_t*) stack->array; if (stack->kind == GREY) { if (stack->array[seed] != flag) { TZ_WARN(ERROR_OTHER); fprintf(stderr, "The seed does not have the right flag.\n"); return 0; } } else { if (array16[seed] != flag) { TZ_WARN(ERROR_OTHER); fprintf(stderr, "The seed does not have the right flag.\n"); return 0; } } int npixel = Get_Stack_Size(stack); int i; int c = seed; /* center pixel */ int nb; /* neighobr pixel */ if (ow->init_chord == TRUE) { for (i = 0; i < npixel; i++) { ow->chord->array[i] = -1; } } int obj_size = 0; int next = c; if (stack->kind == GREY) { stack->array[seed] = label; } else { array16[seed] = label; } int x, y, z; int is_in_bound[26]; int n_in_bound = 0; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; int neighbor[26]; Stack_Neighbor_Offset(ow->conn, stack->width, stack->height, neighbor); #define STACK_LABEL_OBJECT_N_UPDATE_QUEUE(stack_array) \ { \ nb = c + neighbor[i]; \ /*process unlabeled white neighbors*/ \ if ((stack_array[nb] == flag) && (ow->chord->array[nb] == -1)) { \ ow->chord->array[next] = nb; \ TZ_ASSERT(ow->chord->array[next] != next, "loop"); \ next = nb; \ stack_array[nb] = label; \ } \ } int area = stack->width * stack->height; do { z = c / area; if (z > stack->depth) { n_in_bound = 0; } else { y = c % area; x = y % stack->width; y = y / stack->width; if ((x > stack->width) || (y > stack->height)) { n_in_bound = 0; } else { //Stack_Util_Coord(c, stack->width, stack->height, &x, &y, &z); if ((x > 0) && (x < cwidth) && (y > 0) && (y < cheight) && (z > 0) && (z < cdepth)) { n_in_bound = ow->conn; } else { n_in_bound = Stack_Neighbor_Bound_Test_S(ow->conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); } } } /* add all unlabeled neighbors to the queue*/ if (n_in_bound == ow->conn) { /* no boundary check required */ if (stack->kind == GREY) { for (i = 0; i < ow->conn; i++) { STACK_LABEL_OBJECT_N_UPDATE_QUEUE(array8); } } else { for (i = 0; i < ow->conn; i++) { STACK_LABEL_OBJECT_N_UPDATE_QUEUE(array16); } } } else { for (i = 0; i < ow->conn; i++) { if (is_in_bound[i]) { if (stack->kind == GREY) { STACK_LABEL_OBJECT_N_UPDATE_QUEUE(array8); } else { STACK_LABEL_OBJECT_N_UPDATE_QUEUE(array16); } } } } c = ow->chord->array[c]; /* move to next voxel */ obj_size++; } while (c >= 0); STACK_OBJLABEL_CLOSE_WORKSPACE(ow); return obj_size; }
/** * Stack_Build_Seed_Graph_Gg() allows users to build a seed graph using * approximate geodesdic distances. The workspace should be created by * Make_Objlabel_Workspace_Gg() and initialized by Init_Objlabel_Workspace_Gg() * if necessary. */ Graph* Stack_Build_Seed_Graph_Gg(Stack *stack, int *seed, int nseed, BOOL weighted, Objlabel_Workspace *ow) { if (stack->kind != GREY16) { PRINT_EXCEPTION("Unsupported stack kind", "The stack must be GREY16"); return NULL; } int i, j, k; uint16 *level = (uint16 *) ow->u; uint16 *mask = (uint16 *) stack->array; const int conn = 26; /* each seed has a queue */ int *queue_head = iarray_malloc(nseed); /* queue_head malloced */ int *queue_tail = iarray_malloc(nseed); /* queue_head malloced */ int *queue_length = iarray_malloc(nseed); /* queue_length malloced */ /* At the beginning, each queue has one element, the corresponding seed */ iarraycpy(queue_head, seed, 0, nseed); iarraycpy(queue_tail, seed, 0, nseed); for (i = 0; i < nseed; i++) { queue_length[i] = 1; } int neighbor[26]; int bound[26]; int nbound; int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; BOOL stop = FALSE; int x, y, z; Stack_Neighbor_Offset(conn, stack->width, stack->height, neighbor); #define STACK_SEED_GRAPH_UPDATE_QUEUE_GG(test) \ for (k = 0; k < conn; k++) { \ if (test) { \ int checking_voxel = queue_head[i] + neighbor[k]; \ if ((mask[checking_voxel] > 0) && (mask[checking_voxel] != label)) { \ if (mask[checking_voxel] == 1) { \ ow->chord->array[queue_tail[i]] = checking_voxel; \ queue_tail[i] = checking_voxel; \ mask[checking_voxel] = label; \ level[checking_voxel] = level[queue_head[i]] + 1; \ queue_length[i]++; \ } else { \ int v1, v2, tmp; \ v1 = i; \ v2 = mask[checking_voxel] - 2; \ ASSERT(v1 != v2, "Bug in Stack_Build_Seed_Graph_G()"); \ if (v1 > v2) { \ SWAP2(v1, v2, tmp); \ } \ if (Graph_Edge_Index(v1, v2, gw) < 0) { \ if (weighted == TRUE) { \ /*double dist = Stack_Util_Voxel_Distance(seed[v1], seed[v2], stack->width, stack->height);*/ \ double dist = level[checking_voxel] + level[queue_head[i]]; \ Graph_Add_Weighted_Edge(graph, v1, v2, dist); \ } else { \ Graph_Add_Edge(graph, v1, v2); \ } \ Graph_Expand_Edge_Table(v1, v2, graph->nedge -1, gw); \ } \ } \ } \ } \ } Graph *graph = Make_Graph(nseed, nseed, weighted); Graph_Workspace *gw = New_Graph_Workspace(); while (stop == FALSE) { stop = TRUE; for (i = 0; i < nseed; i++) { if (queue_length[i] > 0) { int label = i + 2; for (j = 0; j < queue_length[i]; j++) { Stack_Util_Coord(queue_head[i], stack->width, stack->height, &x, &y, &z); nbound = Stack_Neighbor_Bound_Test(conn, cwidth, cheight, cdepth, x, y, z, bound); if (nbound == conn) { STACK_SEED_GRAPH_UPDATE_QUEUE_GG(1); } else { STACK_SEED_GRAPH_UPDATE_QUEUE_GG(bound[k]); } } queue_head[i] = ow->chord->array[queue_head[i]]; queue_length[i]--; stop = FALSE; } } } free(queue_head); /* queue_head freed */ free(queue_tail); /* queue_head freed */ free(queue_length); /* queue_length freed */ return graph; }
int* Stack_Graph_Shortest_Path(const Stack *stack, int start[], int end[], Stack_Graph_Workspace *sgw) { int start_index = Stack_Util_Offset(start[0], start[1], start[2], stack->width, stack->height, stack->depth); int end_index = Stack_Util_Offset(end[0], end[1], end[2], stack->width, stack->height, stack->depth); int nvoxel = Stack_Voxel_Number(stack); int *path = iarray_malloc(nvoxel); double *dist = darray_malloc(nvoxel); int *checked = iarray_malloc(nvoxel); int i, j; for (i = 0; i < nvoxel; i++) { dist[i] = Infinity; path[i] = -1; checked[i] = 0; } dist[start_index] = 0; path[start_index] = -1; checked[start_index] = 1; int prev_vertex = start_index; int cur_vertex = start_index; int updating_vertex; double tmpdist; int neighbor[26]; Stack_Neighbor_Offset(sgw->conn, stack->width, stack->height, neighbor); const double *neighbor_dist = Stack_Neighbor_Dist(sgw->conn); int is_in_bound[26]; int nbound; Int_Arraylist *heap = Int_Arraylist_New(1, 0); int cwidth = stack->width - 1; int cheight = stack->height - 1; int cdepth = stack->depth - 1; void *argv[3]; double v1; double v2; double d; argv[0] = &v1; argv[1] = &v2; argv[2] = &d; for (i = 1; i < nvoxel; i++) { prev_vertex = cur_vertex; nbound = Stack_Neighbor_Bound_Test_I(sgw->conn, cwidth, cheight, cdepth, cur_vertex, is_in_bound); if (nbound == sgw->conn) { for (j = 0; j < sgw->conn; j++) { updating_vertex = cur_vertex + neighbor[j]; if (checked[updating_vertex] != 1) { v1 = Stack_Array_Value(stack, cur_vertex); v2 = Stack_Array_Value(stack, updating_vertex); d = neighbor_dist[j]; double weight = sgw->wf(argv); tmpdist = weight + dist[cur_vertex]; if (dist[updating_vertex] > tmpdist) { dist[updating_vertex] = tmpdist; path[updating_vertex] = cur_vertex; if (checked[updating_vertex] > 1) { Int_Heap_Update_I(heap, updating_vertex, dist, checked); } else { Int_Heap_Add_I(heap, updating_vertex, dist, checked); } } } } } else { for (j = 0; j < sgw->conn; j++) { if (is_in_bound[j]) { updating_vertex = cur_vertex + neighbor[j]; if (checked[updating_vertex] != 1) { v1 = Stack_Array_Value(stack, cur_vertex); v2 = Stack_Array_Value(stack, updating_vertex); d = neighbor_dist[j]; double weight = sgw->wf(argv); tmpdist = weight + dist[cur_vertex]; if (dist[updating_vertex] > tmpdist) { dist[updating_vertex] = tmpdist; path[updating_vertex] = cur_vertex; if (checked[updating_vertex] > 1) { Int_Heap_Update_I(heap, updating_vertex, dist, checked); } else { Int_Heap_Add_I(heap, updating_vertex, dist, checked); } } } } } } cur_vertex = extract_min(dist, checked, nvoxel, heap); if (cur_vertex == end_index) { break; } if (cur_vertex < 0) { break; } } Kill_Int_Arraylist(heap); free(checked); free(dist); return path; }
Graph* Stack_Graph_W(const Stack *stack, Stack_Graph_Workspace *sgw) { int x, y, z; int offset = 0; int is_in_bound[26]; int nbound; int i; int stack_range[6]; int *range = sgw->range; if (range == NULL) { stack_range[0] = 0; stack_range[1] = stack->width - 1; stack_range[2] = 0; stack_range[3] = stack->height - 1; stack_range[4] = 0; stack_range[5] = stack->depth - 1; } else { stack_range[0] = imax2(0, range[0]); stack_range[1] = imin2(stack->width - 1, range[1]); stack_range[2] = imax2(0, range[2]); stack_range[3] = imin2(stack->height - 1, range[3]); stack_range[4] = imax2(0, range[4]); stack_range[5] = imin2(stack->depth - 1, range[5]); } int cdepth = stack_range[5] - stack_range[4]; int cheight = stack_range[3] - stack_range[2]; int cwidth = stack_range[1] - stack_range[0]; int nvertex = (cwidth + 1) * (cheight + 1) * (cdepth + 1); sgw->virtualVertex = nvertex; BOOL weighted = TRUE; if (sgw->sp_option == 1) { weighted = FALSE; sgw->intensity = darray_malloc(nvertex + 1); sgw->intensity[nvertex] = Infinity; } Graph *graph = Make_Graph(nvertex, nvertex, weighted); int neighbor[26]; int scan_mask[26]; Stack_Neighbor_Offset(sgw->conn, cwidth + 1, cheight + 1, neighbor); int org_neighbor[26]; Stack_Neighbor_Offset(sgw->conn, Stack_Width(stack), Stack_Height(stack), org_neighbor); double dist[26]; Stack_Neighbor_Dist_R(sgw->conn, sgw->resolution, dist); //const double *dist = Stack_Neighbor_Dist(sgw->conn); const int *x_offset = Stack_Neighbor_X_Offset(sgw->conn); const int *y_offset = Stack_Neighbor_Y_Offset(sgw->conn); const int *z_offset = Stack_Neighbor_Z_Offset(sgw->conn); /* go forward */ for (i = 0; i < sgw->conn; i++) { scan_mask[i] = (neighbor[i] > 0); } #define STACK_GRAPH_ADD_EDGE(cond) \ for (i = 0; i < sgw->conn; i++) { \ if (cond) { \ int nx = x + stack_range[0]; \ int ny = y + stack_range[2]; \ int nz = z + stack_range[4]; \ if (Graph_Is_Weighted(graph)) { \ double weight = dist[i]; \ if (sgw->wf != NULL) { \ sgw->argv[0] = dist[i]; \ \ sgw->argv[1] = Get_Stack_Pixel((Stack *)stack, nx, ny, nz, 0); \ sgw->argv[2] = \ Get_Stack_Pixel((Stack *)stack, nx + x_offset[i], \ ny + y_offset[i], nz + z_offset[i], 0); \ weight = sgw->wf(sgw->argv); \ } \ Graph_Add_Weighted_Edge(graph, offset, offset + neighbor[i], \ weight); \ } else { \ Graph_Add_Edge(graph, offset, offset + neighbor[i]); \ sgw->intensity[offset] = Get_Stack_Pixel((Stack*) stack, \ nx, ny, nz, 0); \ } \ } \ } int groupVertexMap[256]; for (i = 0; i < 256; ++i) { groupVertexMap[i] = 0; } int swidth = cwidth + 1; int sarea = (cwidth + 1) * (cheight + 1); int area = stack->width * stack->height; for (z = 0; z <= cdepth; z++) { for (y = 0; y <= cheight; y++) { for (x = 0; x <= cwidth; x++) { nbound = Stack_Neighbor_Bound_Test_S(sgw->conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); size_t offset2 = Stack_Subindex((size_t) offset, stack_range[0], stack_range[2], stack_range[4], swidth, sarea, stack->width, area); #ifdef _DEBUG_2 if (offset == 36629) { printf("debug here\n"); } #endif if (nbound == sgw->conn) { STACK_GRAPH_ADD_EDGE((scan_mask[i] == 1) && (sgw->signal_mask == NULL ? 1 : ((sgw->signal_mask->array[offset2] > 0) && (sgw->signal_mask->array[offset2+org_neighbor[i]] > 0)))) } else { STACK_GRAPH_ADD_EDGE((scan_mask[i] == 1) && is_in_bound[i] && (sgw->signal_mask == NULL ? 1 : ((sgw->signal_mask->array[offset2] > 0) && (sgw->signal_mask->array[offset2+org_neighbor[i]]) > 0))) } if (sgw->group_mask != NULL) { int groupId = sgw->group_mask->array[offset2]; if (groupId > 0) { #ifdef _DEBUG_2 sgw->group_mask->array[offset2] = 2; #endif int groupVertex = groupVertexMap[groupId]; if (groupVertex <= 0) { groupVertex = nvertex++; groupVertexMap[groupId] = groupVertex; } Graph_Add_Weighted_Edge(graph, groupVertex, offset, 0.0); } } offset++; } } } return graph; }
Graph* Stack_Graph(const Stack *stack, int conn, const int *range, Weight_Func_t *wf) { int x, y, z; int offset = 0; int is_in_bound[26]; int nbound; int i; int stack_range[6]; if (range == NULL) { stack_range[0] = 0; stack_range[1] = stack->width - 1; stack_range[2] = 0; stack_range[3] = stack->height - 1; stack_range[4] = 0; stack_range[5] = stack->depth - 1; } else { stack_range[0] = imax2(0, range[0]); stack_range[1] = imin2(stack->width - 1, range[1]); stack_range[2] = imax2(0, range[2]); stack_range[3] = imin2(stack->height - 1, range[3]); stack_range[4] = imax2(0, range[4]); stack_range[5] = imin2(stack->depth - 1, range[5]); } int cdepth = stack_range[5] - stack_range[4]; int cheight = stack_range[3] - stack_range[2]; int cwidth = stack_range[1] - stack_range[0]; int nvertex = (cwidth + 1) * (cheight + 1) * (cdepth + 1); Graph *graph = Make_Graph(nvertex, nvertex, TRUE); int neighbor[26]; int scan_mask[26]; Stack_Neighbor_Offset(conn, cwidth + 1, cheight + 1, neighbor); const double *dist = Stack_Neighbor_Dist(conn); const int *x_offset = Stack_Neighbor_X_Offset(conn); const int *y_offset = Stack_Neighbor_Y_Offset(conn); const int *z_offset = Stack_Neighbor_Z_Offset(conn); double args[3]; for (i = 0; i < conn; i++) { scan_mask[i] = (neighbor[i] > 0); } for (z = 0; z <= cdepth; z++) { for (y = 0; y <= cheight; y++) { for (x = 0; x <= cwidth; x++) { nbound = Stack_Neighbor_Bound_Test(conn, cwidth, cheight, cdepth, x, y, z, is_in_bound); if (nbound == conn) { for (i = 0; i < conn; i++) { if (scan_mask[i] == 1) { double weight = dist[i]; if (wf != NULL) { args[0] = dist[i]; args[1] = Get_Stack_Pixel((Stack *)stack, x + stack_range[0], y + stack_range[2], z + stack_range[4], 0); args[2] = Get_Stack_Pixel((Stack *)stack, x + stack_range[0] + x_offset[i], y + stack_range[2] + y_offset[i], z + stack_range[4] + z_offset[i], 0); weight = wf(args); } Graph_Add_Weighted_Edge(graph, offset, offset + neighbor[i], weight); } } } else { for (i = 0; i < conn; i++) { if ((scan_mask[i] == 1) && is_in_bound[i]){ double weight = dist[i]; if (wf != NULL) { args[0] = dist[i]; args[1] = Get_Stack_Pixel((Stack *)stack, x + stack_range[0], y + stack_range[2], z + stack_range[4], 0); args[2] = Get_Stack_Pixel((Stack *)stack, x + stack_range[0] + x_offset[i], y + stack_range[2] + y_offset[i], z + stack_range[4] + z_offset[i], 0); weight = wf(args); } Graph_Add_Weighted_Edge(graph, offset, offset + neighbor[i], weight); } } } offset++; } } } return graph; }