示例#1
0
// transforms a 4D Volume in a SVM samples file, based on a mask
void saveSVMFile(volume4D <float> &volSamples, volume<float> &mask, const char *outputFileName, float minValue, vector <int > &indexes, vector <int> &classes)
{
	FILE *f;
	f = fopen(outputFileName, "wt+");
	if (f != NULL)
	{
		int i, t;
		for (int h = 0; h < indexes.size(); h++)
		{
			// picking the right indexes
			t = indexes[h] - 1;
			i = 0;
			// saving the class value. Remember indexes size is different from classes. classes has the same sime of the number of volumes
			fprintf(f, "%d ", classes[t]);
			for (int z = 0; z < mask.zsize(); z++)
				for (int y = 0; y < mask.ysize(); y++)
					for (int x = 0; x < mask.xsize(); x++)
						if (mask.value(x, y, z) > minValue)
						{
							i++;
							// writing each voxel value in svm format
							fprintf(f, "%d:%f ", i, volSamples.value(x, y, z, t));
						}
			fprintf(f, "\n");
		}
		fclose(f);
	}
}
示例#2
0
FnirtFileWriter::FnirtFileWriter(const string&              fname,
				 const volume<float>&       fieldx,                         
			         const volume<float>&       fieldy,                         
			         const volume<float>&       fieldz)
{
  volume<float>  tmp(fieldx.xsize(),fieldx.ysize(),fieldx.zsize());
  tmp.copyproperties(fieldx);
  Matrix         aff = IdentityMatrix(4);

  common_field_construction(fname,tmp,fieldx,fieldy,fieldz,aff);
}
示例#3
0
文件: bet2.cpp 项目: dungttbk/sips
volume<float> inside_mesh(const volume<float> & image, const Mesh& m)
{
  volume<float> res = image;
  int xsize = image.xsize();
  int ysize = image.ysize();
  int zsize = image.zsize();
  volume<short> inside = make_mask_from_mesh(image, m);
  for (int k=0; k<zsize; k++)
    for (int j=0; j<ysize; j++)
      for (int i=0; i<xsize; i++)
	res.value(i, j, k) = (1-inside.value(i, j, k)) * image.value(i, j, k);
  return res;
}
示例#4
0
文件: bet2.cpp 项目: dungttbk/sips
//calculates the mask from the mesh by spreading an initial point outside the mesh, and stopping it when the mesh is reached.
volume<short> make_mask_from_mesh(const volume<float> & image, const Mesh& m)
{
  //  cout<<"make_mask_from_mesh begins"<<endl;

  double xdim = (double) image.xdim();
  double ydim = (double) image.ydim();
  double zdim = (double) image.zdim();

  volume<short> mask;
  copyconvert(image,mask);
  
  int xsize = mask.xsize();
  int ysize = mask.ysize();
  int zsize = mask.zsize();
  
  mask = 1;
  
  mask = draw_mesh(mask, m);

  vector<Pt> current;
  current.clear();
  Pt c(0., 0., 0.);
  for (vector<Mpoint *>::const_iterator it=m._points.begin(); it!=m._points.end(); it++)
    c+=(*it)->get_coord();

  c*=(1./m._points.size());
  c.X/=xdim; c.Y/=ydim; c.Z/=zdim;

  current.push_back(c);

  while (!current.empty())
    {
      Pt pc = current.back();
      int x, y, z;
      x=(int) pc.X; y=(int) pc.Y; z=(int) pc.Z;
      //current.remove(pc);
      current.pop_back();
      mask.value(x, y, z) = 0;
      if (0<=x-1 && mask.value(x-1, y, z)==1) current.push_back(Pt(x-1, y, z));
      if (0<=y-1 && mask.value(x, y-1, z)==1) current.push_back(Pt(x, y-1, z));
      if (0<=z-1 && mask.value(x, y, z-1)==1) current.push_back(Pt(x, y, z-1));
      if (xsize>x+1 && mask.value(x+1, y, z)==1) current.push_back(Pt(x+1, y, z));
      if (ysize>y+1 && mask.value(x, y+1, z)==1) current.push_back(Pt(x, y+1, z));
      if (zsize>z+1 && mask.value(x, y, z+1)==1) current.push_back(Pt(x, y, z+1)); 
    }

  //  cout<<"make_mask_from_mesh ends"<<endl;
  return mask;
}
// calculates the mean for each roi
void RoiMeanCalculation::calculateMeans(volume<float> &actualvolume)
{
	if (means.size())
	{
		for (int i = 0; i < means.size(); i++) means[i] = 0;

		for (int z = 0; z < reference.zsize(); z++)
			for (int y = 0; y < reference.ysize(); y++)
				for (int x = 0; x < reference.xsize(); x++)
				{
					float value = reference.value(x, y, z);
					if (value != 0)
					{
						int idx = mapping[value];
						if (idx >= -1)
							means[idx] += actualvolume.value(x, y, z);
					}
				}

		for (int i = 0; i < means.size(); i++)
		{
			if (counts[i]) means[i] = means[i] / (float)counts[i];
		}
	}
}
示例#6
0
//extracts profiles in the area around the eyes
vector<double> t1only_special_extract(const volume<float> & t1, const Pt & point, const Vec & n) {
  vector<double> resul;
  resul.clear();
  bool output = true; 
  const double INNER_DEPTH = 3;
  const double OUTER_DEPTH = 100;
  
  Profile pt1;
  for (double d = -INNER_DEPTH; d < OUTER_DEPTH; d+=.5)
    {
      Pt c = point + d * n;
      double tmp1 = t1.interpolate(c.X, c.Y, c.Z);
      pt1.add (d, tmp1);
    }
  pt1.init_roi();

  //outer skin
  double outskin = pt1.last_point_over(pt1.end(), .2);
  double check = pt1.last_point_over(outskin - 1.5, .2);
  if (outskin - check > 2) output = false;
  
  pt1.set_rroi(outskin);
  
  double inskull = pt1.next_point_under(-INNER_DEPTH, .25);
  if (inskull > 5) inskull = 0;
  
  double outskull = pt1.next_point_over(inskull, .35);
  
  resul.push_back(inskull);
  resul.push_back(outskull);
  resul.push_back(outskin);
  
  return resul;
}
示例#7
0
void _volume2Sample(svm_model *model, volume<float> &volSample, volume<float> &mask, int sampleSize, float minValue, svm_node * &sample)
{	
	sample=(struct svm_node *) malloc((sampleSize+1)*sizeof(struct svm_node));
    
	int i=0;
    for(int z=0; z < volSample.zsize();z++)
      for(int y=0; y < volSample.ysize();y++)
	     for(int x=0; x < volSample.xsize();x++)
         if (mask.value(x,y,z) > minValue)
		   {
             sample[i].index = (i+1);
		       sample[i].value = volSample.value(x,y,z);
				 i++;
			}
    sample[i].index = -1;
}
示例#8
0
void draw_segment(volume<short>& image, const Pt& p1, const Pt& p2)
{
  double xdim = (double) image.xdim();
  double ydim = (double) image.ydim();
  double zdim = (double) image.zdim();
  double mininc = min(xdim,min(ydim,zdim)) * .5;
 
  Vec n = p1 - p2;
  double d = n.norm();
  n.normalize();

  for (double i=0; i<=d; i+=mininc)
    {
      Pt p = p2 + i* n;
      image((int) floor((p.X)/xdim +.5),(int) floor((p.Y)/ydim +.5),(int) floor((p.Z)/zdim +.5)) = 1;
    }
}
示例#9
0
void draw_mesh(volume<short>& image, const Mesh &m)
{
  double xdim = (double) image.xdim();
  double ydim = (double) image.ydim();
  double zdim = (double) image.zdim();
  double mininc = min(xdim,min(ydim,zdim)) * .5;

  for (list<Triangle*>::const_iterator i = m._triangles.begin(); i!=m._triangles.end(); i++)
    {
      Vec n = (*(*i)->get_vertice(0) - *(*i)->get_vertice(1));
      double d = n.norm();
      n.normalize();

      for (double j=0; j<=d; j+=mininc)
	{
	  Pt p = (*i)->get_vertice(1)->get_coord()  + j* n;
	  draw_segment(image, p, (*i)->get_vertice(2)->get_coord());
	} 
    }

}
示例#10
0
文件: integrate.cpp 项目: LeiDai/meep
void check_integral(fields &f,
		    linear_integrand_data &d, const volume &v,
		    component cgrid)
{
  double x1 = v.in_direction_min(d.dx);
  double x2 = v.in_direction_max(d.dx);
  double y1 = v.in_direction_min(d.dy);
  double y2 = v.in_direction_max(d.dy);
  double z1 = v.in_direction_min(d.dz);
  double z2 = v.in_direction_max(d.dz);
  
  master_printf("Check %d-dim. %s integral in %s cell with %s integrand...",
		(x2 - x1 > 0) + (y2 - y1 > 0) + (z2 - z1 > 0), 
		component_name(cgrid),
		v.dim == D3 ? "3d" : (v.dim == D2 ? "2d" : 
				       (v.dim == Dcyl ? "cylindrical" 
					: "1d")),
		(d.c == 1.0 && !d.axy && !d.ax && !d.ay && !d.az
		 && !d.axy && !d.ayz && !d.axz) ? "unit" : "linear");
  if (0)
    master_printf("\n... grid_volume (%g,%g,%g) at (%g,%g,%g) with integral (%g, %g,%g,%g, %g,%g,%g, %g)...\n",
		  x2 - x1, y2 - y1, z2 - z1,
		  (x1+x2)/2, (y1+y2)/2, (z1+z2)/2,
		  d.c, d.ax,d.ay,d.az, d.axy,d.ayz,d.axz, d.axyz);

  double sum = real(f.integrate(0, 0, linear_integrand, (void *) &d, v));
  if (fabs(sum - correct_integral(v, d)) > 1e-9 * fabs(sum))
    abort("FAILED: %0.16g instead of %0.16g\n", 
	  (double) sum, correct_integral(v, d));
  master_printf("...PASSED.\n");
}
示例#11
0
文件: bet2.cpp 项目: dungttbk/sips
volume<float> draw_mesh_bis(const volume<float>& image, const Mesh &m)
{
  double xdim = (double) image.xdim();
  double ydim = (double) image.ydim();
  double zdim = (double) image.zdim();
  double mininc = min(xdim,min(ydim,zdim)) * .5;
  volume<float> res = image;
  double max = image.max();
  for (list<Triangle*>::const_iterator i = m._triangles.begin(); i!=m._triangles.end(); i++)
    {
      Vec n = (*(*i)->get_vertice(0) - *(*i)->get_vertice(1));
      double d = n.norm();
      n.normalize();

      for (double j=0; j<=d; j+=mininc)
	{
	  Pt p = (*i)->get_vertice(1)->get_coord()  + j* n;
	  draw_segment_bis(res, p, (*i)->get_vertice(2)->get_coord(), max);
	} 
    }
  return res;
}
示例#12
0
// transforms an array in a volume
void array2Volume(const char *maskFile, float minValue, vector <double> &weightVector, volume<float> &weightVolume)
{
	volume<float> mask;
    if (maskFile != NULL)
    {
      string Maskfile = maskFile;
      read_volume(mask, Maskfile);
    }

	weightVolume.reinitialize(mask.xsize(), mask.ysize(), mask.zsize(), 0, true);
    weightVolume.copyproperties(mask);
	int i = 0;
	for(int z=0;z < mask.zsize();z++)
	   for(int y=0;y < mask.ysize();y++)
		  for(int x=0;x < mask.xsize();x++)
			 if (mask.value(x,y,z) > minValue)
			 {
				 weightVolume.value(x,y,z) = (float) weightVector[i];
				 i++;
			 }
			 else weightVolume.value(x,y,z) = (float) 0.0;
}
void vega::data::hexagonal_prismatic_lattice::fill_volume_cell( volume& v, const prismatic_hexagon_node & node )
{
    static const int hex_pixel_offset[8][2] = { {1, 0}, {2, 0}, {0, 1}, {1, 1}, {2, 1}, {3, 1}, {1, 2}, {2, 2}};

    math::vector3d vertex = node.get_vertex();

    for(size_t h=0;h<8;++h)
    {
        math::vector3d pixel;
        int xx = (int)vertex.x + hex_pixel_offset[h][0];
        int yy = (int)vertex.y + hex_pixel_offset[h][1];
        int zz = (int)vertex.z;
        if( xx >= 0 && yy >= 0 && zz >= 0 && xx < v.get_width() && yy < v.get_height() && zz < v.get_depth() )
        {
#ifndef USE_COLOR_MAP
            v.set_voxel(xx, yy, zz, (voxel)(node.density * 255.f));
#else
            v.set_voxel(xx, yy, zz, (voxel)(node.color.A));
#endif
        }
    }
}
void basisfield::AsVolume(volume<float>& vol, FieldIndex fi)
{
  if (int(FieldSz_x()) != vol.xsize() || int(FieldSz_y()) != vol.ysize() || int(FieldSz_z()) != vol.zsize()) {
    throw BasisfieldException("basisfield::AsVolume:: Matrix size mismatch beween field and volume");
  }
  if (Vxs_x() != vol.xdim() || Vxs_y() != vol.ydim() || Vxs_z() != vol.zdim()) {
    throw BasisfieldException("basisfield::AsVolume:: Voxel size mismatch beween field and volume");
  }
  if (!coef) {throw BasisfieldException("basisfield::AsVolume: Coefficients undefined");}

  if (!UpToDate(fi)) {Update(fi);}

  const boost::shared_ptr<NEWMAT::ColumnVector> tmptr = Get(fi);
  int vindx=0;
  for (unsigned int k=0; k<FieldSz_z(); k++) {
    for (unsigned int j=0; j<FieldSz_y(); j++) {
      for (unsigned int i=0; i<FieldSz_x(); i++) {
        vol(i,j,k) = tmptr->element(vindx++);
      }
    }
  }
}
void basisfield::Set(const volume<float>& pfield)
{
  if (int(FieldSz_x()) != pfield.xsize() || int(FieldSz_y()) != pfield.ysize() || int(FieldSz_z()) != pfield.zsize()) {
    throw BasisfieldException("basisfield::Set:: Matrix size mismatch beween basisfield class and supplied field");
  }
  if (Vxs_x() != pfield.xdim() || Vxs_y() != pfield.ydim() || Vxs_z() != pfield.zdim()) {
    throw BasisfieldException("basisfield::Set:: Voxel size mismatch beween basisfield class and supplied field");
  }

  volume<float>   volume_of_ones(pfield.xsize(),pfield.ysize(),pfield.zsize());
  volume_of_ones.copyproperties(pfield);
  volume_of_ones = 1.0;

  double lambda = 0.001;
  ColumnVector y = Jte(pfield,0);
  boost::shared_ptr<MISCMATHS::BFMatrix>  XtX = JtJ(volume_of_ones);
  boost::shared_ptr<MISCMATHS::BFMatrix>  BeEn = BendEnergyHess();
  XtX->AddToMe(*BeEn,lambda);
  ColumnVector coef_roof = XtX->SolveForx(y,SYM_POSDEF,1e-6,500);
  SetCoef(coef_roof);
}
示例#16
0
// returns in `output` the best voxels of `region`
void RegionExtraction::regionBestVoxels(RoiMeanCalculation &reference, volume<float>&values, volume<float>&output, int region, int regionSize, float percentage)
{
   vector<roiPoint> roi;
   roi.resize(regionSize);
   greaterRoiPoint greaterFirst;
   int index=0;
   
   // Filter the voxels of the region `region`
   for(int z=0;z<values.zsize();z++)
      for(int y=0;y<values.ysize();y++)
         for(int x=0;x<values.xsize();x++)
         {
            // get the voxel intensity in reference
            int voxelRegion = (int) reference.voxelValues(x,y,z);
            
            // if is the chosen region, records the voxel values (T values or other voxel value)
            if (region == voxelRegion)
            {
               roi[index].value = values.value(x,y,z);
               roi[index].roiValue = region;
               
               roi[index].x=x;
               roi[index].y=y;
               roi[index].z=z;
               index++;
            }
            else values.value(x,y,z)=(float)0.0;
         }
   
   // sorts the vector of values in descending order
   std::sort(roi.begin(), roi.end(), greaterFirst);
   
   // calculates the cut Index. Remember the voxels descending order
   int cutIndex = (int) (roi.size() * percentage + 0.5);
   
   // recording the result in `output`
   for (int j=0; j<=cutIndex;j++)
   {
      output.value(roi[j].x, roi[j].y, roi[j].z) = roi[j].roiValue;
   }
}
示例#17
0
文件: integrate.cpp 项目: LeiDai/meep
static double correct_integral(const volume &v,
			       const linear_integrand_data &data)
{
  direction x = data.dx, y = data.dy, z = data.dz;
  double x1 = v.in_direction_min(x);
  double x2 = v.in_direction_max(x);
  double y1 = v.in_direction_min(y);
  double y2 = v.in_direction_max(y);
  double z1 = v.in_direction_min(z);
  double z2 = v.in_direction_max(z);

  return (data.c * integral1(x1,x2,x) * integral1(y1,y2,y) * integral1(z1,z2,z)
       + data.ax * integralx(x1,x2,x) * integral1(y1,y2,y) * integral1(z1,z2,z)
       + data.ay * integral1(x1,x2,x) * integralx(y1,y2,y) * integral1(z1,z2,z)
       + data.az * integral1(x1,x2,x) * integral1(y1,y2,y) * integralx(z1,z2,z)
      + data.axy * integralx(x1,x2,x) * integralx(y1,y2,y) * integral1(z1,z2,z)
      + data.ayz * integral1(x1,x2,x) * integralx(y1,y2,y) * integralx(z1,z2,z)
      + data.axz * integralx(x1,x2,x) * integral1(y1,y2,y) * integralx(z1,z2,z)
     + data.axyz * integralx(x1,x2,x) * integralx(y1,y2,y) * integralx(z1,z2,z)
	  );
}
示例#18
0
vector<double> t1only_co_ext(const volume<float> & t1, const Pt & point, const Vec & n) {
  vector<double> resul;
  resul.clear();
  bool output = true; 
  bool alloutput = true;
  const double INNER_DEPTH = 3;
  const double OUTER_DEPTH = 60;
  
  Profile pt1;
  for (double d = -INNER_DEPTH; d < OUTER_DEPTH; d+=.5)
    {
      Pt c = point + d * n;
      double tmp1 = t1.interpolate(c.X, c.Y, c.Z);
      pt1.add (d, tmp1);
    }
  pt1.init_roi();

  //outer skin

  double outskin = pt1.last_point_over(pt1.end(), .2);
  double check = pt1.last_point_over(outskin - 1.5, .2);
  if (outskin - check > 2) outskin = check;

  const double OUTER_SKIN = outskin;  

  pt1.set_rroi(OUTER_SKIN);

  double inskull = pt1.next_point_under(pt1.begin(), .25);

  pt1.set_lroi(inskull);

  if (alloutput)
    {
      //outer skull
      
      //starting from the skin
      double outskull2 = 0;
      outskull2 = pt1.last_point_over(outskin, .75); 

      outskull2 = pt1.last_point_under(outskull2, .20);

      //starting from the brain
      double minabs = pt1.next_point_under(pt1.begin(), .30);
      if (minabs == -500) output = false;
      minabs = Max(minabs, -INNER_DEPTH);

      double localminabs = minabs;//0
      if (output)
	{
	  bool stop = false;

	  const double lowthreshold = pt1.threshold(.15);

	  const double upthreshold = pt1.threshold(.60);
	  int test = 0;
	  for (vector<pro_pair>::const_iterator i = pt1.v.begin(); i != pt1.v.end(); i++)
	    {
	      if (!stop && (*i).abs>=minabs && i!=pt1.v.end() && i!=pt1.v.begin())
		{
		  if ((*i).val>upthreshold) stop = true; //avoid climbing skin
		  if ((*i).val>lowthreshold) test++;
		  if ((*i).val<lowthreshold) test--;
		  if (test < 0) test=0;
		  if (test == 12) {stop = true;}
		  if ((*i).val<lowthreshold) 
		    {
		      localminabs = (*i).abs;
		    }
		}
	    }
	}

      double outskull = pt1.next_point_over(localminabs, .15);//.20
      
      if (outskull2 - outskull < -2 || outskull2 - outskull >= 2) {output = false;}
      
      if (outskin - outskull2 < 2) output = false;
      
      if (output) 
	{
	  resul.push_back(inskull);
	  resul.push_back(outskull2);
	  resul.push_back(outskin);
	}
      else resul.push_back(outskin);
    }
  
  return resul;
}
示例#19
0
//writes externall skull computed from image on output.
void t1only_write_ext_skull(volume<float> & output_inskull, volume<float> & output_outskull, volume<float> & output_outskin, const volume<float> & t1, const Mesh & m, const trMatrix & M) {
  int glob_counter = 0;
  int rem_counter = 0;

  const double xdim = t1.xdim();
  const double ydim = t1.ydim();
  const double zdim = t1.zdim();

  double imax = t1.max();
  if (imax == 0) imax = 1;

  volume<short> meshimage;
  copyconvert(t1, meshimage);
  meshimage = 0;
  draw_mesh(meshimage, m);

  for (vector<Mpoint*>::const_iterator i = m._points.begin(); i != m._points.end(); i++)
    {
      (*i)->data.clear();

      double max_neighbour = 0;
      const Vec normal = (*i)->local_normal();
      const Vec n = Vec(normal.X/xdim, normal.Y/ydim, normal.Z/zdim);      
      
      for (list<Mpoint*>::const_iterator nei = (*i)->_neighbours.begin(); nei != (*i)->_neighbours.end(); nei++)
	max_neighbour = Max(((**i) - (**nei)).norm(), max_neighbour); 
      
      max_neighbour = ceil((max_neighbour)/2);
      
      const Pt mpoint((*i)->get_coord().X/xdim,(*i)->get_coord().Y/ydim,(*i)->get_coord().Z/zdim);
      for (int ck = (int)floor(mpoint.Z - max_neighbour/zdim); ck <= (int)floor(mpoint.Z + max_neighbour/zdim); ck++)
	for (int cj = (int)floor(mpoint.Y - max_neighbour/ydim); cj <= (int)floor(mpoint.Y + max_neighbour/ydim); cj++)
	  for (int ci = (int)floor(mpoint.X - max_neighbour/xdim); ci <= (int)floor(mpoint.X + max_neighbour/xdim); ci++)
	    {
	      bool compute = false;
	      const Pt point(ci, cj, ck);
	      const Pt realpoint(ci*xdim, cj*ydim, ck*zdim);
	      if (meshimage(ci, cj, ck) == 1) 
		{
		  double mindist = 10000;
		  for (list<Mpoint*>::const_iterator nei = (*i)->_neighbours.begin(); nei != (*i)->_neighbours.end(); nei++)
		    mindist = Min(((realpoint) - (**nei)).norm(), mindist); 
		  if (mindist >= ((realpoint) - (**i)).norm()) compute = true;
		}
	    

	      if (compute)
		{
		  glob_counter ++;
		  vector<double> val;
		  if (!special_case(realpoint, normal, M))
		    val = t1only_co_ext(t1, point, n);
		  else
		    {
		      val = t1only_special_extract(t1, point, n);
		    }

		  if (val.size() == 3)
		    {
		      Pt opoint(point.X, point.Y, point.Z); 
		      Vec on(n.X, n.Y, n.Z); 
		      Pt c0 = opoint + val[0]*on;
		      Pt c1 = opoint + val[1]*on;
		      Pt c2 = opoint + val[2]*on;

		      output_inskull((int)floor(c0.X + .5) + infxm,(int) floor(c0.Y + .5) + infym,(int) floor(c0.Z + .5) + infzm) +=1; 
		      output_outskull((int)floor(c1.X + .5) + infxm,(int) floor(c1.Y + .5) + infym,(int) floor(c1.Z + .5) + infzm)+=1; 
		      output_outskin((int)floor(c2.X + .5) + infxm,(int) floor(c2.Y + .5) + infym,(int) floor(c2.Z + .5) + infzm) +=1; 
		    }
		  else {
		    rem_counter++;

		    if (val.size()==1)
		      {
			Pt opoint(point.X, point.Y, point.Z); 
			Vec on(n.X, n.Y, n.Z); 
			Pt c0 = opoint + val[0]*on;
			
			output_outskin((int)floor(c0.X + .5) + infxm,(int) floor(c0.Y + .5) + infym,(int) floor(c0.Z + .5) + infzm) +=1; 
		      }
		  }
		}      
	    }
    }
  if (verbose.value())
    {
      cout<<" nb of profiles : "<<glob_counter<<endl;
      cout<<" removed profiles : "<<100. * rem_counter/(double) glob_counter<<"%"<<endl;
    }
}
示例#20
0
double standard_step_of_computation(const volume<float> & image, Mesh & m, const int iteration_number, const double E,const double F, const float addsmooth, const float speed, const int nb_iter, const int id, const int od, const bool vol, const volume<short> & mask){
  double xdim = image.xdim();
  double ydim = image.ydim();
  double zdim = image.zdim();
  
  if (nb_iter % 50 == 0)
    {
      double l2 = 0;
      int counter = 0;
      for (vector<Mpoint*>::iterator i = m._points.begin(); i!=m._points.end(); i++ )
	{
	  counter++;
	  l2 += (*i)->medium_distance_of_neighbours();
	}
      l = l2/counter;
    }
  if (nb_iter % 100 == 0)
    {
      for (vector<Mpoint*>::iterator i = m._points.begin(); i!=m._points.end(); i++)
	{
	  Vec n = (*i)->local_normal();
	  Pt point = (*i)->get_coord();
	  Pt ipoint(point.X/xdim, point.Y/ydim, point.Z/zdim);
	  Vec in(n.X/xdim, n.Y/ydim, n.Z/zdim);
	  double max = 0;
	  Pt c_m1 = ipoint + (-1) * in;
	  double current = image.interpolate((c_m1.X),(c_m1.Y),(c_m1.Z));
	  for (double i2 = 1; i2 < 150; i2+=2)
	    {
	      if (max > .1) break;
	      Pt c_p = ipoint + i2 * in;
	      double tmpp = image.interpolate((c_p.X),(c_p.Y),(c_p.Z));
	      double tmp = (tmpp - current) * 100;
	      max = Max(max, tmp);
	      current = tmpp;
	      if (tmpp > .1) {max = 1; break;}
	    }

	  if (max < .1)
	    {   
              //There is a problem here for precision mode, since with the copy, no guarantee that data is non-zero size
              //even if mesh.cpp operator = is modified to copy data, after retesselate "new" points will have zero size data member
	      if ( (*i)->data.size() ) (*i)->data.pop_back();
	      (*i)->data.push_back(1);
	    }
	  else
	    {
	      if ( (*i)->data.size() ) (*i)->data.pop_back();
	      (*i)->data.push_back(0);
	    }
	}
    }

  for (vector<Mpoint*>::iterator i = m._points.begin(); i!=m._points.end(); i++)
    {
      Vec sn, st, u1, u2, u3, u;
      double f2, f3=0;
      
      Vec n = (*i)->local_normal();
      Vec dv = (*i)->difference_vector();
      
      double tmp = dv|n;
      sn = n * tmp;
      st = dv - sn;
      
      u1 = st*.5;
      
      double rinv = (2 * fabs(sn|n))/(l*l);
      
      f2 = (1+tanh(F*(rinv - E)))*0.5;
      
      u2 = f2 * sn * addsmooth;
      
      if ((*i)->data.back() == 0)
	{
	  //main term of skull_extraction
	  {
	    Pt point = (*i)->get_coord();
	    Pt ipoint(point.X/xdim, point.Y/ydim, point.Z/zdim);
	    Vec in(n.X/xdim, n.Y/ydim, n.Z/zdim);
	    
	    Pt c_m = ipoint + (-1.) * in;
	    Pt c_p = ipoint + 1. * in;
	    
	    double tmp = image.interpolate((c_p.X ),( c_p.Y),(c_p.Z));
	    double gradient = tmp - image.interpolate((c_m.X),(c_m.Y), (c_m.Z));
	    
	    double tmp2 = gradient*100;
	    f3 = max(-1., min(tmp2, 1.));
	    if (tmp2 >= 0 && tmp2 < .1 && tmp < .1 ) f3 = speed;
	    
	    if (vol) 
	      {
		double tmpvol = mask.interpolate((ipoint.X ),(ipoint.Y),(ipoint.Z));
		if (tmpvol > .0)
		  {
		    f3 = Max(Max(tmpvol*.5, .1), f3); 
		    f2 = 0;
		  }
	      }
	    
	    
	  }
	}
      else 
	{
	  f3 = 0;
	  Pt point = (*i)->get_coord();
	  Pt ipoint(point.X/xdim, point.Y/ydim, point.Z/zdim);
	  double tmpvol = mask.interpolate((ipoint.X ),(ipoint.Y),(ipoint.Z));
	  if (tmpvol > .0)
	    {
	      f3 = Max(tmpvol*.5, .1); 
	      f2 = 0;
	    }
	}

      u3 = .05 * f3 * n;
      
      u = u1 + u2 + u3;
      
      (*i)->_update_coord = (*i)->get_coord() + u;
    }

  m.update();
  
  return (0); 
}
示例#21
0
文件: bet2.cpp 项目: dungttbk/sips
bet_parameters adjust_initial_mesh(const volume<float> & image, Mesh& m, const double & rad = 0., const double xpara=0.,  const double ypara=0.,  const double zpara=0.)
{
  bet_parameters bp;
  double xdim = image.xdim();
  double ydim = image.ydim();
  double zdim = image.zdim();
  double t2, t98, t;

  //computing t2 && t98
  //  cout<<"computing robust min && max begins"<<endl;

  bp.min = image.min();
  bp.max = image.max();

  t2 = image.robustmin();
  t98 = image.robustmax();
  //t2=32.;
  //t98=16121.;
  
  //  cout<<"computing robust min && max ends"<<endl;
  
  t = t2 + .1*(t98 - t2);
  bp.t98 = t98;
  bp.t2 = t2;
  bp.t = t;
  //  cout<<"t2 "<<t2<<" t98 "<<t98<<" t "<<t<<endl;
  
  //  cout<<"computing center && radius begins"<<endl;
  
  //finds the COG
  Pt center(0, 0, 0);
  double counter = 0;
  if (xpara == 0. & ypara==0. & zpara==0.)
    {
      double tmp = t - t2;
      for (int k=0; k<image.zsize(); k++)
	for (int j=0; j<image.ysize(); j++)
	  for (int i=0; i<image.xsize(); i++)
	    {
	      double c = image(i, j, k ) - t2;
	      if (c > tmp)
		{
		  c = min(c, t98 - t2);   
		  counter+=c;
		  center +=  Pt(c*i*xdim, c*j*ydim, c*k*zdim);
		}
	    }
      center=Pt(center.X/counter, center.Y/counter, center.Z/counter);
      //cout<<counter<<endl;
      //  cout<<"cog "<<center.X<<" "<<center.Y<<" "<<center.Z<<endl;
    }
  else center=Pt(xpara, ypara, zpara);
  
  bp.cog = center;

  if (rad == 0.)
    {
      double radius=0;
      counter=0;
      double scale=xdim*ydim*zdim;
      for (int k=0; k<image.zsize(); k++)
	for (int j=0; j<image.ysize(); j++)
	  for (int i=0; i<image.xsize(); i++)
	    {
	      double c = image(i, j, k);
	      if (c > t)
		{
		  counter+=1;
		}
	    }
      radius = pow (.75 * counter*scale/M_PI, 1.0/3.0);
      //      cout<<radius<<endl;
      bp.radius = radius;
    } 
  else (bp.radius = rad);

  m.translation(center.X, center.Y, center.Z);
  m.rescale (bp.radius/2, center);

  //  cout<<"computing center && radius ends"<<endl;

  //computing tm
  //  cout<<"computing tm begins"<<endl;
  vector<double> vm;
  for (int k=0; k<image.zsize(); k++)
    for (int j=0; j<image.ysize(); j++)
      for (int i=0; i<image.xsize(); i++)
	{
	  double d = image.value(i, j, k);
	  Pt p(i*xdim, j*ydim, k*zdim);
	  if (d > t2 && d < t98 && ((p - center)|(p - center)) < bp.radius * bp.radius)
	    vm.push_back(d);
	}

  int med = (int) floor(vm.size()/2.);
  //  cout<<"before sort"<<endl;
  nth_element(vm.begin(), vm.begin() + med - 1, vm.end());
  //partial_sort(vm.begin(), vm.begin() + med + 1, vm.end());
  //double tm = vm[med];
  double tm=(*max_element(vm.begin(), vm.begin() + med));
  //  cout<<"tm "<<tm<<endl;
  bp.tm = tm;
  //  cout<<"computing tm ends"<<endl;
  
  return bp;
}
示例#22
0
文件: bet2.cpp 项目: dungttbk/sips
double step_of_computation(const volume<float> & image, Mesh & m, const double bet_main_parameter, const int pass, const double increase_smoothing, const int iteration_number, double & l, const double t2, const double tm, const double t, const double E,const double F, const double zcog, const double radius, const double local_th=0., const int d1=7, const int d2=3){
  double xdim = image.xdim();
  double ydim = image.ydim();
  double zdim = image.zdim();
  
  if (iteration_number==50 || iteration_number%100 == 0 )
    {
      l = 0;
      int counter = 0;
      for (vector<Mpoint*>::iterator i = m._points.begin(); i!=m._points.end(); i++ )
	{
	  counter++;
	  l += (*i)->medium_distance_of_neighbours();
	}
      l/=counter;
    }
  
  for (vector<Mpoint*>::iterator i = m._points.begin(); i!=m._points.end(); i++)
    {
      Vec sn, st, u1, u2, u3, u;
      double f2, f3=0;
      
      Vec n = (*i)->local_normal();
      Vec dv = (*i)->difference_vector();
      
      double tmp = dv|n;
      sn = n * tmp;
      st = dv - sn;
      
      u1 = st*.5;
      
      double rinv = (2 * fabs(sn|n))/(l*l);
      
      f2 = (1+tanh(F*(rinv - E)))*0.5;
      if (pass > 0)
	if (tmp > 0) {
	  f2*=increase_smoothing;
	  f2 = Min(f2, 1.);
	}
      
      u2 = f2 * sn;
      
      //main term of bet
      {
	double local_t = bet_main_parameter;
	if (local_th != 0.0)
	  {
	    local_t = Min(1., Max(0., bet_main_parameter + local_th*((*i)->get_coord().Z - zcog)/radius));
	  }
	
	double Imin = tm;
	double Imax = t;
	
	Pt p = (*i)->get_coord() + (-1)*n;
	double iv = p.X/xdim + .5, jv = p.Y/ydim +.5, kv = p.Z/zdim +.5; 
	if (image.in_bounds((int)iv,(int) jv,(int) kv))
	  {	
	    double im=image.value((int)iv,(int)jv,(int)kv);
	    Imin = Min(Imin, im);
	    Imax = Max(Imax,im);
	    
	    double nxv=n.X/xdim, nyv=n.Y/ydim, nzv=n.Z/zdim;
	    int i2=(int)(iv-(d1-1)*nxv), j2 =(int) (jv-(d1-1)*nyv), k2 =(int)(kv-(d1-1)*nzv); 
	    if (image.in_bounds(i2, j2, k2))
	      {	
		im=image.value(i2,j2,k2);
		Imin = Min(Imin, im);
		
		for (int gi=2; gi<d1; gi++)
		  {
		    // the following is a quick calc of Pt p = (*i)->get_coord() + (-gi)*n;
		    iv-=nxv; jv-=nyv; kv-=nzv;
		    im = image.value((int) (iv), (int) (jv), (int) (kv));
		    Imin = Min(Imin, im);
		
		    if (gi<d2)
		      Imax = Max(Imax,im);
		  }
		
		Imin = Max (t2, Imin);
		Imax = Min (tm, Imax);	
		
		const double tl = (Imax - t2) * local_t + t2;
		
		if (Imax - t2 > 0)
		  f3=2*(Imin - tl)/(Imax - t2);
		else f3=(Imin - tl)*2;
	      }
	  }
	
      }
      
      f3 *= (normal_max_update_fraction * lambda_fit * l);
      
      u3 = f3 * n;
      
      u = u1 + u2 + u3;
            
      //cout<<"l "<<l<<"u1 "<<((u1*n).norm())<<"u2 "<<(u2|n)<<"u3 "<<(u3|n)<<endl;
      
      (*i)->_update_coord = (*i)->get_coord() + u;
    }

  m.update();
  
  return (0); 
}
示例#23
0
文件: bet2.cpp 项目: dungttbk/sips
volume<float> find_skull (volume<float> & image, const Mesh & m, const double t2, double t, double t98)
{ 
  const double skull_search = 30;
  const double skull_start = -3;
  
  volume<float> result = image;
  result=0;

  volume<short> volmesh;
  copyconvert(image,volmesh);  
  int xsize = volmesh.xsize();
  int ysize = volmesh.ysize();
  int zsize = volmesh.zsize();  
  double xdim = volmesh.xdim();
  double ydim = volmesh.ydim();
  double zdim = volmesh.zdim();  
  double scale = Min(xdim, Min(ydim, zdim)); 
  volmesh = 1;
  volmesh = draw_mesh(volmesh, m);
  
  image.setinterpolationmethod(trilinear);

  for (vector<Mpoint*>::const_iterator i = m._points.begin(); i != m._points.end(); i++)
    {
      double max_neighbour = 0;
      const Vec normal = (*i)->local_normal();
      const Vec n = Vec(normal.X/xdim, normal.Y/ydim, normal.Z/zdim);      

      for (list<Mpoint*>::const_iterator nei = (*i)->_neighbours.begin(); nei != (*i)->_neighbours.end(); nei++)
	max_neighbour = Max(((**i) - (**nei)).norm(), max_neighbour); 

      max_neighbour = ceil((max_neighbour)/2);

      const Pt mpoint((*i)->get_coord().X/xdim,(*i)->get_coord().Y/ydim,(*i)->get_coord().Z/zdim);
      for (int ck = (int)floor(mpoint.Z - max_neighbour/zdim); ck <= (int)floor(mpoint.Z + max_neighbour/zdim); ck++)
	for (int cj = (int)floor(mpoint.Y - max_neighbour/ydim); cj <= (int)floor(mpoint.Y + max_neighbour/ydim); cj++)
	  for (int ci = (int)floor(mpoint.X - max_neighbour/xdim); ci <= (int)floor(mpoint.X + max_neighbour/xdim); ci++)
	    {
	      bool compute = false;
	      const Pt point(ci, cj, ck);
	      const Pt realpoint(ci*xdim, cj*ydim, ck*zdim);
	      if (volmesh(ci, cj, ck) == 0) 
		{
		  double mindist = 10000;
		  for (list<Mpoint*>::const_iterator nei = (*i)->_neighbours.begin(); nei != (*i)->_neighbours.end(); nei++)
		    mindist = Min(((realpoint) - (**nei)).norm(), mindist); 
		  if (mindist >= ((realpoint) - (**i)).norm()) compute = true;
		}
	    

	      if (compute)
		{
		  double maxval = t;
		  double minval = image.interpolate(point.X, point.Y, point.Z);
		  double d_max = 0;
		  
		  for (double d=0; d<skull_search; d+=scale*.5)
		    {
		      Pt current = point + d * n;
		      double val = image.interpolate(current.X, current.Y, current.Z);
		      if (val>maxval)
			{
			  maxval=val;
			  d_max=d;
			}
		      
		      if (val<minval)
			minval=val;
		    }
		  
		  if (maxval > t)
		    {
		      double d_min=skull_start;
		      double maxJ =-1000000;
		      double lastJ=-2000000;
		      for(double d=skull_start; d<d_max; d+=scale*0.5)
			{
			  Pt current = point + d * n;
			  if (current.X >= 0 && current.Y >= 0 && current.Z >= 0 && current.X<xsize && current.Y<ysize && current.Z<zsize)
			    {
			      double tmpf = d/30 - image.interpolate(current.X, current.Y, current.Z) / (t98 - t2);
			      if (tmpf > maxJ)
				{
				  maxJ=tmpf;
				  d_min = d;
				}
			      lastJ=tmpf;
			    }
			}
		      double maxgrad = 0;
		      double d_skull;
		      Pt current2 = point + d_min * n;
		      if (current2.X >= 0 && current2.Y >= 0 && current2.Z >= 0 && current2.X<xsize && current2.Y<ysize && current2.Z<zsize)
			{
			  double val2 = image.interpolate(current2.X, current2.Y, current2.Z);
			  for(double d=d_min + scale; d<d_max; d+=0.5*scale)
			    {
			      Pt current = point + d * n;
			      if (current.X >= 0 && current.Y >= 0 && current.Z >= 0 && current.X<xsize && current.Y<ysize && current.Z<zsize)
				{
				  double val = image.interpolate(current.X, current.Y, current.Z);
				  double grad = val - val2;
				  val2 = val;
				  if (grad > 0)
				    {
				      if (grad > maxgrad)
					{
					  maxgrad=grad;
					  d_skull=d;
					}
				      else d = d_max;
				    }
				}
			    }
			}
		      if (maxgrad > 0)
			{
			  Pt current3 = point + d_skull * n;
			  if (current3.X >= 0 && current3.Y >= 0 && current3.Z >= 0 && current3.X<xsize && current3.Y<ysize && current3.Z<zsize)
			    result ((int)current3.X, (int)current3.Y, (int)current3.Z) = 100/*max*/;
			}
		    }
		}
	    }
    }
  return result;
}
示例#24
0
void FnirtFileWriter::common_field_construction(const string&            fname,
                                                const volume<float>&     ref,
                                                const volume<float>&     fieldx,
                                                const volume<float>&     fieldy,
                                                const volume<float>&     fieldz, 
                                                const Matrix&            aff)
{
  volume4D<float>   fields(ref.xsize(),ref.ysize(),ref.zsize(),3);
  fields.copyproperties(ref); 

  Matrix M;
  bool   add_affine = false;
  if (add_affine = ((aff-IdentityMatrix(4)).MaximumAbsoluteValue() > 1e-6)) { // Add affine part to fields
    M = (aff.i() - IdentityMatrix(4))*ref.sampling_mat();
  }

  if (samesize(ref,fieldx,true)) { // If ref is same size as the original field
    fields[0] = fieldx; fields[1] = fieldy; fields[2] = fieldz;
    fields.copyproperties(ref);    // Put qform/sform and stuff back.
    if (add_affine) {
      ColumnVector xv(4), xo(4);
      int zs = ref.zsize(), ys = ref.ysize(), xs = ref.xsize();
      xv(4) = 1.0;
      for (int z=0; z<zs; z++) {
        xv(3) = double(z);
        for (int y=0; y<ys; y++) {
          xv(2) = double(y);
          for (int x=0; x<xs; x++) {
            xv(1) = double(x);
            xo = M*xv;
            fields(x,y,z,0) += xo(1);
            fields(x,y,z,1) += xo(2);
            fields(x,y,z,2) += xo(3);
	  }
        }
      }
    } 
  }
  else {
    fieldx.setextrapolationmethod(extraslice);
    fieldy.setextrapolationmethod(extraslice);
    fieldz.setextrapolationmethod(extraslice);
    Matrix R2F = fieldx.sampling_mat().i() * ref.sampling_mat();
    ColumnVector xv(4), xo(4), xr(4);
    int zs = ref.zsize(), ys = ref.ysize(), xs = ref.xsize();
    xv(4) = 1.0;
    for (int z=0; z<zs; z++) {
      xv(3) = double(z);
      for (int y=0; y<ys; y++) {
        xv(2) = double(y);
        for (int x=0; x<xs; x++) {
          xv(1) = double(x);
          xr = R2F*xv;
          fields(x,y,z,0) = fieldx.interpolate(xr(1),xr(2),xr(3));
          fields(x,y,z,1) = fieldy.interpolate(xr(1),xr(2),xr(3));
          fields(x,y,z,2) = fieldz.interpolate(xr(1),xr(2),xr(3));
          if (add_affine) {
            xo = M*xv;
            fields(x,y,z,0) += xo(1);
            fields(x,y,z,1) += xo(2);
            fields(x,y,z,2) += xo(3);
	  }
        }
      }
    }
  }

  fields.set_intent(FSL_FNIRT_DISPLACEMENT_FIELD,fields.intent_param(0),fields.intent_param(1),fields.intent_param(2));
  fields.setDisplayMaximum(0.0);
  fields.setDisplayMinimum(0.0);

  // Save resulting field
  save_volume4D(fields,fname);
}
示例#25
0
void volume::inset(double x_inset, double y_inset, double z_inset, volume& dst) const
{
	dst = *this;
	dst.inset(x_inset, y_inset, z_inset);
}
vega::data::hexagonal_prismatic_lattice::hexagonal_prismatic_lattice( const volume& v )
{
    VEGA_LOG_FN;

    // Lattice L = {Lx, Ly, Lz};
    static const int Lx[3] = {2, -1, 0};
    static const int Ly[3] = {0, 2, 0};
    static const int Lz[3] = {0, 0, 1};

    myWidth = v.get_width() / 2;
    myHeight = v.get_height() / 2;
    myDepth = v.get_depth();

    assert(myWidth > 0 && myHeight > 0 && myDepth > 0);

    myLatticeCells.reserve(myWidth * myHeight * myDepth);

    for(uint16 k=0;k<myDepth;++k)
    {
        for(uint16 i=0;i<myHeight;++i)
        {
            for(uint16 j=0;j<myWidth;++j)
            {
                prismatic_hexagon_node cell;

                cell.x = j;
                cell.y = i + j/2 + j%2;
                cell.z = k;


                static const int hex_neighbor_offset[NEIGHBOR_COUNT][3] = 
                { 
                               {1, 1, 0}, {0, 1, 0}, {-1, 0, 0}, {-1, -1, 0}, {0, -1, 0}, {1, 0, 0},
                    {0, 0,-1}, 
#if NEIGHBOR_COUNT==20
                               {1, 1,-1}, {0, 1,-1}, {-1, 0,-1}, {-1, -1,-1}, {0, -1,-1}, {1, 0,-1},
#endif
                    {0, 0, 1}, 
#if NEIGHBOR_COUNT==20                               
                               {1, 1, 1}, {0, 1, 1}, {-1, 0, 1}, {-1, -1, 1}, {0, -1, 1}, {1, 0, 1}
#endif
                };

                for(int h=0; h<NEIGHBOR_COUNT; ++h)
                {
                    int hj = cell.x + hex_neighbor_offset[h][0];
                    int hi = cell.y + hex_neighbor_offset[h][1] - hj/2 - hj%2;
                    int hk = cell.z + hex_neighbor_offset[h][2];

                    if( hi >= 0 && hi < myHeight && hj >= 0 && hj < myWidth && hk >=0 && hk < myDepth )
                        cell.hex[h] = hk * myWidth * myHeight + hi * myWidth + hj;
                    else
                        cell.hex[h] = -1;
                }

                // the hexagon pixel offsets from the upper left corner
                // 
                // x 1-2 o
                //  /   \
                // 3-4-5-6
                //  \   /
                // o 7-8 o
                //

                static const int hex_pixel_offset[8][2] = { {1, 0}, {2, 0}, {0, 1}, {1, 1}, {2, 1}, {3, 1}, {1, 2}, {2, 2}};
                
                math::vector3d vertex = cell.get_vertex();
#ifndef USE_COLOR_MAP
                cell.density = 0.f;
#else
                cell.color.RGBA = 0;
#endif

                // compute average density
                int k = 0;
                for(size_t h=0;h<8;++h)
                {
                    math::vector3d pixel;
                    int xx = (int)vertex.x + hex_pixel_offset[h][0];
                    int yy = (int)vertex.y + hex_pixel_offset[h][1];
                    int zz = (int)vertex.z;
                    if( xx >= 0 && yy >= 0 && zz >= 0 && xx < v.get_width() && yy < v.get_height() && zz < v.get_depth() )
                    {
#ifndef USE_COLOR_MAP                        
                        float vx = v.get_voxel(xx, yy, zz);
                        cell.density = (cell.density * k + vx) * (1.f/(++k));
#else
                        r8g8b8a8 vx = v.get_voxel_color(xx, yy, zz);
                        cell.color.A = (cell.color.A * k + vx.A) / ++k;
                        cell.color.R = (cell.color.R * k + vx.R) / ++k;
                        cell.color.G = (cell.color.G * k + vx.G) / ++k;
                        cell.color.B = (cell.color.B * k + vx.B) / ++k;
#endif
                    }
                }

                myLatticeCells.push_back(cell);
            }
        }

    }
}
示例#27
0
	void reflect_z(volume &dst) const { dst = *this; dst.reflect_z(); }
