17#ifndef __image_check__h__
18#define __image_check__h__
29 template <
class HeaderType1,
class HeaderType2>
32 check_dimensions (in1, in2);
33 for (
size_t i = 0; i < in1.ndim(); ++i) {
34 if (std::isfinite (in1.spacing(i)))
35 if (
abs ((in1.spacing(i) - in2.spacing(i)) / (in1.spacing(i) + in2.spacing(i))) > 1
e-4)
36 throw Exception (
"images \"" + in1.name() +
"\" and \"" + in2.name() +
"\" do not have matching voxel spacings on axis " +
str(i) +
37 " (" +
str(in1.spacing(i)) +
" vs " +
str(in2.spacing(i)) +
")");
39 for (
size_t i = 0; i < 3; ++i) {
40 for (
size_t j = 0; j < 4; ++j) {
41 if (
abs (in1.transform().matrix()(i,j) - in2.transform().matrix()(i,j)) > 0.001)
42 throw Exception (
"images \"" + in1.name() +
"\" and \"" + in2.name() +
"\" do not have matching header transforms:\n" +
43 str(in1.transform().matrix()) +
"\nvs:\n " +
str(in2.transform().matrix()) +
")");
50 template <
class ImageType1,
class ImageType2>
51 inline void check_images_abs (ImageType1& in1, ImageType2& in2,
const double tol = 0.0)
55 .run ([&tol] (
const ImageType1& a,
const ImageType2& b) {
57 throw Exception (
"images \"" + a.name() +
"\" and \"" + b.name() +
"\" do not match within absolute precision of " +
str(tol)
64 template <
class ImageType1,
class ImageType2>
69 .run ([&tol] (
const ImageType1& a,
const ImageType2& b) {
71 throw Exception (
"images \"" + a.name() +
"\" and \"" + b.name() +
"\" do not match within fractional precision of " +
str(tol)
77 template <
class ImageType1,
class ImageType2,
class ImageTypeTol>
83 .run ([] (
const ImageType1& a,
const ImageType2& b,
const ImageTypeTol& t) {
85 throw Exception (
"images \"" + a.name() +
"\" and \"" + b.name() +
"\" do not match within precision of \"" + t.name() +
"\""
91 template <
class ImageType1,
class ImageType2>
94 auto func = [&tol] (
decltype(in1)& a,
decltype(in2)& b) {
95 double maxa = 0.0, maxb = 0.0;
96 for (
auto l =
Loop(3) (a, b); l; ++l) {
97 maxa = std::max (maxa,
abs (
cdouble(a.value())));
98 maxb = std::max (maxb,
abs (
cdouble(b.value())));
100 const double threshold = tol * 0.5 * (maxa + maxb);
101 for (
auto l =
Loop(3) (a, b); l; ++l) {
103 throw Exception (
"images \"" + a.name() +
"\" and \"" + b.name() +
"\" do not match within " +
str(tol) +
" of maximal voxel value"
112 template <
class HeaderType1,
class HeaderType2>
115 const static std::set<std::string> reserved {
"command_history",
"mrtrix_version",
"project_version" };
116 auto it1 = in1.keyval().cbegin();
117 auto it2 = in2.keyval().cbegin();
119 while (it1 != in1.keyval().end() || it2 != in2.keyval().end()) {
120 while (it1 != in1.keyval().end() && reserved.find (it1->first) != reserved.end())
122 while (it2 != in2.keyval().end() && reserved.find (it2->first) != reserved.end())
125 if (it1 == in1.keyval().end() || it2 == in2.keyval().end())
128 if (it1 == in1.keyval().end()) {
129 errors.
push_back (
"Key \"" + it2->first +
"\" in image \"" + in2.name() +
"\" not present in \"" + in1.name() +
"\"");
132 else if (it2 == in2.keyval().end()) {
133 errors.
push_back (
"Key \"" + it1->first +
"\" in image \"" + in1.name() +
"\" not present in \"" + in2.name() +
"\"");
136 else if (it1->first < it2->first) {
137 errors.
push_back (
"Key \"" + it1->first +
"\" in image \"" + in1.name() +
"\" not present in \"" + in2.name() +
"\"");
140 else if (it1->first > it2->first) {
141 errors.
push_back (
"Key \"" + it2->first +
"\" in image \"" + in2.name() +
"\" not present in \"" + in1.name() +
"\"");
145 if (it1->second != it2->second)
146 errors.
push_back (
"Key \"" + it1->first +
"\" has different values between images");
152 if (errors.
num() > 0)
157 template <
class HeaderType1,
class HeaderType2>
160 if (!dimensions_match (in1, in2))
162 if (!spacings_match (in1, in2, 1
e-6))
164 if (!voxel_grids_match_in_scanner_space (in1, in2))
171 template <
class ImageType1,
class ImageType2>
176 for (
auto i =
Loop (in1)(in1, in2); i; ++i)
void push_back(const std::string &s)
FORCE_INLINE LoopAlongAxes Loop()
bool images_match_abs(ImageType1 &in1, ImageType2 &in2, const double tol=0.0)
check images are the same within a absolute tolerance
std::complex< double > cdouble
constexpr std::enable_if< std::is_arithmetic< X >::value &&std::is_unsigned< X >::value, X >::type abs(X x)
bool headers_match(HeaderType1 &in1, HeaderType2 &in2)
check image headers are the same (dimensions, spacing & transform)
void check_images_frac(ImageType1 &in1, ImageType2 &in2, const double tol=0.0)
check images are the same within a fractional tolerance
std::string str(const T &value, int precision=0)
ThreadedLoopRunOuter< decltype(Loop(vector< size_t >()))> ThreadedLoop(const HeaderType &source, const vector< size_t > &outer_axes, const vector< size_t > &inner_axes)
Multi-threaded loop object.
void check_headers(HeaderType1 &in1, HeaderType2 &in2)
check image headers are the same (dimensions, spacing & transform)
void check_images_tolimage(ImageType1 &in1, ImageType2 &in2, ImageTypeTol &tol)
check images are the same within a tolerance defined by a third image
void check_images_abs(ImageType1 &in1, ImageType2 &in2, const double tol=0.0)
check images are the same within a absolute tolerance
void check_keyvals(const HeaderType1 &in1, const HeaderType2 &in2)
check headers contain the same key-value entries
void check_images_voxel(ImageType1 &in1, ImageType2 &in2, const double tol=0.0)
check images are the same within a fractional tolerance relative to the maximum value in the voxel