-
Mark Jenkinson authored
Hopefully fixed bugs in avwstats++, except -r and -R when -l and -u are used - but this is an old, existing bug
Mark Jenkinson authoredHopefully fixed bugs in avwstats++, except -r and -R when -l and -u are used - but this is an old, existing bug
fslstats.cc 12.06 KiB
/* avwstats++.cc
Mark Jenkinson, FMRIB Image Analysis Group
Copyright (C) 2003 University of Oxford */
/* CCOPYRIGHT */
// Like avwstats but better! :)
#include "miscmaths/miscmaths.h"
#include "newimage/newimageall.h"
#include "newimage/costfns.h"
using namespace NEWIMAGE;
using namespace MISCMATHS;
bool masks_used=false;
bool lthr_used=false;
bool uthr_used=false;
void print_usage(const string& progname) {
cout << "Usage: avwstats++ <input> [options]" << endl << endl;
cout << endl;
cout << "-l <lthresh> : set lower threshold" << endl;
cout << "-u <uthresh> : set upper threshold" << endl;
cout << "-r : output <robust min intensity> <robust max intensity>" << endl;
cout << "-R : output <min intensity> <max intensity>" << endl;
cout << "-e : output mean entropy ; mean(-i*ln(i))" << endl;
cout << "-E : output mean entropy (of nonzero voxels)" << endl;
cout << "-v : output <voxels> <volume>" << endl;
cout << "-V : output <voxels> <volume> (for nonzero voxels)" << endl;
cout << "-m : output mean" << endl;
cout << "-M : output mean (for nonzero voxels)" << endl;
cout << "-s : output standard deviation" << endl;
cout << "-S : output standard deviation (for nonzero voxels)" << endl;
cout << "-w : output smallest ROI <xmin> <xsize> <ymin> <ysize> <zmin> <zsize> <tmin> <tsize> containing nonzero voxels" << endl;
cout << "-x : output co-ordinates of maximum voxel" << endl;
cout << "-X : output co-ordinates of minimum voxel" << endl;
cout << "-c : output centre-of-gravity (cog) in mm coordinates" << endl;
cout << "-C : output centre-of-gravity (cog) in voxel coordinates" << endl;
cout << "-p <n> : output nth percentile (n between 0 and 100)" << endl;
cout << "-P <n> : output nth percentile (for nonzero voxels)" << endl;
cout << "-a : use absolute values of all image intensities"<< endl;
cout << "-k <mask> : use the specified image (filename) for masking - overrides lower and upper thresholds" << endl;
cout << endl;
cout << "Note - thresholds are not inclusive ie lthresh<allowed<uthresh" << endl;
}
// Some specialised nonzero functions just for speedup
// (it avoids generating masks when not absolutely necessary)
long int nonzerocount(const volume4D<float>& vol)
{
long int totn=0;
for (int t=vol.mint(); t<=vol.maxt(); t++) {
for (int z=vol.minz(); z<=vol.maxz(); z++) {
for (int y=vol.miny(); y<=vol.maxy(); y++) {
for (int x=vol.minx(); x<=vol.maxx(); x++) {
if (vol(x,y,z,t)!=0.0) {
totn++;
}
}
}
}
}
return totn;
}
double nonzeromean(const volume4D<float>& vol)
{
double totv=0.0;
long int totn=0;
for (int t=vol.mint(); t<=vol.maxt(); t++) {
for (int z=vol.minz(); z<=vol.maxz(); z++) {
for (int y=vol.miny(); y<=vol.maxy(); y++) {
for (int x=vol.minx(); x<=vol.maxx(); x++) {
if (vol(x,y,z,t)!=0.0) {
totv+=(double) vol(x,y,z,t);
totn++;
}
}
}
}
}
double meanval=0.0;
if (totn>0) {
meanval=totv/totn;
}
return meanval;
}
double nonzerostddev(const volume4D<float>& vol)
{
double totv=0.0, totvv=0.0;
long int totn=0;
for (int t=vol.mint(); t<=vol.maxt(); t++) {
for (int z=vol.minz(); z<=vol.maxz(); z++) {
for (int y=vol.miny(); y<=vol.maxy(); y++) {
for (int x=vol.minx(); x<=vol.maxx(); x++) {
if (vol(x,y,z,t)!=0.0) {
float v=vol(x,y,z,t);
totvv+=(double) v*v;
totv+=(double) v;
totn++;
}
}
}
}
}
double var=0.0;
if (totn>1) {
double meanval = totv/totn;
var = (totvv - totn*meanval*meanval)/(totn-1);
}
return std::sqrt(var);
}
int generate_masks(volume4D<float> &mask, volume4D<float> &masknz, const volume4D<float> &vin,
float& lthr, float& uthr)
{
if (!lthr_used) { lthr=vin.min()-1; }
if (!uthr_used) { uthr=vin.max()+1; }
mask = binarise(vin,lthr,uthr,exclusive);
masknz = mask * (1.0f - binarise(vin,0.0f, 0.0f));
return 0;
}
int generate_masks(const volume4D<float> &mask, volume4D<float> &masknz, const volume4D<float> &vin)
{
masknz = mask * (1.0f - binarise(vin,0.0f, 0.0f));
return 0;
}
int fmrib_main_float(int argc, char* argv[])
{
cout.setf(ios::dec);
cout.setf(ios::fixed, ios::floatfield);
cout.setf(ios::left, ios::adjustfield);
cout.precision(6);
volume4D<float> vin, vol, mask, masknz;
read_volume4D(vol,argv[1]);
float lthr=0, uthr=0; // these initial values are not used
if (masks_used) {
vin = vol;
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
}
int narg=2;
string sarg;
while (narg<argc) {
sarg=argv[narg];
if (sarg=="-m") {
if (masks_used) cout << vol.mean(mask) << " ";
else cout << vol.mean() << " ";
} else if (sarg=="-M") {
if (masks_used) cout << vol.mean(masknz) << " ";
else {
double nzmean=0;
nzmean = nonzeromean(vol);
cout << nzmean << " ";
}
} else if (sarg=="-X") {
if (masks_used) {
cout << vol.mincoordx(mask) << " " << vol.mincoordy(mask) << " "
<< vol.mincoordz(mask) << " ";
} else {
cout << vol.mincoordx() << " " << vol.mincoordy() << " "
<< vol.mincoordz() << " ";
}
} else if (sarg=="-x") {
if (masks_used) {
cout << vol.maxcoordx(mask) << " " << vol.maxcoordy(mask) << " "
<< vol.maxcoordz(mask) << " ";
} else {
cout << vol.maxcoordx() << " " << vol.maxcoordy() << " "
<< vol.maxcoordz() << " ";
}
} else if (sarg=="-w") {
if (!masks_used) {
if (vin.nvoxels()<1) { vin = vol; }
masks_used=true;
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
}
int xmin=masknz.maxx(),xmax=masknz.minx(),ymin=masknz.maxy(),ymax=masknz.miny(),zmin=masknz.maxz(),zmax=masknz.minz(),tmin=masknz.maxt(),tmax=masknz.mint();
for(int t=masknz.mint();t<=masknz.maxt();t++) {
for(int z=masknz.minz();z<=masknz.maxz();z++) {
for(int y=masknz.miny();y<=masknz.maxy();y++) {
for(int x=masknz.minx();x<=masknz.maxx();x++) {
if (masknz(x,y,z,t)>0.5) {
// if (masknz(x,y,z)>0.5) {
if (x<xmin) xmin=x;
if (x>xmax) xmax=x;
if (y<ymin) ymin=y;
if (y>ymax) ymax=y;
if (z<zmin) zmin=z;
if (z>zmax) zmax=z;
if (t<tmin) tmin=t;
if (t>tmax) tmax=t;
}
}
}
}
}
cout << xmin << " " << 1+xmax-xmin << " " << ymin << " " << 1+ymax-ymin << " " << zmin << " " << 1+zmax-zmin << " " << tmin << " " << 1+tmax-tmin << " ";
} else if (sarg=="-e") {
if (!masks_used) {
if (vin.nvoxels()<1) { vin = vol; }
masks_used=true;
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
}
ColumnVector hist;
int nbins=1000;
double entropy=0;
hist = vol.histogram(nbins,mask);
double ntot = hist.Sum();
for (int j=1; j<=nbins; j++) {
if (hist(j)>0) {
entropy -= (hist(j)/ntot) * log(hist(j)/ntot);
}
}
entropy /= log((double) nbins);
cout << entropy << " ";
} else if (sarg=="-E") {
ColumnVector hist;
int nbins=1000;
double entropy=0;
hist = vol.histogram(nbins,masknz);
double ntot = hist.Sum();
for (int j=1; j<=nbins; j++) {
if (hist(j)>0) {
entropy -= (hist(j)/ntot) * log(hist(j)/ntot);
}
}
entropy /= log((double) nbins);
cout << entropy << " ";
} else if (sarg=="-k") {
narg++;
if (narg>=argc) {
cerr << "Must specify an argument to -k" << endl;
exit(2);
}
read_volume4D(mask,argv[narg]);
if (!samesize(mask[0],vol[0])) {
cerr << "Mask and image must be the same size" << endl;
exit(3);
}
if ( mask.tsize() > vol.tsize() ) {
cerr << "Mask and image must be the same size" << endl;
exit(3);
}
if ( mask.tsize() != vol.tsize() ) {
// copy the last max volume until the correct size is reached
while (mask.tsize() < vol.tsize() ) {
mask.addvolume(mask[mask.maxt()]);
}
}
if (!masks_used) {
masks_used=true;
vin = vol;
}
float th= 0.5;
if (th!=0) {
mask.binarise(th);
} else {
mask.binarise(1);
}
generate_masks(mask,masknz,vin);
vol = vin * mask;
} else if (sarg=="-l") {
narg++;
if (narg<argc) {
lthr = atof(argv[narg]);
} else {
cerr << "Must specify an argument to -l" << endl;
exit(2);
}
lthr_used=true;
if (!masks_used) {
masks_used=true;
vin = vol;
}
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
} else if (sarg=="-u") {
narg++;
if (narg<argc) {
uthr = atof(argv[narg]);
} else {
cerr << "Must specify an argument to -u" << endl;
exit(2);
}
uthr_used=true;
if (!masks_used) {
masks_used=true;
vin = vol;
}
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
} else if (sarg=="-a") {
vol = abs(vin);
} else if (sarg=="-v") {
if (masks_used) {
cout << (long int) mask.sum() << " "
<< mask.sum() * vol.xdim() * vol.ydim() * vol.zdim() << " ";
} else {
cout << (long int) vol.nvoxels() << " "
<< vol.nvoxels() * vol.xdim() * vol.ydim() * vol.zdim() << " ";
}
} else if (sarg=="-V") {
if (masks_used) {
cout << (long int) masknz.sum() << " "
<< masknz.sum() * vol.xdim() * vol.ydim() * vol.zdim() << " ";
} else {
long int nzvox;
nzvox = nonzerocount(vol);
cout << nzvox << " "
<< nzvox * vol.xdim() * vol.ydim() * vol.zdim() << " ";
}
} else if (sarg=="-d") {
// hidden debug option!
cout << vol.sum() << " ";
} else if (sarg=="-s") {
if (masks_used) cout << vol.stddev(mask) << " ";
else cout << vol.stddev() << " ";
} else if (sarg=="-S") {
if (masks_used) {
cout << vol.stddev(masknz) << " ";
} else {
cout << nonzerostddev(vol) << " ";
}
} else if (sarg=="-r") {
if (masks_used) {
float rmin=vol.robustmin(mask);
float rmax=vol.robustmax(mask);
if (rmin>rmax) {
float tmp = rmax;
rmax = rmin;
rmin = tmp;
}
cout << rmin << " " << rmax << " ";
} else {
cout << vol.robustmin() << " " << vol.robustmax() << " ";
}
} else if (sarg=="-R") {
if (masks_used) cout << vol.min(mask) << " " << vol.max(mask) << " ";
else cout << vol.min() << " " << vol.max() << " ";
} else if (sarg=="-c") {
ColumnVector cog(4);
// convert from fsl mm to voxel to sform coord
cog.SubMatrix(1,3,1,1) = vol[0].cog();
cog(4) = 1.0;
if (vol[0].sform_code()!=NIFTI_XFORM_UNKNOWN) {
cog = vol[0].sform_mat() * (vol[0].sampling_mat()).i() * cog;
}
cout << cog(1) << " " << cog(2) << " " << cog(3) << " " ;
} else if (sarg=="-C") {
ColumnVector cog(4);
// convert from fsl mm to voxel coord
cog.SubMatrix(1,3,1,1) = vol[0].cog();
cog(4) = 1.0;
cog = (vol[0].sampling_mat()).i() * cog;
cout << cog(1) << " " << cog(2) << " " << cog(3) << " " ;
} else if (sarg=="-p") {
float n;
narg++;
if (narg<argc) {
n = atof(argv[narg]);
} else {
cerr << "Must specify an argument to -p" << endl;
exit(2);
}
if ( (n<0) || (n>100) ) {
cerr << "Percentile must be between 0 and 100" << endl;
exit(1);
}
if (masks_used) cout << vol.percentile((float) n/100.0, mask) << " ";
else cout << vol.percentile((float) n/100.0) << " ";
} else if (sarg=="-P") {
float n;
narg++;
if (narg<argc) {
n = atof(argv[narg]);
} else {
cerr << "Must specify an argument to -P" << endl;
exit(2);
}
if ( (n<0) || (n>100) ) {
cerr << "Percentile must be between 0 and 100" << endl;
exit(1);
}
if (!masks_used) {
if (vin.nvoxels()<1) { vin = vol; }
masks_used=true;
generate_masks(mask,masknz,vin,lthr,uthr);
vol = vin * mask;
}
cout << vol.percentile((float) n/100.0,masknz) << " ";
} else {
cerr << "Unrecognised option: " << sarg << endl;
exit(3);
}
narg++;
}
cout << endl;
return 0;
}
int main(int argc,char *argv[])
{
Tracer tr("main");
string progname=argv[0];
if (argc<3) {
print_usage(progname);
return 1;
}
return fmrib_main_float(argc,argv);
}