示例#28
0
/* default: simple numerical integration of surfaces/cubes, relative
   tolerance 'tol'.   This is superseded by the routines in the libctl
   interface, which either use a semi-analytical average or can
   use a proper adaptive cubature. */
void material_function::eff_chi1inv_row(component c, double chi1inv_row[3],
                                        const volume &v,
                                        double tol, int maxeval) {
    field_type ft = type(c);
    if (!maxeval) {
trivial:
        chi1inv_row[0] = chi1inv_row[1] = chi1inv_row[2] = 0.0;
        chi1inv_row[component_direction(c) % 3] = 1/chi1p1(ft,v.center());
        return;
    }

    vec gradient(normal_vector(ft, v));
    if (abs(gradient) < 1e-8) goto trivial;

    double meps=1, minveps=1;
    vec d = v.get_max_corner() - v.get_min_corner();
    int ms = 10;
    double old_meps=0, old_minveps=0;
    int iter = 0;
    switch(v.dim) {
    case D3:
        while ((fabs(meps - old_meps) > tol*fabs(old_meps)) && (fabs(minveps - old_minveps) > tol*fabs(old_minveps))) {
            old_meps=meps;
            old_minveps=minveps;
            meps = minveps = 0;
            for (int k=0; k < ms; k++)
                for (int j=0; j < ms; j++)
                    for (int i=0; i < ms; i++) {
                        double ep = chi1p1(ft,v.get_min_corner() + vec(i*d.x()/ms, j*d.y()/ms, k*d.z()/ms));
                        if (ep < 0) goto trivial;
                        meps += ep;
                        minveps += 1/ep;
                    }
            meps /= ms*ms*ms;
            minveps /= ms*ms*ms;
            ms *= 2;
            if (maxeval && (iter += ms*ms*ms) >= maxeval) goto done;
        }
        break;
    case D2:
        while ((fabs(meps-old_meps) > tol*old_meps) && (fabs(minveps-old_minveps) > tol*old_minveps)) {
            old_meps=meps;
            old_minveps=minveps;
            meps = minveps = 0;
            for (int j=0; j < ms; j++)
                for (int i=0; i < ms; i++) {
                    double ep = chi1p1(ft,v.get_min_corner() + vec(i*d.x()/ms, j*d.y()/ms));
                    if (ep < 0) goto trivial;
                    meps += ep;
                    minveps += 1/ep;
                }
            meps /= ms*ms;
            minveps /= ms*ms;
            ms *= 2;
            if (maxeval && (iter += ms*ms) >= maxeval) goto done;
        }
        break;
    case Dcyl:
        while ((fabs(meps-old_meps) > tol*old_meps) && (fabs(minveps-old_minveps) > tol*old_minveps)) {
            old_meps=meps;
            old_minveps=minveps;
            meps = minveps = 0;
            double sumvol = 0;
            for (int j=0; j < ms; j++)
                for (int i=0; i < ms; i++) {
                    double r = v.get_min_corner().r() + i*d.r()/ms;
                    double ep = chi1p1(ft,v.get_min_corner() + veccyl(i*d.r()/ms, j*d.z()/ms));
                    if (ep < 0) goto trivial;
                    sumvol += r;
                    meps += ep * r;
                    minveps += r/ep;
                }
            meps /= sumvol;
            minveps /= sumvol;
            ms *= 2;
            if (maxeval && (iter += ms*ms) >= maxeval) goto done;
        }
        break;
    case D1:
        while ((fabs(meps-old_meps) > tol*old_meps) && (fabs(minveps-old_minveps) > tol*old_minveps)) {
            old_meps=meps;
            old_minveps=minveps;
            meps = minveps = 0;
            for (int i=0; i < ms; i++) {
                double ep = chi1p1(ft,v.get_min_corner() + vec(i*d.z()/ms));
                if (ep < 0) {
                    meps = chi1p1(ft,v.center());
                    minveps = 1/meps;
                    goto done;
                }
                meps += ep;
                minveps += 1/ep;
            }
            meps /= ms;
            minveps /= ms;
            ms *= 2;
            if (maxeval && (iter += ms*ms) >= maxeval) goto done;
        }
        break;
    }

done:
    {
        double n[3] = {0,0,0};
        double nabsinv = 1.0/abs(gradient);
        LOOP_OVER_DIRECTIONS(gradient.dim, k)
        n[k%3] = gradient.in_direction(k) * nabsinv;

        /* get rownum'th row of effective tensor
           P * minveps + (I-P) * 1/meps = P * (minveps-1/meps) + I * 1/meps
           where I is the identity and P is the projection matrix
           P_{ij} = n[i] * n[j]. */
        int rownum = component_direction(c) % 3;
        for (int i=0; i<3; ++i)
            chi1inv_row[i] = n[rownum] * n[i] * (minveps - 1/meps);
        chi1inv_row[rownum] += 1/meps;
    }
}