예제 #1
0
Geo3d_Scalar_Field* ZNeuronTracer::extractSeedSkel(const Stack *mask)
{
  Stack *skel = Stack_Bwthin(mask, NULL);

  /* alloc <dist> */
  Stack *dist = Stack_Bwdist_L_U16(mask, NULL, 0);


  ZStackProcessor::RemoveBranchPoint(skel, 26);

  Stack *skel_proc = C_Stack::clone(skel);
 Geo3d_Scalar_Field *field1 = extractLineSeed(skel_proc, dist);
 C_Stack::kill(skel_proc);

 for (int i = 0; i <field1->size; ++i) {
   int x = field1->points[i][0];
   int y = field1->points[i][1];
   int z = field1->points[i][2];
   Set_Stack_Pixel(skel, x, y, z, 0, 0);
 }

#ifdef _DEBUG_2
  C_Stack::write(GET_TEST_DATA_DIR + "/test.tif", skel);
#endif


 Geo3d_Scalar_Field *field2 = extractLineSeed(skel, dist, 0);

 Geo3d_Scalar_Field *field = Geo3d_Scalar_Field_Merge(field1, field2, NULL);

 Kill_Geo3d_Scalar_Field(field1);
 Kill_Geo3d_Scalar_Field(field2);

#ifdef _DEBUG_2
  ZSwcTree tree;
  tree.forceVirtualRoot();
  for (int i = 0; i <field->size; ++i) {
    int x = field->points[i][0];
    int y = field->points[i][1];
    int z = field->points[i][2];
    double radius = field->values[i];
    SwcTreeNode::setFirstChild(
          tree.root(), SwcTreeNode::makePointer(x, y, z, radius));
  }
  tree.save(GET_TEST_DATA_DIR + "/test.swc");
#endif

  /* free <dist> */
  C_Stack::kill(dist);

  C_Stack::kill(skel);

  return field;
}
예제 #2
0
void Neuroseg_Field_Range(const Neuroseg *seg, Field_Range *range, 
			  double z_scale)
{
  /* alloc <field> */
  Geo3d_Scalar_Field *field = Neuroseg_Field_S(seg, NULL, NULL);
  if (field == NULL)
    return;
  coordinate_3d_t bound[2];
  Geo3d_Scalar_Field_Boundbox(field, bound);
  
  range->first_corner[0] = (int) (bound[0][0] - 1.5);
  range->first_corner[1] = (int) (bound[0][1] - 1.5);
  range->first_corner[2] = (int) (bound[0][2] * z_scale - 1.5);

  range->size[0] = (int) (bound[1][0] - range->first_corner[0] + 1.5);
  range->size[1] = (int) (bound[1][1] - range->first_corner[1] + 1.5);
  range->size[2] = (int) (bound[1][2]* z_scale - range->first_corner[2] 
			  + 1.5);

#ifdef _DEBUG_2
  print_field_range(range);
#endif

  /* free <field> */
  Kill_Geo3d_Scalar_Field(field);
}
예제 #3
0
double Local_R2_Rect_Score_P(const Local_R2_Rect *locseg,
    const Stack *stack, double z_scale, Stack_Fit_Score *fs)
{
  double score = 0.0;

  Geo3d_Scalar_Field *field = Local_R2_Rect_Field(locseg, NULL);
  score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, fs);

  Kill_Geo3d_Scalar_Field(field);

  return score;
}
예제 #4
0
double Local_Bifold_Neuroseg_Score(const Local_Bifold_Neuroseg *locbn, 
				  const Stack *stack, 
				  double z_scale, Stack_Fit_Score *fs)
{
  Geo3d_Scalar_Field *field = Local_Bifold_Neuroseg_Field(locbn,
							 NULL);
  double score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, fs);

  Kill_Geo3d_Scalar_Field(field);
  
  return score;
}
예제 #5
0
double Local_Neuroseg_Plane_Score(const Local_Neuroseg_Plane *locnp, 
				  const Stack *stack, 
				  double z_scale, Stack_Fit_Score *fs)
{
  double sample_step = 1.0;
  Geo3d_Scalar_Field *field = Local_Neuroseg_Plane_Field(locnp, sample_step,
							 NULL);
  double score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, fs);

  Kill_Geo3d_Scalar_Field(field);
  
  return score;
}
예제 #6
0
void Clean_Swc_Tree_Svg_Workspace(Swc_Tree_Svg_Workspace *ws)
{
  if (ws->puncta == NULL) {
    Kill_Geo3d_Scalar_Field(ws->puncta);
  }
  if (ws->on_root != NULL) {
    free(ws->on_root);
  }
  if (ws->puncta_type != NULL) {
    free(ws->puncta_type);
  }

  Default_Swc_Tree_Svg_Workspace(ws);
}
예제 #7
0
double Local_R2_Rect_Score_W(const Local_R2_Rect *locseg, 
        const Stack *stack, double z_scale, Receptor_Score_Workspace *ws)
{
  Geo3d_Scalar_Field *field = Local_R2_Rect_Field(locseg, NULL);
  double score = 0.0;
  if (ws->mask == NULL) {
    score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, &(ws->fs));
  } else {
    score = Geo3d_Scalar_Field_Stack_Score_M(field, stack, z_scale, ws->mask,
        &(ws->fs));
  }

  Kill_Geo3d_Scalar_Field(field);

  return score;
}
예제 #8
0
void Local_R2_Rect_Position_Adjust(Local_R2_Rect *locseg,
    const Stack *stack, double z_scale)
{   
  /* alloc <field> */
  Geo3d_Scalar_Field *field = Local_R2_Rect_Field(locseg, NULL);

  Geo3d_Scalar_Field_Stack_Sampling(field, stack, z_scale, 
      field->values);

  coordinate_3d_t center;
  Geo3d_Scalar_Field_Centroid(field, center);
#ifdef _DEBUG_2
  printf("%g, %g, %g\n", center[0], center[1], center[2]);
#endif

  locseg->transform.x = center[0];
  locseg->transform.y = center[1];

  /* free <field> */
  Kill_Geo3d_Scalar_Field(field);
} 
예제 #9
0
double Local_R2_Rect_Orientation_Search_C(Local_R2_Rect *locseg,
    const Stack *stack, double z_scale, Stack_Fit_Score *fs)
{
  double best_theta;
  double best_score;
  double theta;
  double score;

  double center[3];
  Local_R2_Rect_Center(locseg, center);

  Geo3d_Scalar_Field *field = Local_R2_Rect_Field_Sp(locseg, NULL);

  best_score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, fs);
  best_theta = locseg->transform.theta;

  Local_R2_Rect tmp_locseg = *locseg;

  for (theta = 0.0; theta < TZ_2PI; theta += 0.2) {
    tmp_locseg.transform.theta = theta;

    Local_R2_Rect_Set_Center(&tmp_locseg, center);
    Local_R2_Rect_Field_Sp(&tmp_locseg, field);

    score = Geo3d_Scalar_Field_Stack_Score(field, stack, z_scale, fs);

    if (score > best_score) {
      best_theta = tmp_locseg.transform.theta;
      best_score = score;
    }
  }

  locseg->transform.theta = best_theta;
  Local_R2_Rect_Set_Center(locseg, center);

  Kill_Geo3d_Scalar_Field(field);

  return best_score;
}
예제 #10
0
int main()
{
  /* Read stack */
  Stack *stack = Read_Stack("../data/fly_neuron.tif");
  double z_scale = 1.0;

  /* New a bifold segment */
  Local_Bifold_Neuroseg *locbn = New_Local_Bifold_Neuroseg();
  /*
  Set_Local_Bifold_Neuroseg(locbn, 2, 2, 2, 2, 30, 0.5,
			    TZ_PI_2, TZ_PI_2, -TZ_PI_2, 0, 
			    461, 296, 144); //fly_neuron.tif
  */
  
  Set_Local_Bifold_Neuroseg(locbn, 2, 2, 2, 2, 40, 0.5, 
			    TZ_PI_2, TZ_PI_2, TZ_PI_2, TZ_PI_2, 
			    290, 304, 112); //fly_neuron.tif
  
  
  /*
  Set_Local_Bifold_Neuroseg(locbn, 2, 2, 2, 2, 30, 0.5, 
			    TZ_PI_2, TZ_PI_2, -TZ_PI_2, 0, 
			    320, 164, 148); //fly_neuron.tif
  */  

  /*
  Set_Local_Bifold_Neuroseg(locbn, 3, 3, 3, 3, 30, 0.5, 
			    TZ_PI_2, TZ_PI_2, -TZ_PI_2, 0,
			    262, 136, 141); //fly_neuron2.tif
  */

  /*
  Set_Local_Bifold_Neuroseg(locbn, 3, 3, 3, 3, 30, 0.5, 
			    TZ_PI_2, TZ_PI_2, -TZ_PI_2, 0,
			    236, 396, 143); //fly_neuron2.tif
  */

  /* fit */
  int var_index[LOCAL_BIFOLD_NEUROSEG_NPARAM];
  int nvar = Local_Bifold_Neuroseg_Var_Mask_To_Index
    (BIFOLD_NEUROSEG_VAR_MASK_R |
     BIFOLD_NEUROSEG_VAR_MASK_KNOT |
     BIFOLD_NEUROSEG_VAR_MASK_ORIENTATION2 |
     BIFOLD_NEUROSEG_VAR_MASK_ORIENTATION, NEUROPOS_VAR_MASK_NONE, var_index);

  Fit_Local_Bifold_Neuroseg(locbn, stack, var_index, nvar, z_scale, NULL);

  Print_Local_Bifold_Neuroseg(locbn);

  /* Generate field */
  Geo3d_Scalar_Field *field = Local_Bifold_Neuroseg_Field(locbn, 1.0, NULL);
  Delete_Local_Bifold_Neuroseg(locbn);

  /* Draw it in a stack */
  Stack *label = Make_Stack(FLOAT32, stack->width, stack->height, stack->depth);
  Zero_Stack(label);
  double coef[] = {0.1, 255.0};
  double range[] = {0.0, 10000.0};
  Geo3d_Scalar_Field_Draw_Stack(field, label, coef, range);

  /* Turn the stack to GREY type */
  Translate_Stack(label, GREY, 1);

  /* Make canvas */
  Translate_Stack(stack, COLOR, 1);
  
  /* Label the canvas */
  Stack_Label_Color(stack, label, 5.0, 1.0, label);

  /* Save the stack */
  Write_Stack("../data/test.tif", stack);

  /* clean up */
  Kill_Geo3d_Scalar_Field(field);
  Kill_Stack(stack);
  Kill_Stack(label);
  
  return 0;
}
예제 #11
0
ZSwcTree* ZNeuronTracer::trace(Stack *stack, bool doResampleAfterTracing)
{
  startProgress();

  ZSwcTree *tree = NULL;

  //Extract seeds
  //First mask
  std::cout << "Binarizing ..." << std::endl;

  /* <bw> allocated */
  Stack *bw = binarize(stack);
  C_Stack::translate(bw, GREY, 1);

  advanceProgress(0.05);

  std::cout << "Removing noise ..." << std::endl;

  /* <mask> allocated */
  Stack *mask = bwsolid(bw);
  advanceProgress(0.05);

  /* <bw> freed */
  C_Stack::kill(bw);

  //Thin line mask
  /* <mask2> allocated */
  Stack *mask2 = NULL;

  if (m_enhancingMask) {
    std::cout << "Enhancing thin branches ..." << std::endl;
    mask2 = enhanceLine(stack);
    advanceProgress(0.05);
  }

  if (mask2 != NULL) {
    std::cout << "Making mask for thin branches ..." << std::endl;
    ZStackBinarizer binarizer;
    binarizer.setMethod(ZStackBinarizer::BM_LOCMAX);
    binarizer.setRetryCount(5);
    binarizer.setMinObjectSize(27);

    if (binarizer.binarize(mask2) == false) {
      std::cout << "Thresholding failed" << std::endl;
      C_Stack::kill(mask2);
      mask2 = NULL;
    }
  }

  /* <mask2> freed */
  if (mask2 != NULL) {
    C_Stack::translate(mask2, GREY, 1);
    Stack_Or(mask, mask2, mask);
    C_Stack::kill(mask2);
    mask2 = NULL;
  }
  advanceProgress(0.05);

  //Trace each seed
  std::cout << "Extracting seed points ..." << std::endl;

  /* <seedPointArray> allocated */
  Geo3d_Scalar_Field *seedPointArray = extractSeed(mask);
  m_mask = mask;

  advanceProgress(0.05);

  std::cout << "Sorting seeds ..." << std::endl;
  ZNeuronTraceSeeder seeder;
  setTraceScoreThreshold(TRACING_SEED);
  m_baseMask = seeder.sortSeed(seedPointArray, stack, m_traceWorkspace);

#ifdef _DEBUG_2
  C_Stack::write(GET_TEST_DATA_DIR + "/test.tif", m_baseMask);
#endif

  advanceProgress(0.1);

  /* <seedPointArray> freed */
  Kill_Geo3d_Scalar_Field(seedPointArray);

  std::vector<Local_Neuroseg>& locsegArray = seeder.getSeedArray();
  std::vector<double>& scoreArray = seeder.getScoreArray();

  std::cout << "Tracing ..." << std::endl;

  /* <chainArray> allocated */

  std::vector<Locseg_Chain*> chainArray = trace(stack, locsegArray, scoreArray);

  if (m_recover > 0) {
    std::vector<Locseg_Chain*> newChainArray = recover(stack);
    chainArray.insert(
          chainArray.end(), newChainArray.begin(), newChainArray.end());
  }
  advanceProgress(0.1);

  chainArray = screenChain(stack, chainArray);
  advanceProgress(0.3);

  /* <mask2> freed */
//  C_Stack::kill(mask);

  std::cout << "Reconstructing ..." << std::endl;
  ZNeuronConstructor constructor;
  constructor.setWorkspace(m_connWorkspace);
  constructor.setSignal(stack);

  //Create neuron structure

  BOOL oldSpTest = m_connWorkspace->sp_test;
  if (chainArray.size() > 1000) {
    std::cout << "Too many chains: " << chainArray.size() << std::endl;
    std::cout << "Turn off shortest path test" << std::endl;
    m_connWorkspace->sp_test = FALSE;
  }

  /* free <chainArray> */
  tree = constructor.reconstruct(chainArray);

  m_connWorkspace->sp_test = oldSpTest;

  advanceProgress(0.1);

  //Post process
  Swc_Tree_Remove_Zigzag(tree->data());
  Swc_Tree_Tune_Branch(tree->data());
  Swc_Tree_Remove_Spur(tree->data());
  Swc_Tree_Merge_Close_Node(tree->data(), 0.01);
  Swc_Tree_Remove_Overshoot(tree->data());

  if (doResampleAfterTracing) {
    ZSwcResampler resampler;
    resampler.optimalDownsample(tree);
  }
  advanceProgress(0.1);

  std::cout << "Done!" << std::endl;
  endProgress();

  return tree;
}
예제 #12
0
std::vector<Locseg_Chain*> ZNeuronTracer::recover(const Stack *stack)
{
  std::vector<Locseg_Chain*> chainArray;

  if (m_mask != NULL) {
    Stack *leftover = C_Stack::translate(m_mask, GREY, 0);
    Stack *traceMask = C_Stack::make(
          GREY, C_Stack::width(m_mask), C_Stack::height(m_mask),
          C_Stack::depth(m_mask));
    uint16_t *traceMaskArray =
        C_Stack::guardedArray16(m_traceWorkspace->trace_mask);
    size_t nvoxel = C_Stack::voxelNumber(m_mask);
    for (size_t i = 0; i < nvoxel; i++) {
      if ((traceMaskArray[i] > 0) || (m_baseMask->array[i] == 1)) {
        traceMask->array[i] = 1;
      } else {
        traceMask->array[i] = 0;
      }
    }

    C_Stack::kill(m_baseMask);
    m_baseMask = NULL;

    Stack *submask = Stack_Z_Dilate(traceMask, 5, stack, NULL);
    Stack_Bsub(leftover, submask, traceMask);

    C_Stack::kill(submask);
    submask = NULL;

    Stack_Remove_Small_Object(traceMask, leftover, 27, 26);
    C_Stack::translate(leftover, GREY, 1);

#ifdef _DEBUG_2
  C_Stack::write(GET_TEST_DATA_DIR + "/test.tif", leftover);
#endif

    if (Stack_Is_Dark(leftover) == FALSE) {
      double originalMinLength = m_traceWorkspace->min_chain_length;
      if (m_traceWorkspace->refit == FALSE) {
        m_traceWorkspace->min_chain_length =
            (NEUROSEG_DEFAULT_H  - 1.0) * 2.0 - 1.0;
      } else {
        m_traceWorkspace->min_chain_length =
            (NEUROSEG_DEFAULT_H  - 1.0) * 1.5 - 1.0;
      }

      /* <seedPointArray> allocated */
      Geo3d_Scalar_Field *seedPointArray = extractSeed(leftover);
      C_Stack::kill(leftover);
      leftover = NULL;

      ZNeuronTraceSeeder seeder;
      setTraceScoreThreshold(TRACING_SEED);
      m_baseMask = seeder.sortSeed(seedPointArray, stack, m_traceWorkspace);

      /* <seedPointArray> freed */
      Kill_Geo3d_Scalar_Field(seedPointArray);

      std::vector<Local_Neuroseg>& locsegArray = seeder.getSeedArray();
      std::vector<double>& scoreArray = seeder.getScoreArray();
      chainArray = trace(stack, locsegArray, scoreArray);
      m_traceWorkspace->min_chain_length = originalMinLength;
    }
  }

  return chainArray;
}
예제 #13
0
int main(int argc, char* argv[])
{
  if (Show_Version(argc, argv, "1.00") == 1) {
    return 0;
  }

  static char *Spec[] = {
    " <image:string> -s <string> -o <string> [-e <string>] [-fo <int>] "
    "[-z <double> | -res <string>] [-field <int>] [-min_score <double>]",
    NULL};
  
  Process_Arguments(argc, argv, Spec, 1);
  
  Geo3d_Scalar_Field *seed = Read_Geo3d_Scalar_Field(Get_String_Arg("-s"));

  size_t idx;
  double max_r = darray_max(seed->values, seed->size, &idx);

  max_r *= 1.5;

  //Set_Neuroseg_Max_Radius(max_r);

  Stack *signal = Read_Stack_U(Get_String_Arg("image"));

  dim_type dim[3];
  dim[0] = signal->width;
  dim[1] = signal->height;
  dim[2] = signal->depth;

  Rgb_Color color;
  Set_Color(&color, 255, 0, 0);

  int seed_offset = -1;

  double z_scale = 1.0;

  if (Is_Arg_Matched("-res")) {
    if (fexist(Get_String_Arg("-res"))) {
      double res[3];
      int length;
      darray_read2(Get_String_Arg("-res"), res, &length);
      if (res[0] != res[1]) {
	perror("Different X-Y resolutions.");
	TZ_ERROR(ERROR_DATA_VALUE);
      }
      z_scale = res[0] / res[2] * 2.0;
    }
  }
  
  if (Is_Arg_Matched("-z")) {
    z_scale = Get_Double_Arg("-z");
  }

  printf("z scale: %g\n", z_scale);

  tic();


  double *values = darray_malloc(seed->size);

  int i;
  Local_Neuroseg *locseg = (Local_Neuroseg *) 
    malloc(seed->size * sizeof(Local_Neuroseg));


  int index = 0;

  //int ncol = LOCAL_NEUROSEG_NPARAM + 1 + 23;
  //double *features = darray_malloc(seed->size * ncol);
  //double *tmpfeats = features;

  Stack *seed_mask = Make_Stack(GREY, signal->width, signal->height, 
				signal->depth);
  Zero_Stack(seed_mask);

  Locseg_Fit_Workspace *fws = New_Locseg_Fit_Workspace();
  
  if (Is_Arg_Matched("-field")) {
    fws->sws->field_func = Neuroseg_Slice_Field_Func(Get_Int_Arg("-field"));
  }

  fws->sws->fs.n = 2;
  fws->sws->fs.options[0] = STACK_FIT_DOT;
  fws->sws->fs.options[1] = STACK_FIT_CORRCOEF;

  if (Is_Arg_Matched("-fo")) {
    fws->sws->fs.options[1] = Get_Int_Arg("-fo");
  }

  for (i = 0; i < seed->size; i++) {
    printf("-----------------------------> seed: %d / %d\n", i, seed->size);

    index = i;
    int x = (int) seed->points[index][0];
    int y = (int) seed->points[index][1];
    int z = (int) seed->points[index][2];

    double width = seed->values[index];

    seed_offset = Stack_Util_Offset(x, y, z, signal->width, signal->height,
				    signal->depth);

    if (width < 3.0) {
      width += 0.5;
    }
    Set_Neuroseg(&(locseg[i].seg), width, 0.0, NEUROSEG_DEFAULT_H, 
		 0.0, 0.0, 0.0, 0.0, 1.0);

    double cpos[3];
    cpos[0] = x;
    cpos[1] = y;
    cpos[2] = z;
    cpos[2] /= z_scale;
    
    Set_Neuroseg_Position(&(locseg[i]), cpos, NEUROSEG_CENTER);

    if (seed_mask->array[seed_offset] > 0) {
      printf("labeled\n");
      values[i] = 0.0;
      continue;
    }

    //Local_Neuroseg_Optimize(locseg + i, signal, z_scale, 0);
    Local_Neuroseg_Optimize_W(locseg + i, signal, z_scale, 0, fws);

    values[i] = fws->sws->fs.scores[1];
    /*
    Stack_Fit_Score fs;
    fs.n = 1;
    fs.options[0] = 1;
    values[i] = Local_Neuroseg_Score(locseg + i, signal, z_scale, &fs);
    */

    //values[i] = Local_Neuroseg_Score_W(locseg + i, signal, z_scale, sws);

    printf("%g\n", values[i]);

    double min_score = LOCAL_NEUROSEG_MIN_CORRCOEF;
    if (Is_Arg_Matched("-min_score")) {
      min_score = Get_Double_Arg("-min_score");
    }

    if (values[i] > min_score) {
      Local_Neuroseg_Label_G(locseg + i, seed_mask, -1, 2, z_scale);
    } else {
      Local_Neuroseg_Label_G(locseg + i, seed_mask, -1, 1, z_scale);
    }

    /*
    tmpfeats += Local_Neuroseg_Param_Array(locseg + i, z_scale, tmpfeats);
    
    tmpfeats += Local_Neuroseg_Stack_Feature(locseg + i, signal, z_scale, 
					     tmpfeats); 
    */
  }

  if (Is_Arg_Matched("-e")) {
    Write_Stack(Get_String_Arg("-e"), seed_mask);
  }
  Write_Local_Neuroseg_Array(Get_String_Arg("-o"), locseg, seed->size);

  char file_path[MAX_PATH_LENGTH];
  sprintf(file_path, "%s_score", Get_String_Arg("-o"));
  darray_write(file_path, values, seed->size);

  //sprintf(file_path, "%s_feat", Get_String_Arg("-o"));
  //darray_write(file_path, features, seed->size * ncol); 

  Kill_Geo3d_Scalar_Field(seed);

  printf("Time passed: %lld\n", toc());

  
  return 0;
}
예제 #14
0
/*
 * trace_neuron - trace neuron from given seeds
 *
 * trace_neuron [!wtr] seed_file -Dsave_dir
 *   -r: write intermediate results
 *
 */
