Skip to content
Snippets Groups Projects
surface_norm.cc 4.57 KiB
Newer Older
/*  surface_norm.cc

    Mark Jenkinson, FMRIB Image Analysis Group

    Copyright (C) 2004 University of Oxford  */

/*  CCOPYRIGHT  */

// Calculates the surface normals for a mask, using a smoothed
//  gradient calculation (all non-surface points get zero ouput)

#define _GNU_SOURCE 1
#define POSIX_SOURCE 1

#include "newimage/newimageall.h"
#include "miscmaths/miscmaths.h"
#include "utils/options.h"

using namespace MISCMATHS;
using namespace NEWIMAGE;
using namespace Utilities;

// The two strings below specify the title and example usage that is
//  printed out as the help or usage message

string title="surface_norm (Version 1.0)\nCopyright(c) 2004, University of Oxford (Mark Jenkinson)";
string examples="surface_norm [options] -i <input mask image> -s <smoothing in mm> -o <output surface normal image>";

// Each (global) object below specificies as option and can be accessed
//  anywhere in this file (since they are global).  The order of the
//  arguments needed is: name(s) of option, default value, help message,
//       whether it is compulsory, whether it requires arguments
// Note that they must also be included in the main() function or they
//  will not be active.

Option<bool> verbose(string("-v,--verbose"), false, 
		     string("switch on diagnostic messages"), 
		     false, no_argument);
Option<bool> help(string("-h,--help"), false,
		  string("display this message"),
		  false, no_argument);
Option<float>  smoothing(string("-s"),3.0,
			 string("smoothing in mm (default is 3.0)"),
			 false, requires_argument);
Option<string> inname(string("-i"), string(""),
		      string("input mask filename"),
		      true, requires_argument);
Option<string> outname(string("-o"), string(""),
		       string("output surface normal filename"),
		       true, requires_argument);
int nonoptarg;

////////////////////////////////////////////////////////////////////////////

// Local functions

int do_work(int argc, char* argv[]) 
{
  volume<float> vin;
  volume4D<float> snorm;
  read_volume(vin,inname.value());

  // force input to be a binary mask
  vin.binarise(0.5);
  if (verbose.value()) print_info(vin,"vin");

  // smooth the mask volume and calculate the gradient
  if (verbose.value()) { cerr << "Performing smoothing" << endl; }
  { 
    volume<float> smoothv;
    smoothv = smooth(vin,smoothing.value());
    if (verbose.value()) print_info(smoothv,"smoothv");
    if (verbose.value()) { cerr << "Calculating the gradient" << endl; }
    gradient(smoothv,snorm);
  }

  if (verbose.value()) print_info(snorm,"snorm");

  bool atedge;
  if (verbose.value()) { cerr << "Normalising gradients" << endl; }
  // zero all non-surface values and normalise vectors at the surface
  for (int z=vin.minz(); z<=vin.maxz(); z++) {
    for (int y=vin.miny(); y<=vin.maxy(); y++) {
      for (int x=vin.minx(); x<=vin.maxx(); x++) {
	atedge = false;
	if ( (vin(x,y,z)>0.5) ) {
	  if (vin(x,y,z-1)<0.5) atedge=true;
	  else { 
	    if (vin(x,y-1,z)<0.5) atedge=true;
	    else { 
	      if (vin(x-1,y,z)<0.5) atedge=true;
	      else {
		if (vin(x+1,y,z)<0.5) atedge=true;
		else {
		  if (vin(x,y+1,z)<0.5) atedge=true;
		  else {
		    if (vin(x,y,z+1)<0.5) atedge=true;
		  }
		}
	      }
	    }
	  }
	}
	if (atedge) {
	  float norm;
	  norm = 1.0 / sqrt(Sqr(snorm(x,y,z,0)) + Sqr(snorm(x,y,z,1)) 
			    + Sqr(snorm(x,y,z,2)) );
	  snorm(x,y,z,0) *= norm;
	  snorm(x,y,z,1) *= norm;
	  snorm(x,y,z,2) *= norm;
	} else {
	  snorm(x,y,z,0) = 0.0;
	  snorm(x,y,z,1) = 0.0;
	  snorm(x,y,z,2) = 0.0;
	}
      }
    }
    if (verbose.value()) { cerr << "."; }
  }
  if (verbose.value()) { cerr << endl; }

  // save the results
  save_volume4D(snorm,outname.value());

  return 0;
}

////////////////////////////////////////////////////////////////////////////

int main(int argc,char *argv[])
{

  Tracer tr("main");
  OptionParser options(title, examples);

  try {
    // must include all wanted options here (the order determines how
    //  the help message is printed)
    options.add(inname);
    options.add(outname);
    options.add(smoothing);
    options.add(verbose);
    options.add(help);
    
    nonoptarg = options.parse_command_line(argc, argv);

    // line below stops the program if the help was requested or 
    //  a compulsory option was not set
    if ( (help.value()) || (!options.check_compulsory_arguments(true)) )
      {
	options.usage();
	exit(EXIT_FAILURE);
      }
    
  }  catch(X_OptionError& e) {
    options.usage();
    cerr << endl << e.what() << endl;
    exit(EXIT_FAILURE);
  } catch(std::exception &e) {
    cerr << e.what() << endl;
  } 

  // Call the local functions

  return do_work(argc,argv);
}