void normalize_data_to_match_target(VIO_Volume d1, VIO_Volume m1, VIO_Real thresh1,
                                           VIO_Volume d2, VIO_Volume m2, VIO_Real thresh2,
                                           Arg_Data *globals)
{

  VectorR
    vector_step;

  PointR
    starting_position,
    slice,
    row,
    col,
    pos2,
    voxel;

  double
    tx,ty,tz;
  int
    i,j,k,
    r,c,s;

  VIO_Real
    min_range, max_range,
    data_vox, data_val,
    value1, value2;
  
  VIO_Real
    t1,t2,                        /* temporary threshold values     */
    s1,s2,s3;                   /* to store the sums for f1,f2,f3 */
  float 
    *ratios,
    result;                                /* the result */
  int 
    sizes[VIO_MAX_DIMENSIONS],ratios_size,count1,count2;

  VIO_Volume 
    vol;

  VIO_progress_struct
    progress;

  VIO_Data_types 
    data_type;


  set_feature_value_threshold(d1,d2, 
                              &thresh1, &thresh2,
                              &t1,      &t2);                              

  if (globals->flags.debug) {
    print ("In normalize_data_to_match_target, thresh = %10.3f %10.3f\n",t1,t2) ;
  }

  ratios_size = globals->count[ROW_IND] * globals->count[COL_IND] * globals->count[SLICE_IND];

  ALLOC(ratios, ratios_size);  

  fill_Point( starting_position, globals->start[VIO_X], globals->start[VIO_Y], globals->start[VIO_Z]);

  s1 = s2 = s3 = 0.0;
  count1 = count2 = 0;

  for(s=0; s<=globals->count[SLICE_IND]; s++) {

    SCALE_VECTOR( vector_step, globals->directions[SLICE_IND], s);
    ADD_POINT_VECTOR( slice, starting_position, vector_step );

    for(r=0; r<=globals->count[ROW_IND]; r++) {
      
      SCALE_VECTOR( vector_step, globals->directions[ROW_IND], r);
      ADD_POINT_VECTOR( row, slice, vector_step );
      
      SCALE_POINT( col, row, 1.0); /* init first col position */
      for(c=0; c<=globals->count[COL_IND]; c++) {
        
        convert_3D_world_to_voxel(d1, Point_x(col), Point_y(col), Point_z(col), &tx, &ty, &tz);
        
        fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */
        
        if (point_not_masked(m1, Point_x(col), Point_y(col), Point_z(col))) {

          value1 = get_value_of_point_in_volume( Point_x(col), Point_y(col), Point_z(col), d1);

          if ( value1 > t1 ) {

            count1++;

            DO_TRANSFORM(pos2, globals->trans_info.transformation, col);
            
            convert_3D_world_to_voxel(d2, Point_x(pos2), Point_y(pos2), Point_z(pos2), &tx, &ty, &tz);
            
            fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */
        
            if (point_not_masked(m2, Point_x(pos2), Point_y(pos2), Point_z(pos2))) {

              value2 = get_value_of_point_in_volume( Point_x(pos2), Point_y(pos2), Point_z(pos2), d2);

              if ( (value2 > t2)  && 
                   ((value2 < -1e-15) || (value2 > 1e-15)) ) {
                  
                ratios[count2++] = value1 / value2 ;

                s1 += value1*value2;
                s2 += value1*value1;
                s3 += value2*value2;
                  
                
              } /* if voxel in d2 */
            } /* if point in mask volume two */
          } /* if voxel in d1 */
        } /* if point in mask volume one */
        
        ADD_POINT_VECTOR( col, col, globals->directions[COL_IND] );
        
      } /* for c */
    } /* for r */
  } /* for s */
  

  if (count2 > 0) {

    if (globals->flags.debug) (void)print ("Starting qsort of ratios...");


    qs_list (ratios,0,count2);

    if (globals->flags.debug) (void)print ("Done.\n");

    result = ratios[ (int)(count2/2) ];        /* the median value */

    if (globals->flags.debug) (void)print ("Normalization: %7d %7d -> %10.8f\n",count1,count2,result);

    if ( fabs(result) < 1e-15) {
      print_error_and_line_num("Error computing normalization ratio `%f'.",__FILE__, __LINE__, result);
    }
    else {

      data_type = get_volume_data_type(d1);



      
      switch( data_type ) {
      case SIGNED_BYTE: 
      case UNSIGNED_BYTE: 
      case SIGNED_SHORT: 
      case UNSIGNED_SHORT: 
	
	/* build temporary working volume */
	
	vol = copy_volume_definition_no_alloc(d1, NC_UNSPECIFIED, FALSE, 0.0, 0.0);
	get_volume_minimum_maximum_real_value(d1, &min_range, &max_range);
	min_range /= result;
	max_range /= result;
	set_volume_real_range(vol, min_range, max_range);
	get_volume_sizes(d1, sizes);
	
	initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1,
				   "Normalizing source data" );
	count1 = 0;
	
	/* reset values in the data volume */
	
	for(i=0; i<sizes[0]; i++)
	  for(j=0; j<sizes[1]; j++) {
	    count1++;
	    update_progress_report( &progress, count1);
	    for(k=0; k<sizes[2]; k++) {
	      GET_VOXEL_3D( data_vox,  d1, i, j, k );
	      data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox);
	      data_val /= result;
	      data_vox = CONVERT_VALUE_TO_VOXEL( vol, data_val);
	      SET_VOXEL_3D( d1 , i, j, k, data_vox );
	    }
	  }
	
	terminate_progress_report( &progress );
	
	set_volume_real_range(d1, min_range, max_range);
	
	if (globals->flags.debug) (void)print ("After normalization min,max, thresh = %f %f %f\n",
					       min_range, max_range, t1/result);
	
	delete_volume(vol);
	break;
	
      default:			/* then volume should be either float or double */
	
	get_volume_sizes(d1, sizes);
	initialize_progress_report(&progress, FALSE, sizes[0]*sizes[1]*sizes[2] + 1,
				   "Normalizing source data" );
	count1 = 0;
	
	/* nomalize the values in the data volume */
	
	for(i=0; i<sizes[0]; i++)
	  for(j=0; j<sizes[1]; j++) {
	    count1++;
	    update_progress_report( &progress, count1);
	    
	    for(k=0; k<sizes[2]; k++) {	/* it should be possible to directly stream through the voxels, without indexing... */
	      GET_VOXEL_3D( data_vox,  d1, i, j, k );
	      data_val = CONVERT_VOXEL_TO_VALUE(d1, data_vox);
	      data_val /= result;
	      data_vox = CONVERT_VALUE_TO_VOXEL( d1, data_val);
	      SET_VOXEL_3D( d1 , i, j, k, data_vox );
	    }
	  }
	terminate_progress_report( &progress );
      }
    }
    
  }
  FREE(ratios);

  
}
VIO_BOOL vol_to_cov(VIO_Volume d1, VIO_Volume m1, float centroid[4], float covar[4][4], double *step)
{

  VectorR
    vector_step,
    slice_step,
    row_step,
    col_step;

  PointR 
    starting_offset,
    starting_origin,
    starting_position,
    slice,
    row,
    col,
    voxel;

  VIO_Real
    tx,ty,tz;
  int
    i,r,c,s,
    limits[VOL_NDIMS];

  float
    t,
    sxx,syy,szz,
    sxy,syz,sxz,
    sx,sy,sz,si; 
  VIO_Real
    thickness[3];
  int
    sizes[3];

  VIO_Real
    true_value;

  get_volume_separations(d1, thickness);
  get_volume_sizes(d1, sizes);
  
                                /* build sampling lattice info */
  for(i=0; i<3; i++) {        
    step[i] *= thickness[i] / fabs( thickness[i]);
  }

  fill_Vector( col_step,   step[COL_IND], 0.0,     0.0 );
  fill_Vector( row_step,   0.0,     step[ROW_IND], 0.0 );
  fill_Vector( slice_step, 0.0,     0.0,     step[SLICE_IND] );

  convert_3D_voxel_to_world(d1, 0.0, 0.0, 0.0, &tx, &ty, &tz); 

  fill_Point( starting_origin, tx, ty, tz);

  for(i=0; i<3; i++) {                /* for each dim, get # of steps in that direction,
                                   and set starting offset */
    t = sizes[i] * thickness[i] / step[i];
    limits[i] = abs( t );
    
    Point_coord( starting_offset, (i) ) = 
      ( (sizes[i]-1)*thickness[i] - (limits[i] * step[i] ) ) / 2.0;
  }
  
  ADD_POINTS( starting_position, starting_origin, starting_offset ); /*  */

                                /* calculate centroids first */

  sx = 0.0;
  sy = 0.0;
  sz = 0.0;
  si = 0.0;

  for(s=0; s<=limits[SLICE_IND]; s++) {

    SCALE_VECTOR( vector_step, slice_step, s);
    ADD_POINT_VECTOR( slice, starting_position, vector_step );

    for(r=0; r<=limits[ROW_IND]; r++) {

      SCALE_VECTOR( vector_step, row_step, r);
      ADD_POINT_VECTOR( row, slice, vector_step );

      SCALE_POINT( col, row, 1.0); /* init first col position */
      for(c=0; c<=limits[COL_IND]; c++) {

        convert_3D_world_to_voxel(d1, Point_x(col), Point_y(col), Point_z(col), &tx, &ty, &tz);

        fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */
        
        if (point_not_masked(m1, Point_x(col), Point_y(col), Point_z(col))) {
          
          if (INTERPOLATE_TRUE_VALUE( d1, &voxel, &true_value )) {
            
            sx +=  Point_x(col) * true_value;
            sy +=  Point_y(col) * true_value;
            sz +=  Point_z(col) * true_value;
            
            si += true_value;
          }
          /* else requested voxel is just outside volume., so ignore it */

        } 
        
        ADD_POINT_VECTOR( col, col, col_step );
        
      }
    }
  }

  if (si!=0.0) {
    centroid[1] = sx/ si;
    centroid[2] = sy/ si;
    centroid[3] = sz/ si;
    
    sxx = syy = szz = 0.0;
    sxy = syz = sxz = 0.0;
    
                                /* now calculate variances and co-variances */

    for(s=0; s<=limits[VIO_Z]; s++) {
      
      SCALE_VECTOR( vector_step, slice_step, s);
      ADD_POINT_VECTOR( slice, starting_position, vector_step );
      
      for(r=0; r<=limits[VIO_Y]; r++) {
        
        SCALE_VECTOR( vector_step, row_step, r);
        ADD_POINT_VECTOR( row, slice, vector_step );
        
        SCALE_POINT( col, row, 1.0); /* init first col position */
        for(c=0; c<=limits[VIO_X]; c++) {
          
          convert_3D_world_to_voxel(d1, Point_x(col), Point_y(col), Point_z(col), &tx, &ty, &tz);

          fill_Point( voxel, tx, ty, tz ); /* build the voxel POINT */
        
          if (point_not_masked(m1, Point_x(col), Point_y(col), Point_z(col))) {
            
            if (INTERPOLATE_TRUE_VALUE( d1, &voxel, &true_value )) {
              
                    sxx += (Point_x( col )-centroid[1]) * (Point_x( col )-centroid[1]) * true_value;
              syy += (Point_y( col )-centroid[2]) * (Point_y( col )-centroid[2]) * true_value;
              szz += (Point_z( col )-centroid[3]) * (Point_z( col )-centroid[3]) * true_value;
              sxy += (Point_x( col )-centroid[1]) * (Point_y( col )-centroid[2]) * true_value;
              syz += (Point_y( col )-centroid[2]) * (Point_z( col )-centroid[3]) * true_value;
              sxz += (Point_x( col )-centroid[1]) * (Point_z( col )-centroid[3]) * true_value;

            }
            /* else requested voxel is just outside volume., so ignore it */

          } 
          
          ADD_POINT_VECTOR( col, col, col_step );
        
        }
      }
    }
    
    covar[1][1] = sxx/si; covar[1][2] = sxy/si; covar[1][3] = sxz/si;
    covar[2][1] = sxy/si; covar[2][2] = syy/si; covar[2][3] = syz/si;
    covar[3][1] = sxz/si; covar[3][2] = syz/si; covar[3][3] = szz/si;
    
    return(TRUE);
    
  }
  else {
    return(FALSE);
  }
}
void add_speckle_to_volume(VIO_Volume d1, 
                                  float speckle,
                                  double  *start, int *count, VectorR directions[])
{
  VectorR
    vector_step;

  PointR 
    starting_position,
    slice,
    row,
    col;
  VIO_Real valid_min_voxel, valid_max_voxel;

  double
    tx,ty,tz,
    voxel_value;
  int
    xi,yi,zi,
    flip_flag,r,c,s;


  flip_flag = FALSE;

  get_volume_voxel_range(d1, &valid_min_voxel, &valid_max_voxel);
  fill_Point( starting_position, start[0], start[1], start[2]);
  
  for(s=0; s<count[SLICE_IND]; s++) {

    SCALE_VECTOR( vector_step, directions[SLICE_IND], s);
    ADD_POINT_VECTOR( slice, starting_position, vector_step );

    for(r=0; r<count[ROW_IND]; r++) {

      SCALE_VECTOR( vector_step, directions[ROW_IND], r);
      ADD_POINT_VECTOR( row, slice, vector_step );

      SCALE_POINT( col, row, 1.0); /* init first col position */
      for(c=0; c<count[COL_IND]; c++) {

        convert_3D_world_to_voxel(d1, Point_x(col), Point_y(col), Point_z(col), &tx, &ty, &tz);

        xi = (int)floor(tx + 0.5);
        yi = (int)floor( ty + 0.5);
        zi = (int)floor( tz + 0.5 );

        GET_VOXEL_3D( voxel_value, d1 , xi, yi, zi ); 


        if (voxel_value >= valid_min_voxel && voxel_value <= valid_max_voxel) {
          if (flip_flag)
            voxel_value = voxel_value * (1 + 0.01*speckle);
          else
            voxel_value = voxel_value * (1 - 0.01*speckle);

          SET_VOXEL_3D( d1 , xi, yi, zi, voxel_value );
        }

        flip_flag = !flip_flag;


        ADD_POINT_VECTOR( col, col, directions[COL_IND] );

      }
        


    }
  }


}