<commit_before>/*
 *  niinudge.cpp
 *
 *  Copyright (c) 2014 <NAME>.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>
#include <sstream>
#include <string>
#include <getopt.h>

#include <Eigen/Core>
#include "Nifti/Nifti.h"
#include "QUIT/MultiArray.h"

using namespace std;
using namespace Eigen;
using namespace QUIT;

const string usage = "niinudge - A utility for moving Nifti images in physical space.\n\
\n\
Usage: niinudge [options] file1 [other files]\n\
By default nothing happens. Specify one of the options to move your image.\n\
Many of the options require a 3 dimensional vector argument. Valid formats for\n\
this are:\n\
X Y Z - Make sure you encase this format in quotes (\" \")!\n\
\n\
Options:\n\
	--out, -o prefix       : Add a prefix to the output filenames\n\
	--nudge, -n \"X Y Z\"  : Nudge the image (X Y Z added to current offset)\n\
	--offset, -f \"X Y Z\" : Set the offset to (X,Y,Z)\n\
	--cog, -c              : Move the Center of Gravity to the origin of the\n\
	                         first image, and move subsequent images by the\n\
	                         same amount\n\
	--verbose, -v          : Print out what the program is doing\n\
	-h, --help:   Print this message and quit.\n\
";

static const struct option long_opts[] = {
	{"nudge",  required_argument, 0, 'n'},
	{"out", required_argument, 0, 'o'},
	{"offset", required_argument, 0, 'f'},
	{"cog",    no_argument, 0, 'c'},
	{"verbose", no_argument, 0, 'v'},
	{"help",   no_argument, 0, 'h'},
	{0, 0, 0, 0}
};
static const char *short_opts = "n:o:f:cvh";
static string prefix;
static int verbose = false;

Vector3f parse_vector(char *str);
Vector3f parse_vector(char *str) {
	istringstream is(str);
	Vector3f vec;
	is >> vec[0] >> vec[1] >> vec[2];
	return vec;
}

Vector3f calc_cog(Nifti::File &f);
Vector3f calc_cog(Nifti::File &f) {
	const auto dims = f.matrix();
	MultiArray<float, 3> a(dims);
	f.open(f.imagePath(), Nifti::Mode::Read);
	f.readVolumes(a.begin(), a.end(), 0, 1);

	Vector3f cog = Vector3f::Zero();
	float mass = 0.;
	for (size_t k = 0; k < dims[2]; k++) {
		for (size_t j = 0; j < dims[1]; j++) {
			for (size_t i = 0; i < dims[0]; i++) {
				float val = a[{i,j,k}];
				if (isfinite(val)) {
					cog += val * Vector3f(i,j,k);
					mass += val;
				}
			}
		}
	}
	cog /= mass;
	if (verbose) cout << "CoG in voxels: " << cog.transpose() << ", mass: " << mass << endl;
	cog = f.header().transform() * cog;
	if (verbose) cout << "CoG in space:  " << cog.transpose() << endl;
	f.close();
	return cog;
}

int main(int argc, char **argv) {
	// Make a first pass to permute the options and get filenames at the end
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
		case 'o': prefix = optarg; break;
		case 'v': verbose = true; break;
		case '?': // getopt will print an error message
		case 'h':
			cout << usage << endl;
			return EXIT_FAILURE;
		default:
			break;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		cout << usage << endl;
		return EXIT_FAILURE;
	}
	vector<Nifti::File> files;
	vector<vector<char>> data;
	files.reserve(argc - optind);
	data.reserve(argc - optind);
	while (optind < argc) {
		files.emplace_back(Nifti::File(argv[optind++], Nifti::Mode::Read));
		Nifti::File &f = files.back();
		if (verbose) cout << "Opened file: " << f.imagePath() << endl;
		data.emplace_back(vector<char>(f.dataSize()));
		f.readBytes(data.back());
		f.close();
	}
	optind = 1;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		Vector3f nudge;
		switch (c) {
		case 'n':
			nudge = parse_vector(optarg);
			for (Nifti::File &f : files) {
				if (verbose) cout << "Nudging offset by: " << nudge.transpose() << " in file: " << f.imagePath() << endl;
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm = Translation3f(nudge) * xfm;
				h.setTransform(xfm);
				f.setHeader(h);
			}
			break;
		case 'f':
			nudge = parse_vector(optarg);
			for (Nifti::File &f : files) {
				if (verbose) cout << "Setting offset to: " << nudge.transpose() << " in file: " << f.imagePath() << endl;
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm.translation() = nudge;
				h.setTransform(xfm);
				f.setHeader(h);
			}
			break;
		case 'c': {
			if (verbose) cout << "Aligning origin to CoG in file: " << files.front().imagePath() << endl;
			Affine3f CoG; CoG = Translation3f(-calc_cog(files.front()));
			for (Nifti::File &f : files) {
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm = CoG * xfm;
				h.setTransform(xfm);
				f.setHeader(h);
			}
		} break;
		case '?': // getopt will print an error message<commit_msg>Modified the CoG application to subsequent files.<commit_after>/*
 *  niinudge.cpp
 *
 *  Copyright (c) 2014 <NAME>.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <iostream>
#include <sstream>
#include <string>
#include <getopt.h>

#include <Eigen/Core>
#include "Nifti/Nifti.h"
#include "QUIT/MultiArray.h"

using namespace std;
using namespace Eigen;
using namespace QUIT;

const string usage = "niinudge - A utility for moving Nifti images in physical space.\n\
\n\
Usage: niinudge [options] file1 [other files]\n\
By default nothing happens. Specify one of the options to move your image.\n\
Many of the options require a 3 dimensional vector argument. Valid formats for\n\
this are:\n\
X Y Z - Make sure you encase this format in quotes (\" \")!\n\
\n\
Options:\n\
	--out, -o prefix       : Add a prefix to the output filenames\n\
	--nudge, -n \"X Y Z\"  : Nudge the image (X Y Z added to current offset)\n\
	--offset, -f \"X Y Z\" : Set the offset to (X,Y,Z)\n\
	--cog, -c              : Move the Center of Gravity to the origin of the\n\
	                         first image, and make subsequent images match\n\
	--verbose, -v          : Print out what the program is doing\n\
	-h, --help:   Print this message and quit.\n\
";

static const struct option long_opts[] = {
	{"nudge",  required_argument, 0, 'n'},
	{"out", required_argument, 0, 'o'},
	{"offset", required_argument, 0, 'f'},
	{"cog",    no_argument, 0, 'c'},
	{"verbose", no_argument, 0, 'v'},
	{"help",   no_argument, 0, 'h'},
	{0, 0, 0, 0}
};
static const char *short_opts = "n:o:f:cvh";
static string prefix;
static int verbose = false;

Vector3f parse_vector(char *str);
Vector3f parse_vector(char *str) {
	istringstream is(str);
	Vector3f vec;
	is >> vec[0] >> vec[1] >> vec[2];
	return vec;
}

Vector3f calc_cog(Nifti::File &f);
Vector3f calc_cog(Nifti::File &f) {
	const auto dims = f.matrix();
	MultiArray<float, 3> a(dims);
	f.open(f.imagePath(), Nifti::Mode::Read);
	f.readVolumes(a.begin(), a.end(), 0, 1);

	Vector3f cog = Vector3f::Zero();
	float mass = 0.;
	for (size_t k = 0; k < dims[2]; k++) {
		for (size_t j = 0; j < dims[1]; j++) {
			for (size_t i = 0; i < dims[0]; i++) {
				float val = a[{i,j,k}];
				if (isfinite(val)) {
					cog += val * Vector3f(i,j,k);
					mass += val;
				}
			}
		}
	}
	cog /= mass;
	if (verbose) cout << "CoG in voxels: " << cog.transpose() << ", mass: " << mass << endl;
	cog = f.header().transform() * cog;
	if (verbose) cout << "CoG in space:  " << cog.transpose() << endl;
	f.close();
	return cog;
}

int main(int argc, char **argv) {
	// Make a first pass to permute the options and get filenames at the end
	int indexptr = 0, c;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		switch (c) {
		case 'o': prefix = optarg; break;
		case 'v': verbose = true; break;
		case '?': // getopt will print an error message
		case 'h':
			cout << usage << endl;
			return EXIT_FAILURE;
		default:
			break;
		}
	}
	if ((argc - optind) <= 0 ) {
		cerr << "No input image file specified." << endl;
		cout << usage << endl;
		return EXIT_FAILURE;
	}
	vector<Nifti::File> files;
	vector<vector<char>> data;
	files.reserve(argc - optind);
	data.reserve(argc - optind);
	while (optind < argc) {
		files.emplace_back(Nifti::File(argv[optind++], Nifti::Mode::Read));
		Nifti::File &f = files.back();
		if (verbose) cout << "Opened file: " << f.imagePath() << endl;
		data.emplace_back(vector<char>(f.dataSize()));
		f.readBytes(data.back());
		f.close();
	}
	optind = 1;
	while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
		Vector3f nudge;
		switch (c) {
		case 'n':
			nudge = parse_vector(optarg);
			for (Nifti::File &f : files) {
				if (verbose) cout << "Nudging offset by: " << nudge.transpose() << " in file: " << f.imagePath() << endl;
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm = Translation3f(nudge) * xfm;
				h.setTransform(xfm);
				f.setHeader(h);
			}
			break;
		case 'f':
			nudge = parse_vector(optarg);
			for (Nifti::File &f : files) {
				if (verbose) cout << "Setting offset to: " << nudge.transpose() << " in file: " << f.imagePath() << endl;
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm.translation() = nudge;
				h.setTransform(xfm);
				f.setHeader(h);
			}
			break;
		case 'c': {
			if (verbose) cout << "Aligning origin to CoG in file: " << files.front().imagePath() << endl;
			Vector3f CoG = calc_cog(files.front());
			Affine3f xfm1 = files.front().header().transform();
			xfm1 = Translation3f(-CoG) * xfm1;
			Vector3f offset = xfm1.translation();
			for (Nifti::File &f : files) {
				Nifti::Header h = f.header();
				Affine3f xfm = h.transform();
				xfm.translation() = offset;
				h.setTransform(xfm);
				f.setHeader(h);
			}
		} break;
		case '?': // getopt will print an error message
{'fraction_non_alphanumeric': 0.17235494880546076, 'fraction_numerical': 0.011242722344910661, 'mean_word_length': 3.1495210329029573, 'pattern_counts': {'":': 0, '<': 155, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '774901', 'n_tokens_mistral': 4088, 'n_tokens_neox': 3763, 'n_words': 1123}