int main(int argc, char* argv[])
{
  static char *Spec[] = {
    "[!wtr] [-canvas <string>] [-mask <string>] [-res <string>] [-minr <int>]",
    "-minlen <double>",
    " <image:string> -S<string> -D<string>",
    NULL};
  
  Process_Arguments(argc, argv, Spec, 1);
  
  char *dir = Get_String_Arg("-D");
  
  char file_path[100];
  sprintf(file_path, "%s/%s", dir, Get_String_Arg("-S"));
  printf("%s\n", file_path);

  Geo3d_Scalar_Field *seed = Read_Geo3d_Scalar_Field(file_path);

  int idx;

  sprintf(file_path, "%s/%s.bn", dir, "max_r");
  double max_r;
  int tmp;
  if (fexist(file_path)) {
    darray_read2(file_path, &max_r, &tmp);
  } else {
    max_r = darray_max(seed->values, seed->size, &idx);
  }

  printf("%g\n", max_r);

  max_r *= 1.5;

  /*
  sprintf(file_path, "%s/%s", dir, "soma0.bn");
  if (!fexist(file_path)) {
    max_r *= 2.0;
  }
  */
   
  Set_Neuroseg_Max_Radius(max_r);

  Stack *signal = Read_Stack(Get_String_Arg("image"));

  dim_type dim[3];
  dim[0] = signal->width;
  dim[1] = signal->height;
  dim[2] = signal->depth;
  /* 
  IMatrix *chord = Make_IMatrix(dim, 3);
  
  Stack *code = Make_Stack(GREY16, 
			   signal->width, signal->height, signal->depth);
  */
  Rgb_Color color;
  Set_Color(&color, 255, 0, 0);

  Stack *canvas = NULL;

  char trace_file_path[100];
  sprintf(trace_file_path, "%s/%s", dir, Get_String_Arg("-canvas"));
  
  if (fexist(trace_file_path) == 1) {
    canvas = Read_Stack((char *) trace_file_path);
  } else {
    canvas = Copy_Stack(signal);
    Stretch_Stack_Value_Q(canvas, 0.999);
    Translate_Stack(canvas, COLOR, 1);
  }

  Stack *traced = NULL;
  
  char trace_mask_path[100];
  sprintf(trace_mask_path, "%s/%s", dir, Get_String_Arg("-mask"));

  if (fexist(trace_mask_path) == 1) {
    traced = Read_Stack((char *) trace_mask_path);
  } else {
    traced = Make_Stack(GREY, signal->width, signal->height, signal->depth);
    One_Stack(traced);
  }
  

  //Object_3d *obj = NULL;
  int seed_offset = -1;

  Neurochain *chain = NULL;

  double z_scale = 1.0;

  if (Is_Arg_Matched("-res")) {
    sprintf(file_path, "%s", Get_String_Arg("-res"));

    if (fexist(file_path)) {
      double res[3];
      int length;
      darray_read2(file_path, res, &length);
      if (res[0] != res[1]) {
	perror("Different X-Y resolutions.");
	TZ_ERROR(ERROR_DATA_VALUE);
      }
      z_scale = res[0] / res[2];
    }
  }

  //sprintf(file_path, "%s/%s", dir, Get_String_Arg("-M"));
  //Stack *stack = Read_Stack(file_path);

  tic();

  FILE *fp = NULL;
  char chain_file_path[100];
  char vrml_file_path[100];

  double min_chain_length = 25.0;

  if (Is_Arg_Matched("-minlen")) {
    min_chain_length = Get_Double_Arg("-minlen");
  }

  int *indices = iarray_malloc(seed->size);
  double *values = darray_malloc(seed->size);
  int i;

  Local_Neuroseg *locseg = (Local_Neuroseg *) 
    malloc(seed->size * sizeof(Local_Neuroseg));

  int index = 0;
  for (i = 0; i < seed->size; i++) {
    printf("-----------------------------> seed: %d / %d\n", i, seed->size);
    indices[i] = i;
    index = i;
    int x = (int) seed->points[index][0];
    int y = (int) seed->points[index][1];
    int z = (int) seed->points[index][2];

    double width = seed->values[index];

    chain = New_Neurochain();

    seed_offset = Stack_Util_Offset(x, y, z, signal->width, signal->height,
				    signal->depth);

    if (width < 3.0) {
      width += 0.5;
    }
    Set_Neuroseg(&(locseg[i].seg), width, width, 12.0, 
		 0.0, 0.0, 0.0);

    double cpos[3];
    cpos[0] = x;
    cpos[1] = y;
    cpos[2] = z;
    cpos[2] *= z_scale;
    
    Set_Neuroseg_Position(&(locseg[i]), cpos, NEUROSEG_CENTER);
    Stack_Fit_Score fs;
    fs.n = 1;
    fs.options[0] = 1;
    values[i] = Local_Neuroseg_Orientation_Search_C(&(locseg[i]), signal, z_scale, &fs);
  }

  darray_qsort(values, indices, seed->size);

  /*
  for (i = 0; i < seed->size; i++) {
    indices[i] = i;
  }
  darraycpy(values, seed->values, 0, seed->size);
  darray_qsort(values, indices, seed->size);
  */

  int counter = 0;

  //  for (i = seed->size - 1; i >= seed->size - 231; i--) {
  for (i = seed->size - 1; i >= 0; i--) {
    index = indices[i];

    printf("-----------------------------> seed: %d / %d\n", i, seed->size);
    
    sprintf(chain_file_path, "%s/chain%d.bn", dir, index);
    sprintf(vrml_file_path, "%s/chain%d.wrl", dir, index);

    if (fexist(chain_file_path) == 1) {
      chain = Read_Neurochain(chain_file_path);
      if (Neurochain_Geolen(chain) >= min_chain_length) {
	Write_Neurochain_Vrml(vrml_file_path, chain);
	Neurochain_Label(canvas, chain, z_scale);
	Neurochain_Erase_E(traced, chain, z_scale, 0,
			   Neurochain_Length(chain, FORWARD),
			   1.5, 0.0);
      }

      Free_Neurochain(chain);
      printf("chain exists\n");
      continue;
    }
    
    
    int x = (int) seed->points[index][0];
    int y = (int) seed->points[index][1];
    int z = (int) seed->points[index][2];

    if (*STACK_PIXEL_8(traced, x, y, z, 0) == 0) {
      printf("traced \n");
      continue;
    }

    double width = seed->values[index];

    if (width > max_r) {
      printf("too thick\n");
      continue;
    }
    
    if (Is_Arg_Matched("-minr")) {
      int max_level = (int) (width + 0.5);
      if (max_level <= Get_Int_Arg("-minr")) {
	printf("too thin\n");
	continue;
      }
    }
    /*
    seed_offset = Stack_Util_Offset(x, y, z, signal->width, signal->height,
				    signal->depth);
    */

    chain = New_Neurochain();
    /*
    Stack_Level_Code_Constraint(stack, code, chord->array, &seed_offset, 1, 
				max_level + 1);

    Voxel_t v;
    v[0] = x;
    v[1] = y;
    v[2] = z;

    Stack *tmp_stack = Copy_Stack(stack);
    obj = Stack_Grow_Object_Constraint(tmp_stack, 1, v, chord, code, 
				       max_level);
    Free_Stack(tmp_stack);

    Print_Object_3d_Info(obj);
    
    double vec[3];
    Object_3d_Orientation_Zscale(obj, vec, MAJOR_AXIS, z_scale);

    double theta, psi;
    Geo3d_Vector obj_vec;
    Set_Geo3d_Vector(&obj_vec, vec[0], vec[1], vec[2]);

    Geo3d_Vector_Orientation(&obj_vec, &theta, &psi);
    */

    /*
    if (width < 3.0) {
      width += 0.5;
    }
    Set_Neuroseg(&(chain->locseg.seg), width, width, 12.0, 
		 0.0, 0.0, 0.0);

    double cpos[3];
    cpos[0] = x;
    cpos[1] = y;
    cpos[2] = z;
    cpos[2] *= z_scale;
    
    //Set_Neuroseg_Position(&(chain->locseg), cpos, NEUROSEG_BOTTOM);
    Set_Neuroseg_Position(&(chain->locseg), cpos, NEUROSEG_CENTER);
    Stack_Fit_Score fs;
    fs.n = 1;
    fs.options[0] = 1;
    Local_Neuroseg_Orientation_Search_C(&(chain->locseg), signal, z_scale,
					&fs); 
    //fs.options[0] = 1;
    */

    Copy_Local_Neuroseg(&(chain->locseg), &(locseg[index]));
    Neurochain *chain_head = chain;
    
    
    if (Initialize_Tracing(signal, chain, NULL, z_scale) >= MIN_SCORE) {
      if ((Neuroseg_Hit_Traced(&(chain->locseg), traced, z_scale) == FALSE) &&
	  (chain->locseg.seg.r1 < max_r) && 
	  (chain->locseg.seg.r2 < max_r)) {
	//Initialize_Tracing(signal, chain, NULL, z_scale);
	chain = Trace_Neuron2(signal, chain, BOTH, traced, z_scale, 500);

	//Neurochain *chain_head = Neurochain_Head(chain);
	chain_head = Neurochain_Remove_Overlap_Segs(chain);
	chain_head = Neurochain_Remove_Turn_Ends(chain_head, 0.5);
	/*
	if (i == seed->size - 231) {
	  Print_Neurochain(chain_head);
	}
	*/

	fp = fopen(chain_file_path, "w");
	Neurochain_Fwrite(chain_head, fp);
	fclose(fp);
	if (Neurochain_Geolen(chain_head) >= min_chain_length) {
	  Write_Neurochain_Vrml(vrml_file_path, chain_head);

	  Neurochain_Erase_E(traced, chain_head, z_scale, 0,
			     Neurochain_Length(chain_head, FORWARD),
			     1.5, 0.0);
	  Neurochain_Label(canvas, chain_head, z_scale);

	  counter += Neurochain_Length(chain_head, FORWARD);
	  if (counter > 500) {
	    if (Is_Arg_Matched("-r")) {
	      Write_Stack((char *) trace_mask_path, traced);
	    }
	    
	    if (Is_Arg_Matched("-r")) {
	    Write_Stack((char *) trace_file_path, canvas);
	    }

	    counter = 0;
	  }
	}
      }
    }

    Free_Neurochain(chain_head);

    //Kill_Object_3d(obj);
  }

  Write_Stack((char *) trace_file_path, canvas);
  if (Is_Arg_Matched("-r")) {
    Write_Stack((char *) trace_mask_path, traced);
  }

  Kill_Geo3d_Scalar_Field(seed);

  printf("Time passed: %lld\n", toc());

  
  return 0;
}