64 #define LINE_SIZE 4096 70 #include <type_traits> 83 #if __cplusplus > 199711L 91 #include <itkImageSeriesReader.h> 92 #include <itkImageFileReader.h> 93 #include <itkImageFileWriter.h> 94 #include <itkNumericSeriesFileNames.h> 95 #include "itkGDCMImageIO.h" 96 #include "itkGDCMSeriesFileNames.h" 97 #include "itkImportImageFilter.h" 98 #include "itkDiscreteGaussianImageFilter.h" 99 #include "itkAntiAliasBinaryImageFilter.h" 100 #include "itkBinaryBallStructuringElement.h" 101 #include <itkBinaryMorphologicalOpeningImageFilter.h> 102 #include <itkBinaryMorphologicalClosingImageFilter.h> 103 #include <itkRecursiveGaussianImageFilter.h> 104 #include <itkResampleImageFilter.h> 105 #include <itkIdentityTransform.h> 106 #include <itkBSplineInterpolateImageFunction.h> 108 #include <itkRescaleIntensityImageFilter.h> 110 #include "itkBinaryMask3DMeshSource.h" 115 #include <gdcmGlobal.h> 117 #include "gdcmImageReader.h" 118 #include "gdcmSequenceOfFragments.h" 119 #include "gdcmSystem.h" 120 #include "gdcmImageWriter.h" 121 #include "gdcmPixmapWriter.h" 122 #include <gdcmRescaler.h> 124 #include <gdcmImage.h> 125 #include <gdcmBitmap.h> 126 #include <gdcmImageWriter.h> 127 #include <gdcmPixelFormat.h> 128 #include <gdcmPhotometricInterpretation.h> 129 #include <gdcmImageChangeTransferSyntax.h> 140 #ifndef __ConstantValues_h 144 #ifndef __Utilities_h 148 #ifndef __Exception_h 152 #ifndef __OutOfBoundsException_h 156 #ifndef __OutOfMemoryException_h 160 #ifndef __FileDoesNotExistException_h 164 #ifndef __PolygonMesh_h 188 m_number_of_slices(0),
199 m_width(anImage.m_width),
200 m_height(anImage.m_height),
201 m_number_of_slices(anImage.m_number_of_slices),
202 m_spacing(anImage.m_spacing),
203 m_p_image(new T[m_width * m_height * m_number_of_slices]),
208 if (m_width && m_height && m_number_of_slices && !m_p_image)
214 std::copy(anImage.
m_p_image, anImage.
m_p_image + m_width * m_height * m_number_of_slices, m_p_image);
223 m_number_of_slices(0),
238 m_number_of_slices(0),
251 unsigned int aHeight,
252 unsigned int aNumberOfSlices,
253 const VEC3& aVoxelSize):
257 m_number_of_slices(aNumberOfSlices),
258 m_spacing(aVoxelSize),
259 m_p_image(new T[m_width * m_height * m_number_of_slices]),
264 if (m_width && m_height && !m_p_image)
270 std::copy(apData, apData + m_width * m_height * m_number_of_slices, m_p_image);
276 unsigned int aHeight,
277 unsigned int aNumberOfSlices,
279 const VEC3& aVoxelSize):
283 m_number_of_slices(aNumberOfSlices),
284 m_spacing(aVoxelSize),
285 m_p_image(new T[m_width * m_height * m_number_of_slices]),
290 if (m_width && m_height && m_number_of_slices && !m_p_image)
296 std::fill_n(m_p_image, m_width * m_height * m_number_of_slices, aDefaultValue);
313 Image<T> kernel(aSize, aSize, 1, 0.0);
317 double two_sigma_square = 2.0 * aSigmaValue * aSigmaValue;
321 for (
int i = 0; i < aSize; i++)
323 for (
int j = 0; j < aSize; j++)
325 kernel(i, j, 0) = exp(-(pow(i - x0, 2) + pow(j - y0, 2)) / two_sigma_square);
326 sum += kernel(i, j, 0);
330 for (
int i = 0; i < aSize; i++)
332 for (
int j = 0; j < aSize; j++)
334 kernel(i, j, 0) /= sum;
347 std::fill_n(m_p_image, m_width * m_height * m_number_of_slices, aDefaultColour);
355 std::ifstream input_file (aFileName);
358 if (!input_file.is_open())
360 std::string error_message(
"The file (");
361 error_message += aFileName;
362 error_message +=
") does not exist";
364 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
368 std::vector<T> p_data;
370 int number_of_rows(0);
371 int number_of_columns(0);
374 while (std::getline(input_file, line))
380 number_of_columns = 0;
382 std::stringstream line_parser;
384 while (line_parser >> intensity)
386 p_data.push_back(intensity);
395 if (number_of_rows * number_of_columns != p_data.size())
397 std::string error_message(
"The file (");
398 error_message += aFileName;
399 error_message +=
") is invalid";
401 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
408 m_width = number_of_columns;
409 m_height = number_of_rows;
410 m_number_of_slices = 1;
411 m_p_image =
new T[m_width * m_height];
414 std::copy(p_data.begin(), p_data.end(), m_p_image);
422 loadASCII(aFileName.data());
429 unsigned int aHeight,
431 const VEC3& aVoxelSize)
435 std::ifstream input_file(aFileName);
441 if (!input_file.is_open())
443 std::string error_message(
"The file (");
444 error_message += aFileName;
445 error_message +=
") does not exist";
447 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
453 m_number_of_slices = aDepth;
454 unsigned int volume_size(m_width * m_height * m_number_of_slices);
455 m_p_image =
new T[volume_size];
456 m_spacing = aVoxelSize;
459 unsigned int voxels(0);
462 while (input_file >> intensity)
465 if (voxels >= volume_size)
475 m_p_image[voxels] = intensity;
496 unsigned int aHeight,
498 const VEC3& aVoxelSize)
501 loadASCII(aFileName.data(), aWidth,
513 unsigned int aHeight,
514 unsigned int aDepth)
const 518 Image<T> roi(aWidth, aHeight, aDepth);
524 #pragma omp parallel for 526 #pragma omp parallel for collapse(3) 529 for (
int z = 0; z < aDepth; ++z)
532 for (
int y = 0; y < aHeight; ++y)
535 for (
int x = 0; x < aWidth; ++x)
537 unsigned int index_i(x + i);
538 unsigned int index_j(y + j);
539 unsigned int index_k(z + k);
542 if ((index_i >= m_width) ||
543 (index_j >= m_height) ||
544 (index_k >= m_number_of_slices))
550 T intensity(getPixel(index_i, index_j, index_k));
570 if ((i >= m_width) ||
572 (k >= m_number_of_slices))
577 m_p_image[k * m_width * m_height + j * m_width + i] = aValue;
588 if ((i >= m_width) ||
590 (k >= m_number_of_slices))
595 return (m_p_image[k * m_width * m_height + j * m_width + i]);
602 unsigned int k)
const 606 if ((i >= m_width) ||
608 (k >= m_number_of_slices))
613 return (m_p_image[k * m_width * m_height + j * m_width + i]);
623 return (getPixel(i, j, k));
630 unsigned int k)
const 633 return (getPixel(i, j, k));
640 unsigned int k)
const 643 return (
VEC3(m_spacing[0] * i, m_spacing[1] * j, m_spacing[2] * k));
651 if (anIndex >= m_width * m_height * m_number_of_slices)
656 return (m_p_image[anIndex]);
664 if (anIndex >= m_width * m_height * m_number_of_slices)
669 return (m_p_image[anIndex]);
679 return (getPixel(i, j, k));
686 unsigned int k)
const 689 return (getPixel(i, j, k));
710 m_number_of_slices = 0;
712 destroyOpenGLTexture();
737 if (
this != &anImage)
749 if (m_width && m_height && m_number_of_slices && !m_p_image)
762 std::copy(anImage.
m_p_image, anImage.
m_p_image + m_width * m_height * m_number_of_slices, m_p_image);
773 destroyOpenGLTexture();
776 std::copy(apImage, apImage + m_width * m_height * m_number_of_slices, m_p_image);
803 return (m_number_of_slices);
811 m_spacing = aPixelSize;
817 const double& aPixelHeight,
818 const double& aPixelDepth)
821 m_spacing[0] = aPixelWidth;
822 m_spacing[1] = aPixelHeight;
823 m_spacing[2] = aPixelDepth;
842 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Empty image");
845 return (*std::min_element(&m_p_image[0], &m_p_image[m_width * m_height * m_number_of_slices]));
856 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Empty image");
859 return (*std::max_element(&m_p_image[0], &m_p_image[m_width * m_height * m_number_of_slices]));
870 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Empty image");
873 return (*std::min_element(&m_p_image[aSliceID * m_width * m_height], &m_p_image[(aSliceID + 1) * m_width * m_height]));
884 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Empty image");
887 return (*std::max_element(&m_p_image[aSliceID * m_width * m_height], &m_p_image[(aSliceID + 1) * m_width * m_height]));
894 bool aRunOnGPUFlag)
const 901 bool use_gpu =
false;
908 const_cast<Image<T>&
>(temp).transferHostToDevice();
915 LOGGER.
logWarning(
"GPU computation requested but not supported in the function as follows:") << std::endl <<
916 "\tFile: " << __FILE__ << std::endl <<
917 "\tFunction: " << __FUNCTION__ << std::endl <<
918 "\tLine: " << __LINE__ << std::endl;
928 std::string g_compute_shader;
929 g_compute_shader +=
"#version 430\n";
930 g_compute_shader +=
"\n";
931 g_compute_shader +=
"layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n";
933 g_compute_shader +=
"\n";
934 g_compute_shader +=
"layout(location=0) uniform float shift;\n";
935 g_compute_shader +=
"layout(location=1) uniform float scale;\n";
936 g_compute_shader +=
"\n";
937 g_compute_shader +=
"void main(void)\n";
938 g_compute_shader +=
"{\n";
939 g_compute_shader +=
" ivec3 pixel_coordinates = ivec3(gl_GlobalInvocationID.xyz);\n";
940 g_compute_shader +=
" float intensity = imageLoad(input_output_image, pixel_coordinates).r;\n";
941 g_compute_shader +=
" " +
getShaderPixelType(
typeid(T)) +
" pixel_value = (shift + intensity) * scale;\n";
942 g_compute_shader +=
"\n";
943 g_compute_shader +=
" imageStore(input_output_image, pixel_coordinates, " +
getShaderRGBAPixelType(
typeid(T)) +
"(pixel_value, 0, 0, 0));\n";
944 g_compute_shader +=
"}\n";
951 dummy_shader.
setLabel(
"g_compute_shader");
954 dummy_shader.
loadSource(static_cast<const GLchar*>(g_compute_shader.c_str()));
968 GLint program_handle(0);
969 glGetIntegerv(GL_CURRENT_PROGRAM, &program_handle);
972 GLint uniform_handle = glGetUniformLocation(program_handle,
"shift");
973 glUniform1f(uniform_handle, aShiftValue);
976 uniform_handle = glGetUniformLocation(program_handle,
"scale");
977 glUniform1f(uniform_handle, aScaleValue);
982 glDispatchCompute(getWidth(), getHeight(), getDepth());
986 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
989 const_cast<Image<T>&
>(temp).transferDeviceToHost();
1000 LOGGER.
logWarning(
"GPU computation requested and supported but failed to execute in the function as follows:") << std::endl <<
1001 "\tFile: " << __FILE__ << std::endl <<
1002 "\tFunction: " << __FUNCTION__ << std::endl <<
1003 "\tLine: " << __LINE__ << std::endl;
1009 if (use_gpu ==
false)
1013 #pragma omp parallel for 1015 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
1018 temp[i] = (temp[i] + aShiftValue) * aScaleValue;
1034 glGenTextures(1, &m_texture_id);
1039 glBindTexture(GL_TEXTURE_3D, m_texture_id);
1041 if (
typeid(T) ==
typeid(
unsigned int) ||
1042 typeid(T) ==
typeid(
int) ||
1043 typeid(T) ==
typeid(
unsigned short) ||
1044 typeid(T) ==
typeid(
short) ||
1045 typeid(T) ==
typeid(
unsigned char) ||
1046 typeid(T) ==
typeid(
char))
1048 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1049 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1051 else if (
typeid(T) ==
typeid(
float))
1053 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1054 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1058 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1059 "The data type of this image is not supported on GPU.");
1062 glPixelStorei(GL_PACK_ALIGNMENT, 1);
1066 GLint texture_width(0);
1068 if (
typeid(T) ==
typeid(
unsigned int))
1070 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R32UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
1072 else if (
typeid(T) ==
typeid(
int))
1074 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R32I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_INT, 0);
1076 else if (
typeid(T) ==
typeid(
unsigned short))
1078 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R16UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, 0);
1080 else if (
typeid(T) ==
typeid(
short))
1082 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R16I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_SHORT, 0);
1084 else if (
typeid(T) ==
typeid(
unsigned char))
1086 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R8UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
1088 else if (
typeid(T) ==
typeid(
char))
1090 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R8I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_BYTE, 0);
1092 else if (
typeid(T) ==
typeid(
float))
1094 glTexImage3D(GL_PROXY_TEXTURE_3D, 0, GL_R32F, m_width, m_height, m_number_of_slices, 0, GL_RED, GL_FLOAT, 0);
1098 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1099 "The data type of this image is not supported on GPU.");
1104 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &texture_width);
1106 if ((
unsigned int)(texture_width) != m_width)
1108 std::stringstream error_message;
1109 error_message <<
"Cannot create a " <<
"(" << m_width <<
" x " << m_height <<
" x " << m_number_of_slices <<
") floating point render texture.";
1110 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message.str());
1113 if (
typeid(T) ==
typeid(
unsigned int))
1115 glTexImage3D(GL_TEXTURE_3D, 0, GL_R32UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, m_p_image);
1117 else if (
typeid(T) ==
typeid(
int))
1119 glTexImage3D(GL_TEXTURE_3D, 0, GL_R32I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_INT, m_p_image);
1121 else if (
typeid(T) ==
typeid(
unsigned short))
1123 glTexImage3D(GL_TEXTURE_3D, 0, GL_R16UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_p_image);
1125 else if (
typeid(T) ==
typeid(
short))
1127 glTexImage3D(GL_TEXTURE_3D, 0, GL_R16I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_SHORT, m_p_image);
1129 else if (
typeid(T) ==
typeid(
unsigned char))
1131 glTexImage3D(GL_TEXTURE_3D, 0, GL_R8UI, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, m_p_image);
1133 else if (
typeid(T) ==
typeid(
char))
1135 glTexImage3D(GL_TEXTURE_3D, 0, GL_R8I, m_width, m_height, m_number_of_slices, 0, GL_RED_INTEGER, GL_BYTE, m_p_image);
1137 else if (
typeid(T) ==
typeid(
float))
1139 glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, m_width, m_height, m_number_of_slices, 0, GL_RED, GL_FLOAT, m_p_image);
1143 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1144 "The data type of this image is not supported on GPU.");
1157 glBindTexture(GL_TEXTURE_3D, m_texture_id);
1159 if (
typeid(T) ==
typeid(
unsigned int))
1161 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, m_p_image);
1163 else if (
typeid(T) ==
typeid(
int))
1165 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_INT, m_p_image);
1167 else if (
typeid(T) ==
typeid(
unsigned short))
1169 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, m_p_image);
1171 else if (
typeid(T) ==
typeid(
short))
1173 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_SHORT, m_p_image);
1175 else if (
typeid(T) ==
typeid(
unsigned char))
1177 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, m_p_image);
1179 else if (
typeid(T) ==
typeid(
char))
1181 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED_INTEGER, GL_BYTE, m_p_image);
1183 else if (
typeid(T) ==
typeid(
float))
1185 glGetTexImage(GL_TEXTURE_3D, 0, GL_RED, GL_FLOAT, m_p_image);
1189 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1190 "The data type of this image is not supported on GPU.");
1200 const T& aUpperThreshold,
1201 unsigned char anInValue,
1202 unsigned char anOutValue,
1203 bool aRunOnGPUFlag)
const 1209 bool use_gpu =
false;
1223 LOGGER.
logWarning(
"GPU computation requested but not supported in the function as follows:") << std::endl <<
1224 "\tFile: " << __FILE__ << std::endl <<
1225 "\tFunction: " << __FUNCTION__ << std::endl <<
1226 "\tLine: " << __LINE__ << std::endl;
1236 std::string g_compute_shader;
1237 g_compute_shader +=
"#version 430\n";
1238 g_compute_shader +=
"\n";
1239 g_compute_shader +=
"layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n";
1241 g_compute_shader +=
"layout(" +
getShaderTypeID(
typeid(
unsigned char)) +
", binding=1) uniform " +
getShaderImageType(
typeid(
unsigned char)) +
" output_image;\n";
1242 g_compute_shader +=
"\n";
1243 g_compute_shader +=
"layout(location=0) uniform float low_threshold;\n";
1244 g_compute_shader +=
"layout(location=1) uniform float high_threshold;\n";
1245 g_compute_shader +=
"layout(location=2) uniform uint in_value;\n";
1246 g_compute_shader +=
"layout(location=3) uniform uint out_value;\n";
1247 g_compute_shader +=
"\n";
1248 g_compute_shader +=
"void main(void)\n";
1249 g_compute_shader +=
"{\n";
1250 g_compute_shader +=
" ivec3 pixel_coordinates = ivec3(gl_GlobalInvocationID.xyz);\n";
1251 g_compute_shader +=
" float intensity = imageLoad(input_image, pixel_coordinates).r;\n";
1252 g_compute_shader +=
" int comparison_in = int(low_threshold <= intensity && intensity <= high_threshold);\n";
1253 g_compute_shader +=
" int comparison_out = int(!(low_threshold <= intensity && intensity <= high_threshold));\n";
1254 g_compute_shader +=
" " +
getShaderPixelType(
typeid(
unsigned char)) +
" pixel_value = comparison_in * in_value + comparison_out * out_value;\n";
1255 g_compute_shader +=
"\n";
1256 g_compute_shader +=
" imageStore(output_image, pixel_coordinates, " +
getShaderRGBAPixelType(
typeid(
unsigned char)) +
"(pixel_value, 0, 0, 0));\n";
1257 g_compute_shader +=
"}\n";
1262 dummy_shader.
setLabel(
"g_compute_shader");
1265 dummy_shader.
loadSource(static_cast<const GLchar*>(g_compute_shader.c_str()));
1271 glBindImageTexture(0, getTextureId(), 0, GL_FALSE, 0, GL_READ_ONLY,
getShaderOpenGLType(
typeid(T)));
1280 GLint program_handle(0);
1281 glGetIntegerv(GL_CURRENT_PROGRAM, &program_handle);
1284 GLint uniform_handle = glGetUniformLocation(program_handle,
"low_threshold");
1285 glUniform1f(uniform_handle, aLowerThreshold);
1288 uniform_handle = glGetUniformLocation(program_handle,
"high_threshold");
1289 glUniform1f(uniform_handle, aUpperThreshold);
1292 uniform_handle = glGetUniformLocation(program_handle,
"in_value");
1293 glUniform1ui(uniform_handle, anInValue);
1296 uniform_handle = glGetUniformLocation(program_handle,
"out_value");
1297 glUniform1ui(uniform_handle, anOutValue);
1302 glDispatchCompute(getWidth(), getHeight(), getDepth());
1306 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1320 LOGGER.
logWarning(
"GPU computation requested and supported but failed to execute in the function as follows:") << std::endl <<
1321 "\tFile: " << __FILE__ << std::endl <<
1322 "\tFunction: " << __FUNCTION__ << std::endl <<
1323 "\tLine: " << __LINE__ << std::endl;
1329 if (use_gpu ==
false)
1333 #pragma omp parallel for 1335 #pragma omp parallel for collapse(3) 1338 for (
int k = 0; k < m_number_of_slices; ++k)
1340 for (
int j = 0; j < (m_height); ++j)
1342 for (
int i = 0; i < m_width; ++i)
1344 unsigned int index(k * m_width * m_height + j * m_width + i);
1346 float voxel_value(m_p_image[index]);
1347 if (aLowerThreshold <= voxel_value && voxel_value <= aUpperThreshold)
1349 segmentation.
setPixel(i, j, k, anInValue);
1355 return (segmentation);
1364 Image<T> temp(m_width, m_height, m_number_of_slices, 0);
1367 int kernel_size = aKernel.size();
1368 int half_kernel_size = kernel_size / 2;
1372 #pragma omp parallel for collapse(3) 1374 for (
int k = 0; k < m_number_of_slices; ++k)
1375 for (
int j = 0; j < m_height; ++j)
1376 for (
int i = 0; i < m_width; ++i)
1377 for (
int u = -half_kernel_size; u <= half_kernel_size; ++u)
1379 int index_i(std::max(0, i + u));
1380 index_i = std::min(index_i,
int(m_width - 1));
1382 int index_u = u + half_kernel_size;
1384 if (index_u < kernel_size)
1386 temp(i, j, k) += getPixel(index_i, j, k) * aKernel[index_u];
1400 Image<T> temp(m_width, m_height, m_number_of_slices, 0);
1403 int kernel_size_u = aKernel.getWidth();
1404 int kernel_size_v = aKernel.getHeight();
1405 int half_kernel_size_u = kernel_size_u / 2;
1406 int half_kernel_size_v = kernel_size_v / 2;
1410 #pragma omp parallel for collapse(4) 1412 for (
int k = 0; k < m_number_of_slices; ++k)
1413 for (
int j = 0; j < m_height; ++j)
1414 for (
int i = 0; i < m_width; ++i)
1415 for (
int v = -half_kernel_size_v; v <= half_kernel_size_v; ++v)
1417 int index_j(std::max(0, j + v));
1418 index_j = std::min(index_j,
int(m_height - 1));
1420 int index_v = v + half_kernel_size_v;
1422 for (
int u = -half_kernel_size_u; u <= half_kernel_size_u; ++u)
1424 int index_i(std::max(0, i + u));
1425 index_i = std::min(index_i,
int(m_width - 1));
1427 int index_u = u + half_kernel_size_u;
1429 if (index_u < kernel_size_u && index_v < kernel_size_v)
1431 temp(i, j, k) += getPixel(index_i, index_j, k) * aKernel.
getPixel(index_u, index_v);
1446 Image<T> temp(m_width, m_height, m_number_of_slices, 0);
1449 int kernel_size_u = aKernel.getWidth();
1450 int kernel_size_v = aKernel.getHeight();
1451 int half_kernel_size_u = kernel_size_u / 2;
1452 int half_kernel_size_v = kernel_size_v / 2;
1456 #pragma omp parallel for collapse(4) 1458 for (
int k = 0; k < m_number_of_slices; ++k)
1459 for (
int j = 0; j < m_height; ++j)
1460 for (
int i = 0; i < m_width; ++i)
1461 for (
int v = -half_kernel_size_v; v <= half_kernel_size_v; ++v)
1463 int index_j(std::max(0, j + v));
1464 index_j = std::min(index_j,
int(m_height - 1));
1466 int index_v = v + half_kernel_size_v;
1468 for (
int u = -half_kernel_size_u; u <= half_kernel_size_u; ++u)
1470 int index_i(std::max(0, i + u));
1471 index_i = std::min(index_i,
int(m_width - 1));
1473 int index_u = u + half_kernel_size_u;
1475 if (index_u < kernel_size_u && index_v < kernel_size_v)
1477 temp(i, j, k) += getPixel(index_i, index_j, k) * aKernel.
getPixel(index_u, index_v);
1490 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1491 "gVirtualXRay has not been compiled with ITK support. As a consequence Image<T>::antiAliasBinaryImageFilter is not available.");
1494 typedef itk::Image< unsigned char, 3 > InputImageType;
1495 typedef itk::ImportImageFilter< unsigned char, 3 > ImportFilterType;
1497 ImportFilterType::Pointer importFilter = ImportFilterType::New();
1499 ImportFilterType::SizeType size;
1502 size[2] = m_number_of_slices;
1504 ImportFilterType::IndexType start;
1507 ImportFilterType::RegionType region;
1508 region.SetIndex( start );
1509 region.SetSize( size );
1511 importFilter->SetRegion( region );
1518 importFilter->SetOrigin( origin );
1520 double spacing[ 3 ];
1521 spacing[0] = m_spacing[0];
1522 spacing[1] = m_spacing[1];
1523 spacing[2] = m_spacing[2];
1525 importFilter->SetSpacing( spacing );
1527 const bool importImageFilterWillOwnTheBuffer =
false;
1528 importFilter->SetImportPointer( m_p_image, m_width * m_height * m_number_of_slices,
1529 importImageFilterWillOwnTheBuffer );
1531 typedef itk::BinaryBallStructuringElement<InputImageType::PixelType, InputImageType::ImageDimension>
1532 StructuringElementType;
1533 StructuringElementType structuringElement;
1534 structuringElement.SetRadius(aRadius);
1535 structuringElement.CreateStructuringElement();
1537 typedef itk::BinaryMorphologicalOpeningImageFilter <InputImageType, InputImageType, StructuringElementType>
1538 BinaryMorphologicalOpeningImageFilterType;
1539 BinaryMorphologicalOpeningImageFilterType::Pointer openingFilter
1540 = BinaryMorphologicalOpeningImageFilterType::New();
1541 openingFilter->SetInput(importFilter->GetOutput());
1542 openingFilter->SetKernel(structuringElement);
1544 openingFilter->SetBackgroundValue (getMinValue());
1546 openingFilter->SetForegroundValue (getMaxValue());
1548 openingFilter->Update();
1550 return (
Image<unsigned char>(openingFilter->GetOutput()->GetBufferPointer(), m_width, m_height, m_number_of_slices, m_spacing));
1558 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1559 "gVirtualXRay has not been compiled with ITK support. As a consequence Image<T>::antiAliasBinaryImageFilter is not available.");
1562 typedef itk::Image< unsigned char, 3 > InputImageType;
1563 typedef itk::ImportImageFilter< unsigned char, 3 > ImportFilterType;
1565 ImportFilterType::Pointer importFilter = ImportFilterType::New();
1567 ImportFilterType::SizeType size;
1570 size[2] = m_number_of_slices;
1572 ImportFilterType::IndexType start;
1575 ImportFilterType::RegionType region;
1576 region.SetIndex( start );
1577 region.SetSize( size );
1579 importFilter->SetRegion( region );
1586 importFilter->SetOrigin( origin );
1588 double spacing[ 3 ];
1589 spacing[0] = m_spacing[0];
1590 spacing[1] = m_spacing[1];
1591 spacing[2] = m_spacing[2];
1593 importFilter->SetSpacing( spacing );
1595 const bool importImageFilterWillOwnTheBuffer =
false;
1596 importFilter->SetImportPointer( m_p_image, m_width * m_height * m_number_of_slices,
1597 importImageFilterWillOwnTheBuffer );
1599 typedef itk::BinaryBallStructuringElement<InputImageType::PixelType, InputImageType::ImageDimension>
1600 StructuringElementType;
1601 StructuringElementType structuringElement;
1602 structuringElement.SetRadius(aRadius);
1603 structuringElement.CreateStructuringElement();
1605 typedef itk::BinaryMorphologicalClosingImageFilter <InputImageType, InputImageType, StructuringElementType>
1606 BinaryMorphologicalClosingImageFilterType;
1607 BinaryMorphologicalClosingImageFilterType::Pointer closingFilter
1608 = BinaryMorphologicalClosingImageFilterType::New();
1609 closingFilter->SetInput(importFilter->GetOutput());
1610 closingFilter->SetKernel(structuringElement);
1614 closingFilter->SetForegroundValue (getMaxValue());
1616 closingFilter->Update();
1618 return (
Image<unsigned char>(closingFilter->GetOutput()->GetBufferPointer(), m_width, m_height, m_number_of_slices, m_spacing));
1626 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1627 "gVirtualXRay has not been compiled with ITK support. As a consequence Image<T>::antiAliasBinaryImageFilter is not available.");
1630 typedef itk::Image< unsigned char, 3 > InputImageType;
1631 typedef itk::Image< float, 3 > OutputImageType;
1632 typedef itk::ImportImageFilter< unsigned char, 3 > ImportFilterType;
1634 ImportFilterType::Pointer importFilter = ImportFilterType::New();
1636 ImportFilterType::SizeType current_size;
1637 current_size[0] = m_width;
1638 current_size[1] = m_height;
1639 current_size[2] = m_number_of_slices;
1641 ImportFilterType::IndexType start;
1644 ImportFilterType::RegionType region;
1645 region.SetIndex( start );
1646 region.SetSize( current_size );
1648 importFilter->SetRegion( region );
1655 importFilter->SetOrigin( origin );
1657 double current_spacing[ 3 ];
1658 current_spacing[0] = m_spacing[0];
1659 current_spacing[1] = m_spacing[1];
1660 current_spacing[2] = m_spacing[2];
1662 importFilter->SetSpacing( current_spacing );
1664 const bool importImageFilterWillOwnTheBuffer =
false;
1665 importFilter->SetImportPointer( m_p_image, m_width * m_height * m_number_of_slices,
1666 importImageFilterWillOwnTheBuffer );
1676 typedef itk::RecursiveGaussianImageFilter<
1678 OutputImageType > InputGaussianFilterType;
1679 typedef itk::RecursiveGaussianImageFilter<
1681 OutputImageType > OutputGaussianFilterType;
1693 InputGaussianFilterType::Pointer smootherX = InputGaussianFilterType::New();
1694 OutputGaussianFilterType::Pointer smootherY = OutputGaussianFilterType::New();
1695 smootherX->SetInput( importFilter->GetOutput() );
1696 smootherY->SetInput( smootherX->GetOutput() );
1729 const double isoSpacing = std::sqrt( current_spacing[2] * current_spacing[0] );
1730 smootherX->SetSigma( isoSpacing );
1731 smootherY->SetSigma( isoSpacing );
1740 smootherX->SetDirection( 0 );
1741 smootherY->SetDirection( 1 );
1753 typedef itk::ResampleImageFilter<
1754 OutputImageType, OutputImageType > ResampleFilterType;
1755 ResampleFilterType::Pointer resampler = ResampleFilterType::New();
1764 typedef itk::IdentityTransform< double, 3 > TransformType;
1765 TransformType::Pointer transform = TransformType::New();
1766 transform->SetIdentity();
1767 resampler->SetTransform( transform );
1776 typedef itk::LinearInterpolateImageFunction<
1778 OutputImageType,
double > InterpolatorType;
1779 InterpolatorType::Pointer interpolator = InterpolatorType::New();
1780 resampler->SetInterpolator( interpolator );
1782 resampler->SetDefaultPixelValue( 0 );
1790 OutputImageType::SpacingType spacing;
1791 spacing[0] = isoSpacing;
1792 spacing[1] = isoSpacing;
1793 spacing[2] = isoSpacing;
1794 resampler->SetOutputSpacing( spacing );
1804 resampler->SetOutputOrigin( origin );
1805 resampler->SetOutputDirection( importFilter->GetOutput()->GetDirection() );
1818 InputImageType::SizeType inputSize =
1819 importFilter->GetOutput()->GetLargestPossibleRegion().GetSize();
1820 typedef InputImageType::SizeType::SizeValueType SizeValueType;
1821 const double dx = current_size[0] * current_spacing[0] / isoSpacing;
1822 const double dy = current_size[1] * current_spacing[1] / isoSpacing;
1823 const double dz = (current_size[2] - 1 ) * current_spacing[2] / isoSpacing;
1834 InputImageType::SizeType size;
1835 size[0] =
static_cast<SizeValueType
>( dx );
1836 size[1] =
static_cast<SizeValueType
>( dy );
1837 size[2] =
static_cast<SizeValueType
>( dz );
1838 resampler->SetSize( size );
1849 resampler->SetInput( smootherY->GetOutput() );
1850 resampler->Update();
1852 return (
Image<float>(resampler->GetOutput()->GetBufferPointer(), size[0], size[1], size[2],
VEC3(isoSpacing, isoSpacing, isoSpacing)));
1860 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1861 "gVirtualXRay has not been compiled with ITK support. As a consequence Image<T>::antiAliasBinaryImageFilter is not available.");
1863 if (aMaximumRMSChange >= 1.0)
1865 throw Exception(__FILE__, __FUNCTION__, __LINE__,
1866 "aMaximumRMSChange should be less than 1.0. A value of 0.07 is a good starting estimate.");
1869 typedef itk::Image< unsigned char, 3 > InputImageType;
1870 typedef itk::Image< float, 3 > OutputImageType;
1872 typedef itk::ImportImageFilter< unsigned char, 3 > ImportFilterType;
1874 ImportFilterType::Pointer importFilter = ImportFilterType::New();
1876 ImportFilterType::SizeType size;
1879 size[2] = m_number_of_slices;
1881 ImportFilterType::IndexType start;
1884 ImportFilterType::RegionType region;
1885 region.SetIndex( start );
1886 region.SetSize( size );
1888 importFilter->SetRegion( region );
1895 importFilter->SetOrigin( origin );
1897 double spacing[ 3 ];
1898 spacing[0] = m_spacing[0];
1899 spacing[1] = m_spacing[1];
1900 spacing[2] = m_spacing[2];
1902 importFilter->SetSpacing( spacing );
1904 const bool importImageFilterWillOwnTheBuffer =
false;
1905 importFilter->SetImportPointer( m_p_image, m_width * m_height * m_number_of_slices,
1906 importImageFilterWillOwnTheBuffer );
1908 typedef itk::DiscreteGaussianImageFilter< InputImageType, OutputImageType > GaussianBlurImageFilter;
1909 GaussianBlurImageFilter::Pointer p_gaussian_blur_filter(GaussianBlurImageFilter::New());
1910 p_gaussian_blur_filter->SetInput(importFilter->GetOutput());
1911 p_gaussian_blur_filter->SetVariance(aVariance);
1912 p_gaussian_blur_filter->Update();
1914 typedef itk::AntiAliasBinaryImageFilter< OutputImageType, OutputImageType > AntiAliasBinaryImageFilter;
1915 AntiAliasBinaryImageFilter::Pointer p_filter(AntiAliasBinaryImageFilter::New());
1916 p_filter->SetInput(p_gaussian_blur_filter->GetOutput());
1917 p_filter->SetNumberOfIterations(aNumberOfIterations);
1918 p_filter->SetMaximumRMSError(aMaximumRMSChange);
1921 return (
Image<float>(p_filter->GetOutput()->GetBufferPointer(), m_width, m_height, m_number_of_slices, m_spacing));
1930 Image<T> temp_image(m_width + 2, m_height + 2, m_number_of_slices + 2, aPadValue, m_spacing);
1934 #pragma omp parallel for 1936 #pragma omp parallel for collapse(3) 1939 for (
int k = 0; k < m_number_of_slices; ++k)
1941 for (
int j = 0; j < m_height; ++j)
1943 for (
int i = 0; i < m_width; ++i)
1945 temp_image.
setPixel(i + 1, j + 1, k + 1, getPixel(i, j, k));
1956 unsigned char aValueIn,
1957 unsigned char aValueOut)
const 1964 #pragma omp parallel for 1966 #pragma omp parallel for collapse(3) 1969 for (
int k = 0; k < m_number_of_slices; ++k)
1971 for (
int j = 0; j < m_height; ++j)
1973 for (
int i = 0; i < m_width; ++i)
1975 if (aThreshold <= getPixel(i, j, k))
1977 temp_image.
setPixel(i, j, k, aValueIn);
2026 return (shiftScaleFilter(-getMinValue(), 1.0 / (getMaxValue() - getMinValue())));
2034 return (normalised());
2047 #pragma omp parallel for 2049 #pragma omp parallel for collapse(3) 2052 for (
int k = 0; k < m_number_of_slices; ++k)
2054 for (
int j = 0; j < (m_height / 2); ++j)
2056 for (
int i = 0; i < m_width; ++i)
2059 temp[k * m_height * m_width + j * m_width + i],
2060 temp[k * m_height * m_width + (m_height - 1 - j) * m_width + i]
2079 #pragma omp parallel for 2081 #pragma omp parallel for collapse(3) 2084 for (
unsigned int k = 0; k < m_number_of_slices; ++k)
2086 for (
unsigned int j = 0; j < m_height; ++j)
2088 for (
unsigned int i = 0; i < (m_width / 2); ++i)
2091 temp[k * m_height * m_width + j * m_width + i ],
2092 temp[k * m_height * m_width + j * m_width + (m_width - 1 - i)]
2110 #pragma omp parallel for 2112 for (
unsigned int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
2132 offset = 0.000000157;
2136 #pragma omp parallel for 2138 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
2140 double pixel(m_p_image[i]);
2159 loadUsingITK(aFileName);
2163 loadASCII(aFileName);
2165 else if (
isPGM(aFileName))
2167 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2168 "Loading PGM files is not implemented, " 2169 "please contact Dr FP Vidal.");
2171 else if (
isRAW(aFileName))
2173 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2174 "Loading RAW files is not implemented, " 2175 "please contact Dr FP Vidal.");
2177 else if (
isMHD(aFileName))
2181 else if (
isMHA(aFileName))
2185 else if (
isDCM(aFileName))
2187 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2188 "Loading DICOM files is not implemented, " 2189 "please contact Dr FP Vidal.");
2191 else if (
isTIFF(aFileName))
2193 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2194 "Loading TIFF files is not implemented, " 2195 "please contact Dr FP Vidal.");
2197 else if (
isJPEG(aFileName))
2199 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2200 "Loading JPEG files is not implemented, " 2201 "please contact Dr FP Vidal.");
2205 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2206 "Unknown file format, to get it added to the library, " 2207 "please contact Dr FP Vidal.");
2217 load(aFileName.data());
2228 typedef T PixelType;
2229 const unsigned int Dimension = 3;
2231 typedef itk::Image< PixelType, Dimension > ImageType;
2232 typedef itk::ImageFileReader < ImageType > ReaderType;
2235 typename ReaderType::Pointer p_reader(ReaderType::New());
2236 p_reader->SetFileName(aFileName);
2240 typename ImageType::RegionType region(p_reader->GetOutput()->GetLargestPossibleRegion());
2241 typename ImageType::SizeType size(region.GetSize());
2245 m_number_of_slices = size[2];
2247 const typename ImageType::SpacingType spacing(p_reader->GetOutput()->GetSpacing());
2248 m_spacing[0] = spacing[0];
2249 m_spacing[1] = spacing[1];
2250 m_spacing[2] = spacing[2];
2255 delete [] m_p_image;
2260 int number_of_pixels(m_width * m_height * m_number_of_slices);
2261 m_p_image =
new T[number_of_pixels];
2264 std::copy(p_reader->GetOutput()->GetBufferPointer(),
2265 p_reader->GetOutput()->GetBufferPointer() + number_of_pixels,
2269 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2270 "ITK is not supported.");
2280 loadUsingITK(aFileName.data());
2286 int aFirstSliceIndex,
2287 int aLastSliceIndex,
2288 int anIncrementIndex)
2294 typedef T PixelType;
2295 const unsigned int Dimension = 3;
2297 typedef itk::Image< PixelType, Dimension > ImageType;
2298 typedef itk::ImageSeriesReader< ImageType > ReaderType;
2299 typedef itk::NumericSeriesFileNames NameGeneratorType;
2302 NameGeneratorType::Pointer p_name_generator(NameGeneratorType::New());
2304 p_name_generator->SetSeriesFormat(aPattern);
2305 p_name_generator->SetStartIndex(aFirstSliceIndex);
2306 p_name_generator->SetEndIndex(aLastSliceIndex);
2307 p_name_generator->SetIncrementIndex(anIncrementIndex);
2308 std::vector<std::string> p_name_set(p_name_generator->GetFileNames());
2311 typename ReaderType::Pointer p_reader(ReaderType::New());
2312 p_reader->SetFileNames(p_name_set);
2316 typename ImageType::RegionType region(p_reader->GetOutput()->GetLargestPossibleRegion());
2317 typename ImageType::SizeType size(region.GetSize());
2321 m_number_of_slices = size[2];
2323 const typename ImageType::SpacingType spacing(p_reader->GetOutput()->GetSpacing());
2324 m_spacing[0] = spacing[0];
2325 m_spacing[1] = spacing[1];
2326 m_spacing[2] = spacing[2];
2331 delete [] m_p_image;
2336 int number_of_pixels(m_width * m_height * m_number_of_slices);
2337 m_p_image =
new T[number_of_pixels];
2340 std::copy(p_reader->GetOutput()->GetBufferPointer(),
2341 p_reader->GetOutput()->GetBufferPointer() + number_of_pixels,
2345 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2346 "ITK is not supported.");
2353 int aFirstSliceIndex,
2354 int aLastSliceIndex,
2355 int anIncrementIndex)
2358 loadSeries(aPattern.data(), aFirstSliceIndex, aLastSliceIndex, anIncrementIndex);
2369 typedef T PixelType;
2370 const unsigned int Dimension = 3;
2372 typedef itk::Image< PixelType, Dimension > ImageType;
2373 typedef itk::ImageSeriesReader< ImageType > ReaderType;
2374 typedef itk::GDCMSeriesFileNames InputNamesGeneratorType;
2377 InputNamesGeneratorType::Pointer p_name_generator(InputNamesGeneratorType::New());
2378 p_name_generator->SetInputDirectory(aDirectory);
2379 const typename ReaderType::FileNamesContainer& p_name_set(p_name_generator->GetInputFileNames());
2382 typename ReaderType::Pointer p_reader(ReaderType::New());
2383 p_reader->SetFileNames(p_name_set);
2387 typename ImageType::RegionType region(p_reader->GetOutput()->GetLargestPossibleRegion());
2388 typename ImageType::SizeType size(region.GetSize());
2392 m_number_of_slices = size[2];
2394 const typename ImageType::SpacingType spacing(p_reader->GetOutput()->GetSpacing());
2395 m_spacing[0] = spacing[0];
2396 m_spacing[1] = spacing[1];
2397 m_spacing[2] = spacing[2];
2402 delete [] m_p_image;
2407 int number_of_pixels(m_width * m_height * m_number_of_slices);
2408 m_p_image =
new T[number_of_pixels];
2411 std::copy(p_reader->GetOutput()->GetBufferPointer(),
2412 p_reader->GetOutput()->GetBufferPointer() + number_of_pixels,
2416 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2417 "ITK is not supported.");
2426 loadDicomSeries(aDirectory.data());
2433 bool anInvertLUTFlag,
2434 const char* aComment,
2435 bool useDeflateCompressionIfPossible)
const 2438 bool image_saved =
false;
2442 saveASCII(aFileName);
2446 else if (
isPGM(aFileName))
2452 else if (
isRAW(aFileName))
2454 saveRAW(aFileName, useDeflateCompressionIfPossible);
2458 else if (
isMHD(aFileName))
2460 saveMHD(aFileName, useDeflateCompressionIfPossible);
2464 else if (
isMHA(aFileName))
2466 saveMHA(aFileName, useDeflateCompressionIfPossible);
2471 else if (
isTIFF(aFileName))
2473 saveTIFF(aFileName, anInvertLUTFlag);
2479 else if (
isJPEG(aFileName))
2481 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2482 "Saving JPEG files is not implemented, " 2483 "please contact Dr FP Vidal.");
2489 else if (
isDCM(aFileName))
2491 saveDCM(aFileName, anInvertLUTFlag, aComment);
2499 saveUsingITK(aFileName, useDeflateCompressionIfPossible);
2506 throw Exception(__FILE__, __FUNCTION__, __LINE__,
2507 "Unknown file format, to get it added to the library, " 2508 "please contact Dr FP Vidal.");
2517 loadMHD(aFileName.data());
2526 loadMetaHeader(aFileName);
2534 loadMHA(aFileName.data());
2543 loadMetaHeader(aFileName);
2549 unsigned int aWidth,
2550 unsigned int aHeight,
2551 unsigned int aNumberOfSlices,
2552 bool aChangeEndianessFlag,
2553 const char* anElementType)
2560 std::ifstream input(aFileName, std::ios::binary|std::ios::in );
2563 if (!input.is_open())
2569 loadRAW(input, aWidth, aHeight, aNumberOfSlices, aChangeEndianessFlag, aFileName, anElementType);
2574 unsigned int aWidth,
2575 unsigned int aHeight,
2576 unsigned int aNumberOfSlices,
2577 bool aChangeEndianessFlag,
2578 const std::string& anElementType)
2581 loadRAW(aFileName.data(), aWidth, aHeight, aNumberOfSlices, aChangeEndianessFlag, anElementType.data());
2587 bool anInvertLUTFlag,
2588 const std::string& aComment,
2589 bool useDeflateCompressionIfPossible)
const 2592 save(aFileName.data(), anInvertLUTFlag, aComment.data());
2601 std::ofstream output_file(aFileName);
2604 if (!output_file.is_open())
2607 std::stringstream error_message;
2608 error_message <<
"Cannot create the file \"" << aFileName <<
"\"";
2611 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message.str());
2617 T min_value(getMinValue());
2618 T max_value(getMaxValue());
2619 T range_value(max_value - min_value);
2622 output_file <<
"P2" << std::endl;
2625 output_file <<
"gVirtualXRay" << std::endl;
2628 output_file << m_width <<
" " << m_height * m_number_of_slices << std::endl;
2631 output_file <<
"65535" << std::endl;
2634 for (
unsigned int k = 0; k < m_number_of_slices; ++k)
2636 for (
unsigned int j = 0; j < m_height; ++j)
2639 for (
unsigned int i = 0; i < m_width; ++i)
2643 if (
typeid(T) ==
typeid(
unsigned char))
2645 pixel_value = m_p_image[k * m_width * m_height + j * m_width + i];
2649 pixel_value = 65535.0 * (m_p_image[k * m_width * m_height + j * m_width + i] - min_value) / range_value;
2652 pixel_value = std::max(0, pixel_value);
2653 pixel_value = std::min(65535, pixel_value);
2655 output_file << pixel_value;
2658 if (i < (m_width - 1))
2665 if (j < (m_height - 1))
2667 output_file << std::endl;
2679 savePGM(aFileName.data());
2684 template<
typename T>
void Image<T>::saveRaw(
const char* aFileName,
bool useDeflateCompressionIfPossible)
const 2688 if (!useDeflateCompressionIfPossible)
2690 std::ofstream output_file (aFileName, std::ifstream::binary);
2693 if (!output_file.is_open())
2695 std::string error_message(
"The file (");
2696 error_message += aFileName;
2697 error_message +=
") cannot be created";
2699 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2703 output_file.write(reinterpret_cast<char*>(m_p_image), m_width * m_height * m_number_of_slices *
sizeof(T));
2707 gzFile output_file = gzopen(aFileName,
"wb");
2712 std::string error_message(
"The file (");
2713 error_message += aFileName;
2714 error_message +=
") cannot be created";
2716 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2719 int write_size = gzwrite( output_file, reinterpret_cast<char*>(m_p_image), m_width * m_height * m_number_of_slices *
sizeof(T));
2720 int close_err = gzclose( output_file );
2722 if (write_size == 0)
2724 std::string error_message(
"The file (");
2725 error_message += aFileName;
2726 error_message +=
") cannot be written";
2728 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2731 if (close_err == Z_STREAM_ERROR)
2733 std::string error_message(
"The file (");
2734 error_message += aFileName;
2735 error_message +=
") is not valid";
2737 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2740 if (close_err == Z_ERRNO)
2742 std::string error_message(
"File operation error on the file (");
2743 error_message += aFileName;
2744 error_message +=
").";
2746 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2749 if (close_err == Z_MEM_ERROR)
2751 std::string error_message(
"File operation error on the file (");
2752 error_message += aFileName;
2753 error_message +=
").";
2758 if (close_err == Z_BUF_ERROR)
2760 std::string error_message(
"The last read ended in the middle of a gzip stream when writing the file (");
2761 error_message += aFileName;
2762 error_message +=
").";
2764 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2767 if (close_err != Z_OK)
2769 std::string error_message(
"Unspecified error when writing the file (");
2770 error_message += aFileName;
2771 error_message +=
").";
2773 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2780 template<
typename T>
void Image<T>::saveRAW(
const char* aFileName,
bool useDeflateCompressionIfPossible)
const 2783 saveRaw(aFileName, useDeflateCompressionIfPossible);
2789 bool useDeflateCompressionIfPossible)
const 2792 saveRaw(aFileName.data(), useDeflateCompressionIfPossible);
2797 template<
typename T>
void Image<T>::saveRAW(
const std::string& aFileName,
bool useDeflateCompressionIfPossible)
const 2800 saveRaw(aFileName, useDeflateCompressionIfPossible);
2809 std::ofstream output_file (aFileName);
2812 if (!output_file.is_open())
2814 std::string error_message(
"The file (");
2815 error_message += aFileName;
2816 error_message +=
") cannot be created";
2818 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
2822 T* p_data(m_p_image);
2823 for (
unsigned int k = 0; k < m_number_of_slices; ++k)
2825 for (
unsigned int j(0); j < m_height; ++j)
2827 for (
unsigned int i(0); i < m_width; ++i)
2829 output_file << *p_data++;
2832 if (i < m_width - 1)
2839 if (j < m_height - 1 || k < m_number_of_slices - 1)
2841 output_file << std::endl;
2852 saveASCII(aFileName.data());
2857 template<
typename T>
void Image<T>::saveMHD(
const char* aFileName,
bool useDeflateCompressionIfPossible)
const 2861 saveMetaHeader(aFileName, useDeflateCompressionIfPossible);
2865 template<
typename T>
void Image<T>::saveMHD(
const std::string& aFileName,
bool useDeflateCompressionIfPossible)
const 2867 saveMHD(aFileName.data(), useDeflateCompressionIfPossible);
2871 template<
typename T>
void Image<T>::saveMHA(
const char* aFileName,
bool useDeflateCompressionIfPossible)
const 2873 saveMetaHeader(aFileName, useDeflateCompressionIfPossible);
2877 template<
typename T>
void Image<T>::saveMHA(
const std::string& aFileName,
bool useDeflateCompressionIfPossible)
const 2879 saveMHA(aFileName.data(), useDeflateCompressionIfPossible);
2885 bool anInvertLUTFlag,
2886 const char* aComment)
const 2890 T min_input_value(getMinValue());
2891 T max_input_value(getMaxValue());
2892 T difference_input(max_input_value - min_input_value);
2894 unsigned short min_output_value(((gdcm::PixelFormat)gdcm::PixelFormat::UINT16).GetMin());
2895 unsigned short max_output_value(((gdcm::PixelFormat)gdcm::PixelFormat::UINT16).GetMax());
2896 unsigned short difference_output(max_output_value - min_output_value);
2898 double shift(min_input_value);
2899 double scale(
double(max_input_value - min_input_value) / max_output_value);
2901 if (m_number_of_slices == 1)
2904 gdcm::ImageWriter writer;
2909 gdcm::Image& gdcm_image(writer.GetImage());
2912 unsigned int dims[3] = {};
2916 double spacing[3] = {};
2917 spacing[0] = m_spacing[0];
2918 spacing[1] = m_spacing[1];
2920 if (m_number_of_slices == 1)
2922 gdcm_image.SetNumberOfDimensions(2);
2926 dims[2] = m_number_of_slices;
2927 gdcm_image.SetNumberOfDimensions(3);
2932 gdcm_image.SetSpacing (spacing);
2934 gdcm_image.SetDimensions( dims );
2937 unsigned short* p_temp(
new unsigned short[m_width * m_height * m_number_of_slices]);
2940 #pragma omp parallel for 2942 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
2944 p_temp[i] = min_output_value + difference_output * (double(m_p_image[i] - min_input_value) / double(difference_input));
2947 unsigned int input_length(m_width * m_height * m_number_of_slices *
sizeof(T));
2948 unsigned int output_length(m_width * m_height * m_number_of_slices *
sizeof(
unsigned short));
2950 gdcm::PixelFormat input_pixel_format(gdcm::PixelFormat::UINT16);
2951 input_pixel_format.SetSamplesPerPixel(1);
2953 gdcm_image.SetSlope(scale);
2954 gdcm_image.SetIntercept(shift);
2957 gdcm_image.SetPixelFormat(input_pixel_format);
2958 gdcm::PhotometricInterpretation photometric_interpretation;
2960 if (anInvertLUTFlag)
2962 photometric_interpretation = gdcm::PhotometricInterpretation::MONOCHROME2;
2966 photometric_interpretation = gdcm::PhotometricInterpretation::MONOCHROME1;
2968 gdcm_image.SetPhotometricInterpretation(photometric_interpretation);
2969 gdcm_image.SetTransferSyntax(gdcm::TransferSyntax::ExplicitVRLittleEndian);
2974 gdcm_image.SetLossyFlag(
false);
2978 addTag(difference_input,
2982 addTag(min_input_value + difference_input / 2.0,
2987 addTag(
"X-ray simulation",
3002 addTag(
"gVirtualXRay",
3007 addTag(
"Bangor University",
3012 addTag(
"http://gvirtualxray.sourceforge.net/",
3021 gdcm::DataElement pixel_data(gdcm::Tag(0x7fe0,0x0010));
3022 pixel_data.SetByteValue((
const char*)p_temp, uint32_t(output_length));
3023 gdcm_image.SetDataElement(pixel_data);
3026 writer.SetFileName( aFileName );
3029 if( !writer.Write() )
3034 std::string error_message(
"Could not write the DICOM file (");
3035 error_message += aFileName;
3036 error_message +=
")";
3037 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3045 throw Exception(__FILE__, __FUNCTION__, __LINE__,
3046 "Saving DICOM files is not implemented, " 3047 "please contact Dr FP Vidal.");
3055 bool anInvertLUTFlag,
3056 const std::string& aComment)
const 3059 saveDCM(aFileName.data(), anInvertLUTFlag, aComment.data());
3065 bool anInvertLUTFlag)
const 3070 float* p_float_data(0);
3071 unsigned int number_of_pixels(m_width * m_height);
3076 if (
typeid(T) ==
typeid(
char) ||
typeid(T) ==
typeid(
unsigned char))
3078 number_of_bits_per_pixel = 8;
3080 else if (
typeid(T) ==
typeid(
short) ||
typeid(T) ==
typeid(
unsigned short))
3082 number_of_bits_per_pixel = 16;
3084 else if (
typeid(T) ==
typeid(
float))
3086 number_of_bits_per_pixel = 32;
3090 number_of_bits_per_pixel = 32;
3091 p_float_data =
new float[number_of_pixels];
3095 TIFF* p_file = TIFFOpen(aFileName,
"w");
3100 std::string error_message(
"The file (");
3101 error_message += aFileName;
3102 error_message +=
") cannot be created";
3104 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3108 for (
unsigned int k(0); k < m_number_of_slices; k++)
3111 T min_value(getMinValue(k));
3112 T max_value(getMaxValue(k));
3113 T value_range(max_value - min_value);
3119 #pragma omp parallel for 3121 for (
int i = 0; i < number_of_pixels; ++i)
3123 float temp(
double(m_p_image[k * m_width * m_height + i] - min_value) / value_range);
3124 p_float_data[i] = temp;
3129 if (m_number_of_slices > 1)
3131 if (TIFFWriteDirectory(p_file) != 1)
3133 std::string error_message(
"Could not write the new directory in the TIFF file (");
3134 error_message += aFileName;
3135 error_message +=
")";
3136 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3143 if (TIFFSetField(p_file, TIFFTAG_IMAGEWIDTH, image_width) != 1)
3145 std::string error_message(
"Could not set the image width in the TIFF file (");
3146 error_message += aFileName;
3147 error_message +=
")";
3148 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3154 if (TIFFSetField(p_file, TIFFTAG_IMAGELENGTH, image_height) != 1)
3156 std::string error_message(
"Could not set the image height in the TIFF file (");
3157 error_message += aFileName;
3158 error_message +=
")";
3159 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3163 if (TIFFSetField(p_file, TIFFTAG_BITSPERSAMPLE, number_of_bits_per_pixel) != 1)
3165 std::string error_message(
"Could not set the number of bits per pixel in the TIFF file (");
3166 error_message += aFileName;
3167 error_message +=
")";
3168 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3174 if (TIFFSetField(p_file, TIFFTAG_COMPRESSION, compression) != 1)
3176 std::string error_message(
"Could not set the compression in the TIFF file (");
3177 error_message += aFileName;
3178 error_message +=
")";
3179 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3184 if (anInvertLUTFlag)
3186 photometric_interpretation = PHOTOMETRIC_MINISWHITE;
3190 photometric_interpretation = PHOTOMETRIC_MINISBLACK;
3193 if (TIFFSetField(p_file, TIFFTAG_PHOTOMETRIC, photometric_interpretation) != 1)
3195 std::string error_message(
"Could not set the photometric interpretation in the TIFF file (");
3196 error_message += aFileName;
3197 error_message +=
")";
3198 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3204 if (TIFFSetField(p_file, TIFFTAG_ORIENTATION, orientation) != 1)
3206 std::string error_message(
"Could not set the orientation in the TIFF file (");
3207 error_message += aFileName;
3208 error_message +=
")";
3209 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3215 if (TIFFSetField(p_file, TIFFTAG_SAMPLESPERPIXEL, number_of_samples_per_pixel) != 1)
3217 std::string error_message(
"Could not set the number of samples per pixel in the TIFF file (");
3218 error_message += aFileName;
3219 error_message +=
")";
3220 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3224 if (TIFFSetField(p_file, TIFFTAG_MINSAMPLEVALUE, min_value) != 1)
3226 std::string error_message(
"Could not set the min sample value in the TIFF file (");
3227 error_message += aFileName;
3228 error_message +=
")";
3229 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3233 if (TIFFSetField(p_file, TIFFTAG_MAXSAMPLEVALUE, max_value) != 1)
3235 std::string error_message(
"Could not set the max sample value in the TIFF file (");
3236 error_message += aFileName;
3237 error_message +=
")";
3238 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3244 if (TIFFSetField(p_file, TIFFTAG_PLANARCONFIG, planar_configuration) != 1)
3246 std::string error_message(
"Could not set the planar configuration in the TIFF file (");
3247 error_message += aFileName;
3248 error_message +=
")";
3249 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3252 std::string software;
3253 software +=
"gVirtualXRay-";
3260 if (TIFFSetField(p_file, TIFFTAG_COPYRIGHT, software.data()) != 1)
3262 std::string error_message(
"Could not set the software value in the TIFF file (");
3263 error_message += aFileName;
3264 error_message +=
")";
3265 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3271 if (
typeid(T) ==
typeid(
unsigned char) ||
typeid(T) ==
typeid(
unsigned short))
3273 format_of_a_sample = SAMPLEFORMAT_UINT;
3275 else if (
typeid(T) ==
typeid(
char) ||
typeid(T) ==
typeid(
short))
3277 format_of_a_sample = SAMPLEFORMAT_INT;
3281 format_of_a_sample = SAMPLEFORMAT_IEEEFP;
3284 if (TIFFSetField(p_file, TIFFTAG_SAMPLEFORMAT, format_of_a_sample) != 1)
3286 std::string error_message(
"Could not set the compression in the TIFF file (");
3287 error_message += aFileName;
3288 error_message +=
")";
3289 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3293 tsize_t number_of_bytes_per_line(number_of_samples_per_pixel * m_width);
3296 TIFFSetField(p_file, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(p_file, number_of_bytes_per_line));
3301 for (
unsigned int j(0); j < m_height; ++j)
3305 error_code = TIFFWriteScanline(p_file, p_float_data + m_width * j, j, 0);
3309 error_code = TIFFWriteScanline(p_file, m_p_image + m_width * m_height * k + m_width * j, j, 0);
3312 if (error_code != 1)
3320 delete [] p_float_data;
3325 std::stringstream error_message;
3326 error_message <<
"Could not write the pixel data (Line " << j <<
") in the TIFF file (";
3327 error_message << aFileName;
3328 error_message <<
")";
3329 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message.str());
3334 if (m_number_of_slices > 1)
3336 if (TIFFFlush(p_file) != 1)
3338 std::string error_message(
"Could not flush the data in the TIFF file (");
3339 error_message += aFileName;
3340 error_message +=
")";
3341 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
3349 delete [] p_float_data;
3358 throw Exception(__FILE__, __FUNCTION__, __LINE__,
3359 "Saving TIFF files is not implemented, " 3360 "please contact Dr FP Vidal.");
3368 bool anInvertLUTFlag)
const 3371 saveTIFF(aFileName.data(), anInvertLUTFlag);
3377 bool useDeflateCompressionIfPossible)
const 3382 if (m_number_of_slices > 1 ||
isDCM(aFileName))
3384 typedef itk::Image< T, 3 > InputImageType;
3386 typename InputImageType::RegionType region;
3387 typename InputImageType::IndexType start;
3392 typename InputImageType::SizeType size;
3395 size[2] = m_number_of_slices;
3397 region.SetSize(size);
3398 region.SetIndex(start);
3400 typename InputImageType::Pointer p_image(InputImageType::New());
3401 p_image->SetRegions(region);
3402 p_image->Allocate();
3405 typename InputImageType::SpacingType spacing;
3406 spacing[0] = m_spacing[0];
3407 spacing[1] = m_spacing[1];
3408 spacing[2] = m_spacing[2];
3409 p_image->SetSpacing(spacing);
3412 int number_of_pixels(m_width * m_height * m_number_of_slices);
3413 std::copy(m_p_image,
3414 m_p_image + number_of_pixels,
3415 p_image->GetBufferPointer());
3418 if (
isDCM(aFileName))
3420 typedef itk::Image< short, 3 > ShortImageType;
3421 typedef itk::ImageFileWriter< ShortImageType > ShortWriterType;
3423 typedef itk::RescaleIntensityImageFilter< InputImageType, ShortImageType > RescaleType;
3424 typename RescaleType::Pointer rescale = RescaleType::New();
3425 rescale->SetInput( p_image );
3428 typename ShortWriterType::Pointer p_writer(ShortWriterType::New());
3429 p_writer->SetFileName( aFileName );
3430 p_writer->SetInput( rescale->GetOutput() );
3431 p_writer->SetUseCompression(useDeflateCompressionIfPossible);
3437 typedef itk::ImageFileWriter< InputImageType > InputWriterType;
3438 typename InputWriterType::Pointer p_writer(InputWriterType::New());
3439 p_writer->SetFileName( aFileName );
3440 p_writer->SetInput( p_image );
3441 p_writer->SetUseCompression(useDeflateCompressionIfPossible);
3448 typedef itk::Image< T, 2 > InputImageType;
3450 typename InputImageType::RegionType region;
3451 typename InputImageType::IndexType start;
3455 typename InputImageType::SizeType size;
3459 region.SetSize(size);
3460 region.SetIndex(start);
3462 typename InputImageType::Pointer p_image(InputImageType::New());
3463 p_image->SetRegions(region);
3464 p_image->Allocate();
3467 typename InputImageType::SpacingType spacing;
3468 spacing[0] = m_spacing[0];
3469 spacing[1] = m_spacing[1];
3470 p_image->SetSpacing(spacing);
3473 int number_of_pixels(m_width * m_height);
3474 std::copy(m_p_image,
3475 m_p_image + number_of_pixels,
3476 p_image->GetBufferPointer());
3484 typedef itk::Image< unsigned char, 2 > UByteImageType;
3485 typedef itk::ImageFileWriter< UByteImageType > UByteWriterType;
3487 typedef itk::RescaleIntensityImageFilter< InputImageType, UByteImageType > RescaleType;
3488 typename RescaleType::Pointer rescale = RescaleType::New();
3489 rescale->SetInput( p_image );
3490 rescale->SetOutputMinimum( 0 );
3491 rescale->SetOutputMaximum( 255 );
3494 typename UByteWriterType::Pointer p_writer(UByteWriterType::New());
3495 p_writer->SetFileName( aFileName );
3496 p_writer->SetInput( rescale->GetOutput() );
3497 p_writer->SetUseCompression(useDeflateCompressionIfPossible);
3503 typedef itk::ImageFileWriter< InputImageType > InputWriterType;
3504 typename InputWriterType::Pointer p_writer(InputWriterType::New());
3505 p_writer->SetFileName( aFileName );
3506 p_writer->SetInput( p_image );
3507 p_writer->SetUseCompression(useDeflateCompressionIfPossible);
3512 throw Exception(__FILE__, __FUNCTION__, __LINE__,
3513 "ITK is not supported.");
3520 bool useDeflateCompressionIfPossible)
const 3523 saveUsingITK(aFileName.data(), useDeflateCompressionIfPossible);
3531 if (m_width != anImage.m_width)
3536 if (m_height != anImage.m_height)
3541 if (m_number_of_slices != anImage.m_number_of_slices)
3546 T
const * p_data1(m_p_image);
3547 T
const * p_data2(anImage.m_p_image);
3548 for (
unsigned int i(0); i < m_width * m_height * m_number_of_slices; ++i)
3564 return (!(
operator==(anImage)));
3575 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Empty image");
3578 return (std::accumulate(&m_p_image[0],
3579 &m_p_image[m_width * m_height * m_number_of_slices],
3588 return (getSum() / (m_width * m_height));
3596 double variance(0.0);
3597 double average(getAverage());
3600 #pragma omp parallel for reduction( + : variance ) 3602 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
3604 variance += std::pow(m_p_image[i] - average, 2);
3607 return (variance / (m_width * m_height));
3615 return (std::sqrt(getVariance()));
3623 if (m_width != anImage.m_width || m_height != anImage.m_height || m_number_of_slices != anImage.m_number_of_slices)
3625 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"The images have different sizes");
3631 #pragma omp parallel for reduction( + : sae ) 3633 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
3635 sae +=
std::abs(m_p_image[i] - anImage.m_p_image[i]);
3646 return (computeSAE(anImage) /
double(m_width * m_height * m_number_of_slices));
3654 if (m_width != anImage.m_width || m_height != anImage.m_height || m_number_of_slices != anImage.m_number_of_slices)
3656 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"The images have different sizes");
3663 #pragma omp parallel for reduction( + : sse ) private(temp) 3665 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
3667 temp = m_p_image[i] - anImage.m_p_image[i];
3681 return (computeSSE(anImage) /
double(m_width * m_height * m_number_of_slices));
3689 return (std::sqrt(computeMSE(anImage) /
double(m_width * m_height * m_number_of_slices)));
3697 if (m_width != anImage.m_width || m_height != anImage.m_height || m_number_of_slices != anImage.m_number_of_slices)
3699 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"The images have different sizes");
3702 double average1(getAverage());
3703 double average2(anImage.getAverage());
3705 double standard_deviation_product(getStandardDeviation() * anImage.getStandardDeviation());
3709 #pragma omp parallel for reduction( + : ncc ) 3711 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
3713 ncc += (m_p_image[i] - average1) * (anImage.m_p_image[i] - average2);
3716 return (ncc / (m_width * m_height * standard_deviation_product));
3729 Image<T> temp(m_height, m_width, m_number_of_slices);
3734 #pragma omp parallel for 3736 #pragma omp parallel for collapse(3) 3739 for (
int k = 0; k < m_number_of_slices; ++k)
3741 for (
int j = 0; j < m_height; ++j)
3743 for (
int i = 0; i < m_width; ++i)
3745 temp(j, i, k) = getPixel(i, j, k);
3757 unsigned int anAddress1,
3758 unsigned int anAddress2,
3759 gdcm::File& aFile)
const 3762 std::stringstream message;
3765 addTag(message.str(), anAddress1, anAddress2, aFile);
3770 template<
typename T>
void Image<T>::addTag(
const char* aValue,
3771 unsigned int anAddress1,
3772 unsigned int anAddress2,
3773 gdcm::File& aFile)
const 3776 std::stringstream message;
3779 addTag(std::string(aValue), anAddress1, anAddress2, aFile);
3784 template<
typename T>
void Image<T>::addTag(
const std::string& aValue,
3785 unsigned int anAddress1,
3786 unsigned int anAddress2,
3787 gdcm::File& aFile)
const 3790 gdcm::DataElement data_element(gdcm::Tag(anAddress1, anAddress2));
3793 data_element.SetByteValue((
const char*)aValue.data(), uint32_t(aValue.size()));
3795 aFile.GetDataSet().Insert(data_element);
3805 unsigned int min_width( std::min(m_width, anImage.m_width));
3806 unsigned int min_height(std::min(m_height, anImage.m_height));
3807 unsigned int min_depth( std::min(m_number_of_slices, anImage.m_number_of_slices));
3810 Image<T> temp(getROI(0, 0, 0, min_width, min_height, min_depth));
3816 #pragma omp parallel for 3818 #pragma omp parallel for collapse(3) 3821 for (
int k = 0; k < min_depth; ++k)
3823 for (
int j = 0; j < min_height; ++j)
3825 for (
int i = 0; i < min_width; ++i)
3827 temp(i, j, k) += anImage(i, j, k);
3842 unsigned int min_width( std::min(m_width, anImage.m_width));
3843 unsigned int min_height(std::min(m_height, anImage.m_height));
3844 unsigned int min_depth( std::min(m_number_of_slices, anImage.m_number_of_slices));
3847 Image<T> temp(getROI(0, 0, 0, min_width, min_height, min_depth));
3853 #pragma omp parallel for 3855 #pragma omp parallel for collapse(3) 3858 for (
int k = 0; k < min_depth; ++k)
3860 for (
int j = 0; j < min_height; ++j)
3862 for (
int i = 0; i < min_width; ++i)
3864 temp(i, j, k) -= anImage(i, j, k);
3879 unsigned int min_width( std::min(m_width, anImage.m_width));
3880 unsigned int min_height(std::min(m_height, anImage.m_height));
3881 unsigned int min_depth( std::min(m_number_of_slices, anImage.m_number_of_slices));
3884 Image<T> temp(getROI(0, 0, 0, min_width, min_height, min_depth));
3890 #pragma omp parallel for 3892 #pragma omp parallel for collapse(3) 3895 for (
int k = 0; k < min_depth; ++k)
3897 for (
int j = 0; j < min_height; ++j)
3899 for (
int i = 0; i < min_width; ++i)
3901 temp(i, j, k) *= anImage(i, j, k);
3916 unsigned int min_width( std::min(m_width, anImage.m_width));
3917 unsigned int min_height(std::min(m_height, anImage.m_height));
3918 unsigned int min_depth( std::min(m_number_of_slices, anImage.m_number_of_slices));
3921 Image<T> temp(getROI(0, 0, 0, min_width, min_height, min_depth));
3927 for (
unsigned int k = 0; k < min_depth; ++k)
3929 for (
unsigned int j = 0; j < min_height; ++j)
3931 for (
unsigned int i = 0; i < min_width; ++i)
3933 double pixel_value(anImage(i, j, k));
3937 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Division by zero.");
3941 temp(i, j, k) /= pixel_value;
3957 *
this = *
this + anImage;
3969 *
this = *
this - anImage;
3981 *
this = *
this * anImage;
3993 *
this = *
this / anImage;
4009 #pragma omp parallel for 4011 for (
unsigned int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4030 #pragma omp parallel for 4032 for (
unsigned int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4051 #pragma omp parallel for 4053 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4070 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Division by zero.");
4078 #pragma omp parallel for 4080 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4095 #pragma omp parallel for 4097 for (
unsigned int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4099 m_p_image[i] += aValue;
4112 #pragma omp parallel for 4114 for (
unsigned int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4116 m_p_image[i] -= aValue;
4129 #pragma omp parallel for 4131 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4133 m_p_image[i] *= aValue;
4148 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Division by zero.");
4152 #pragma omp parallel for 4154 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
4156 m_p_image[i] /= aValue;
4172 T min_value(getMinValue());
4173 T max_value(getMaxValue());
4174 T range(max_value - min_value);
4178 #pragma omp parallel for 4180 for (
unsigned int i = 0;
4181 i < m_width * m_height * m_number_of_slices;
4185 temp.
m_p_image[i] = min_value + range * (1.0 - (m_p_image[i] - min_value) / range);
4195 unsigned int aNewHeight,
4196 unsigned int aNewNumberOfSlices)
const 4199 Image<T> temp(aNewWidth, aNewHeight, aNewNumberOfSlices);
4202 int x_offset((
int(aNewWidth) -
int(m_width)) / 2);
4203 int y_offset((
int(aNewHeight) -
int(m_height)) / 2);
4204 int z_offset((
int(aNewNumberOfSlices) -
int(m_number_of_slices)) / 2);
4208 #pragma omp parallel for 4210 #pragma omp parallel for collapse(3) 4213 for (
int k = 0; k < m_number_of_slices; ++k)
4215 for (
int j = 0; j < m_height; ++j)
4217 for (
int i = 0; i < m_width; ++i)
4219 if (i + x_offset >= 0 && i + x_offset < aNewWidth &&
4220 j + y_offset >= 0 && j + y_offset < aNewHeight &&
4221 k + z_offset >= 0 && k + z_offset < aNewNumberOfSlices)
4223 temp(i + x_offset, j + y_offset, k + z_offset) = getPixel(i, j, k);
4235 unsigned int aNewHeight,
4236 unsigned int aNewNumberOfSlices)
const 4239 Image temp(aNewWidth, aNewHeight, aNewNumberOfSlices);
4247 #pragma omp parallel for 4249 #pragma omp parallel for collapse(3) 4252 for (
int k = 0; k < aNewNumberOfSlices; ++k)
4254 for (
unsigned j = 0; j < aNewHeight; ++j)
4256 for (
unsigned i = 0; i < aNewWidth; ++i)
4259 double x = double(i) * (m_width - 1) / (aNewWidth - 1);
4260 double y = double(j) * (m_height - 1) / (aNewHeight - 1);
4261 double z = double(k) * (m_number_of_slices - 1) / (aNewNumberOfSlices - 1);
4285 if (z2 >= m_number_of_slices)
4287 z2 = m_number_of_slices - 1;
4292 double c111 = getPixel(x1, y1, z1);
4293 double c121 = getPixel(x1, y2, z1);
4294 double c221 = getPixel(x2, y2, z1);
4295 double c211 = getPixel(x2, y1, z1);
4301 cx11 += (c211 - c111) * (x - x1) / (x2 - x1);
4302 cx21 += (c221 - c121) * (x - x1) / (x2 - x1);
4308 cy1 += (cx21 - cx11) * (y - y1) / (y2 - y1);
4312 double c112 = getPixel(x1, y1, z2);
4313 double c122 = getPixel(x1, y2, z2);
4314 double c222 = getPixel(x2, y2, z2);
4315 double c212 = getPixel(x2, y1, z2);
4321 cx12 += (c212 - c112) * (x - x1) / (x2 - x1);
4322 cx22 += (c222 - c122) * (x - x1) / (x2 - x1);
4328 cy2 += (cx22 - cx12) * (y - y1) / (y2 - y1);
4334 cz += (cy2 - cy1) * (z - z1) / (z2 - z1);
4350 Image<T> temp(m_width, m_height, m_number_of_slices);
4353 float angle_in_radian(anAngleInDegrees *
Pi / 180);
4360 #pragma omp parallel for 4362 #pragma omp parallel for collapse(3) 4365 for (
int k = 0; k < m_number_of_slices; ++k)
4367 for (
unsigned j = 0; j < m_height; ++j)
4369 for (
unsigned i = 0; i < m_width; ++i)
4377 temp_x -= (m_width - 1.0) / 2.0;
4378 temp_y -= (m_height - 1.0) / 2.0;
4380 double x = temp_x * std::cos(angle_in_radian) + temp_y * std::sin(angle_in_radian);
4381 double y = temp_y * std::cos(angle_in_radian) - temp_x * std::sin(angle_in_radian);
4383 x += (m_width - 1.0) / 2.0;
4384 y += (m_height - 1.0) / 2.0;
4392 if (x1 >= 0 && x1 < m_width &&
4393 y1 >= 0 && y1 < m_height)
4395 temp(i, j, k) = getPixel(x1, y1, k);
4397 if (x2 >= 0 && x2 < m_width &&
4398 y2 >= 0 && y2 < m_height)
4400 double c11 = getPixel(x1, y1, k);
4401 double c12 = getPixel(x1, y2, k);
4402 double c22 = getPixel(x2, y2, k);
4403 double c21 = getPixel(x2, y1, k);
4405 double cx1 = c11 + (c21 - c11) * (x -
double(x1)) /
double(x2 - x1);
4406 double cx2 = c12 + (c22 - c12) * (x -
double(x1)) /
double(x2 - x1);
4408 double cy = cx1 + (cx2 - cx1) *
double(y - y1) / double(y2 - y1);
4424 double aLastAngle)
const 4427 unsigned int square_width(4 + std::max(m_width, m_height));
4428 square_width *= square_width;
4430 unsigned int sinogram_width(floor(std::sqrt(2.0 * square_width)));
4434 unsigned int sinogram_height(1);
4437 sinogram_height += floor((aLastAngle - aFirstAngle) / anAngleStep);
4440 double scaling_factor(
double(sinogram_width) /
double(m_width));
4442 Sinogram<T> sinogram(sinogram_width, sinogram_height, m_number_of_slices);
4444 Image<T> padded_image(setCanvasSize(sinogram_width, scaling_factor * m_height, m_number_of_slices));
4447 padded_image.
save(
"padded.mhd");
4450 double angle(aFirstAngle);
4452 for (
unsigned int angle_id(0); angle_id < sinogram_height; ++angle_id, angle += anAngleStep)
4457 std::stringstream file_name;
4458 file_name <<
"rotated_" << angle <<
".mhd";
4459 rotated_image.
save(file_name.str());
4465 #pragma omp parallel for 4467 #pragma omp parallel for collapse(3) 4470 for (
int j = 0; j < rotated_image.m_height; ++j)
4472 for (
int i = 0; i < rotated_image.m_width; ++i)
4474 for (
int k = 0; k < m_number_of_slices; ++k)
4476 sinogram(i, angle_id, k) += rotated_image(i, j, k);
4483 std::stringstream file_name;
4484 file_name <<
"sinogram_" << angle <<
".mhd";
4485 sinogram.
save(file_name.str());
4497 const T& aSecondThresholdValue,
4498 bool aTwoThresholdFlag,
4499 unsigned char aVerboseLevel)
const 4506 unsigned char value_in = 255;
4507 unsigned char value_out = 0;
4508 unsigned char iso_value = 128;
4510 if (!aTwoThresholdFlag)
4512 padded_image = this->threshold(aFirstThesholdValue, value_in, value_out).
constantPadFilter(value_out);
4516 padded_image = this->threshold(aFirstThesholdValue, aSecondThresholdValue, value_in, value_out,
true).
constantPadFilter(value_out);
4532 static const float a2fEdgeDirection[12][3] =
4534 {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},
4535 {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},
4536 {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0, 0.0, 1.0}
4540 static const int a2iEdgeConnection[12][2] =
4542 {0,1}, {1,2}, {2,3}, {3,0},
4543 {4,5}, {5,6}, {6,7}, {7,4},
4544 {0,4}, {1,5}, {2,6}, {3,7}
4548 static const unsigned int a2fVertexOffset[8][3] =
4550 {0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0},
4551 {0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1}
4561 static const int aiCubeEdgeFlags[256]=
4563 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
4564 0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
4565 0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
4566 0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
4567 0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
4568 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
4569 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
4570 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
4571 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
4572 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
4573 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
4574 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
4575 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
4576 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
4577 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
4578 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
4589 static const int a2iTriangleConnectionTable[256][16] =
4591 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4592 {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4593 {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4594 {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4595 {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4596 {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4597 {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4598 {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
4599 {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4600 {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4601 {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4602 {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
4603 {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4604 {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
4605 {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
4606 {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4607 {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4608 {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4609 {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4610 {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
4611 {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4612 {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
4613 {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
4614 {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
4615 {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4616 {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
4617 {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
4618 {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
4619 {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
4620 {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
4621 {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
4622 {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
4623 {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4624 {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4625 {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4626 {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
4627 {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4628 {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
4629 {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
4630 {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
4631 {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4632 {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
4633 {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
4634 {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
4635 {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
4636 {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
4637 {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
4638 {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
4639 {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4640 {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
4641 {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
4642 {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4643 {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
4644 {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
4645 {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
4646 {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
4647 {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
4648 {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
4649 {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
4650 {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
4651 {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
4652 {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
4653 {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
4654 {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4655 {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4656 {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4657 {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4658 {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
4659 {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4660 {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
4661 {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
4662 {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
4663 {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4664 {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
4665 {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
4666 {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
4667 {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
4668 {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
4669 {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
4670 {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
4671 {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4672 {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
4673 {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
4674 {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
4675 {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
4676 {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
4677 {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
4678 {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
4679 {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
4680 {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
4681 {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
4682 {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
4683 {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
4684 {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
4685 {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
4686 {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
4687 {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4688 {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
4689 {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
4690 {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
4691 {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
4692 {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
4693 {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4694 {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
4695 {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
4696 {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
4697 {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
4698 {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
4699 {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
4700 {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
4701 {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
4702 {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4703 {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
4704 {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
4705 {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
4706 {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
4707 {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
4708 {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
4709 {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
4710 {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4711 {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
4712 {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
4713 {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
4714 {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
4715 {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
4716 {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4717 {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
4718 {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4719 {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4720 {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4721 {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4722 {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
4723 {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4724 {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
4725 {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
4726 {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
4727 {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4728 {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
4729 {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
4730 {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
4731 {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
4732 {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
4733 {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
4734 {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
4735 {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4736 {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
4737 {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
4738 {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
4739 {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
4740 {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
4741 {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
4742 {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
4743 {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
4744 {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4745 {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
4746 {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
4747 {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
4748 {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
4749 {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
4750 {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4751 {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4752 {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
4753 {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
4754 {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
4755 {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
4756 {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
4757 {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
4758 {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
4759 {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
4760 {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
4761 {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
4762 {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
4763 {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
4764 {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
4765 {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
4766 {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
4767 {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
4768 {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
4769 {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
4770 {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
4771 {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
4772 {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
4773 {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
4774 {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
4775 {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
4776 {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
4777 {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
4778 {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4779 {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
4780 {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
4781 {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4782 {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4783 {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4784 {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
4785 {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
4786 {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
4787 {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
4788 {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
4789 {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
4790 {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
4791 {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
4792 {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
4793 {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
4794 {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
4795 {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4796 {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
4797 {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
4798 {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4799 {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
4800 {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
4801 {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
4802 {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
4803 {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
4804 {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
4805 {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
4806 {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4807 {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
4808 {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
4809 {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
4810 {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
4811 {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
4812 {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4813 {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
4814 {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4815 {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
4816 {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
4817 {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
4818 {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
4819 {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
4820 {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
4821 {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
4822 {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
4823 {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
4824 {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
4825 {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
4826 {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4827 {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
4828 {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
4829 {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4830 {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4831 {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4832 {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
4833 {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
4834 {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4835 {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
4836 {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
4837 {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4838 {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4839 {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
4840 {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4841 {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
4842 {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4843 {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4844 {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4845 {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
4846 {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
4852 unsigned int max_thread(1);
4854 max_thread = omp_get_max_threads();
4857 std::vector<std::vector<float> > p_vertex_set(max_thread);
4858 std::vector<std::vector<float> > p_normal_vector_set(max_thread);
4862 LOGGER.
logNow(
"Create the iso-surface using Marching Cubes") << std::endl;
4864 if (aTwoThresholdFlag)
4870 unsigned int number_of_voxels((padded_image.
getWidth() - 1) * (padded_image.
getHeight() - 1) * (padded_image.
getDepth() - 1));
4871 unsigned int thread_progress = 0;
4875 #pragma omp parallel for 4877 #pragma omp parallel for collapse(3) 4880 for (
int k = 0; k < padded_image.
getDepth() - 1; ++k)
4882 for (
int j = 0; j < padded_image.
getHeight() - 1; ++j)
4884 for (
int i = 0; i < padded_image.
getWidth() - 1; ++i)
4887 int thread_id = omp_get_thread_num();
4899 int number_of_threads = omp_get_num_threads();
4900 unsigned int tasks_per_thread = number_of_voxels / number_of_threads;
4902 if (thread_progress == 1)
4904 LOGGER.
logNow(
"Number of threads: ") << number_of_threads << std::endl;
4905 LOGGER.
logNow(
"Number of voxels per thread: ") << tasks_per_thread << std::endl << std::flush;
4908 if (aVerboseLevel > 1)
4915 int iCorner, iVertex, iVertexTest, iEdge, iTriangle, iFlagIndex, iEdgeFlags;
4918 float afCubeValue[8];
4919 GLvector asEdgeVertex[12];
4920 GLvector asEdgeNorm[12];
4925 for(iVertex = 0; iVertex < 8; iVertex++)
4927 afCubeValue[iVertex] = padded_image.
getPixelValue(i + a2fVertexOffset[iVertex][0],
4928 j + a2fVertexOffset[iVertex][1],
4929 k + a2fVertexOffset[iVertex][2]);
4934 for(iVertexTest = 0; iVertexTest < 8; iVertexTest++)
4936 if(!(iso_value <= afCubeValue[iVertexTest]))
4938 iFlagIndex |= 1<<iVertexTest;
4943 iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];
4950 for(iEdge = 0; iEdge < 12; iEdge++)
4953 if(iEdgeFlags & (1<<iEdge))
4955 double fDelta = afCubeValue[ a2iEdgeConnection[iEdge][1] ] - afCubeValue[ a2iEdgeConnection[iEdge][0] ];
4963 fOffset = (iso_value - afCubeValue[ a2iEdgeConnection[iEdge][0] ])/fDelta;
4966 asEdgeVertex[iEdge].fX = voxel_position.getX() + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0] + fOffset * a2fEdgeDirection[iEdge][0]) * padded_image.
getSpacing()[0];
4967 asEdgeVertex[iEdge].fY = voxel_position.getY() + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1] + fOffset * a2fEdgeDirection[iEdge][1]) * padded_image.
getSpacing()[1];
4968 asEdgeVertex[iEdge].fZ = voxel_position.getZ() + (a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2] + fOffset * a2fEdgeDirection[iEdge][2]) * padded_image.
getSpacing()[2];
4974 for(iTriangle = 0; iTriangle < 5; iTriangle++)
4976 if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)
4979 for(iCorner = 0; iCorner < 3; iCorner++)
4981 iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
4983 p_vertex_set[thread_id].push_back(asEdgeVertex[iVertex].fX);
4984 p_vertex_set[thread_id].push_back(asEdgeVertex[iVertex].fY);
4985 p_vertex_set[thread_id].push_back(asEdgeVertex[iVertex].fZ);
4994 p_normal_vector_set[thread_id].push_back(normal.
getX());
4995 p_normal_vector_set[thread_id].push_back(normal.
getY());
4996 p_normal_vector_set[thread_id].push_back(normal.
getZ());
5004 if (aVerboseLevel > 1)
5012 std::vector<float> p_combined_vertex_set;
5013 std::vector<float> p_combined_normal_vector_set;
5015 for (
int i = 0; i < max_thread; ++i)
5017 p_combined_vertex_set.insert(p_combined_vertex_set.end(), p_vertex_set[i].begin(), p_vertex_set[i].end());
5018 p_combined_normal_vector_set.insert(p_combined_normal_vector_set.end(), p_normal_vector_set[i].begin(), p_normal_vector_set[i].end());
5023 &p_combined_vertex_set,
5024 &p_combined_normal_vector_set,
5033 &(p_normal_vector_set[0]),
5041 return (iso_surface);
5051 glDeleteTextures(1, &m_texture_id);
5061 return m_texture_id;
5071 typedef itk::ImageIOBase::IOComponentType ScalarPixelType;
5074 itk::ImageIOBase::Pointer imageIO(itk::ImageIOFactory::CreateImageIO(aFileName, itk::ImageIOFactory::ReadMode));
5079 std::stringstream error_message;
5080 error_message <<
"Could not CreateImageIO for \"" << aFileName <<
"\"";
5081 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message.str());
5083 imageIO->SetFileName(aFileName);
5084 imageIO->ReadImageInformation();
5086 const ScalarPixelType pixelType = imageIO->GetComponentType();
5088 return (std::string(imageIO->GetComponentTypeAsString(pixelType)));
5090 return (std::string(
"unknown"));
5108 return (anImage * aValue);
5122 for (
unsigned int i(0); i < number_of_voxels; ++i, ++p_temp)
5126 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Division by zero.");
5129 *p_temp = aValue / *p_temp;
5132 return (temp_image);
5141 return (anImage + aValue);
5157 #pragma omp parallel for 5159 for (
int i = 0; i < number_of_voxels; ++i)
5161 p_temp[i] = aValue - p_temp[i];
5164 return (temp_image);
5172 return (anImage.
log());
5180 return (anImage.
abs());
5192 double ratio((v1 - aThresholdValue) / (v1 - v0));
5194 return (p1 + (p0 - p1) * ratio);
5202 loadMetaHeader(aFileName.data());
5207 template<
typename T>
void Image<T>::loadMetaHeader(
const char* aFileName)
5211 std::ifstream meta_header(aFileName, std::ios::binary|std::ios::in);
5214 if (!meta_header.is_open())
5217 throw FileDoesNotExistException(__FILE__, __FUNCTION__, __LINE__, aFileName);
5221 unsigned int number_of_dimensions(0);
5222 double spacing[3] = {0.0, 0.0, 0.0};
5223 unsigned int dimensions[3] = {1, 1, 1};
5224 std::string element_type;
5225 std::string raw_file_name;
5226 bool change_endianess(
false);
5227 bool deflate_compression(
false);
5229 std::string info_type;
5230 while (meta_header >> info_type)
5232 std::string equal_sign;
5233 meta_header >> equal_sign;
5236 if (equal_sign !=
"=")
5238 std::string error_message(
"The program was expecting \"=\" but received \"");
5239 error_message += equal_sign;
5240 error_message +=
"\".";
5241 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5244 if (info_type ==
"ObjectType")
5246 std::string object_type;
5247 meta_header >> object_type;
5249 if (object_type !=
"Image")
5251 std::string error_message(
"The object type \"");
5252 error_message += object_type;
5253 error_message +=
"\" is not known. It should have been \"Image\".";
5254 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5257 else if (info_type ==
"NDims")
5259 meta_header >> number_of_dimensions;
5263 if ( 3 < number_of_dimensions)
5265 std::stringstream error_message;
5266 error_message <<
"The number of dimensions \"" << number_of_dimensions <<
5267 "\" is not valid. It should have been in the range [0, 3].";
5268 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message.str());
5271 else if (info_type ==
"BinaryData")
5273 std::string data_type;
5274 meta_header >> data_type;
5276 if (data_type !=
"True")
5278 std::string error_message(
"The data type is not binary.");
5279 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5282 else if (info_type ==
"BinaryDataByteOrderMSB" || info_type ==
"ElementByteOrderMSB")
5284 std::string big_endian;
5285 meta_header >> big_endian;
5289 change_endianess =
true;
5294 change_endianess =
true;
5297 else if (info_type ==
"CompressedData")
5299 std::string compression;
5300 meta_header >> compression;
5302 if (compression ==
"True")
5304 deflate_compression =
true;
5307 else if (info_type ==
"TransformMatrix")
5309 for (
unsigned int j(0); j < number_of_dimensions; ++j)
5311 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5314 meta_header >> temp;
5318 else if (info_type ==
"Offset")
5320 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5323 meta_header >> temp;
5326 else if (info_type ==
"CenterOfRotation")
5328 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5331 meta_header >> temp;
5334 else if (info_type ==
"AnatomicalOrientation")
5336 std::string anatomical_orientation;
5337 meta_header >> anatomical_orientation;
5339 else if (info_type ==
"ElementSpacing")
5341 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5343 meta_header >> spacing[i];
5346 else if (info_type ==
"DimSize")
5348 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5350 meta_header >> dimensions[i];
5353 else if (info_type ==
"ElementType")
5355 std::string data_type_string;
5356 meta_header >> data_type_string;
5358 if (data_type_string ==
"MET_DOUBLE")
5360 element_type =
typeid(double).name();
5362 else if (data_type_string ==
"MET_FLOAT")
5364 element_type =
typeid(float).name();
5366 else if (data_type_string ==
"MET_CHAR")
5368 element_type =
typeid(char).name();
5370 else if (data_type_string ==
"MET_UCHAR")
5372 element_type =
typeid(
unsigned char).name();
5374 else if (data_type_string ==
"MET_SHORT")
5376 element_type =
typeid(short).name();
5378 else if (data_type_string ==
"MET_USHORT")
5380 element_type =
typeid(
unsigned short).name();
5382 else if (data_type_string ==
"MET_INT")
5384 element_type =
typeid(int).name();
5386 else if (data_type_string ==
"MET_UINT")
5388 element_type =
typeid(
unsigned int).name();
5392 std::string error_message(
"The data type \"");
5393 error_message += data_type_string;
5394 error_message +=
"\" is not known.";
5395 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5398 else if (info_type ==
"HeaderSize")
5401 meta_header >> header_size;
5403 else if (info_type ==
"ElementSize")
5407 for (
unsigned int i(0); i < number_of_dimensions; ++i)
5409 meta_header >> element_size;
5412 else if (info_type ==
"ElementDataFile")
5414 meta_header >> raw_file_name;
5416 if (raw_file_name ==
"LOCAL")
5418 loadRAW(meta_header,
5419 dimensions[0], dimensions[1], dimensions[2],
5427 std::string meta_header_file_name(aFileName);
5428 size_t index1(meta_header_file_name.find_last_of(
'\\'));
5429 size_t index2(meta_header_file_name.find_last_of(
'/'));
5432 if (index1 == std::string::npos)
5437 if (index2 == std::string::npos)
5442 index = std::max(index1, index2);
5446 raw_file_name = meta_header_file_name.substr(0, index) +
"/" + raw_file_name;
5449 loadRAW(raw_file_name,
5450 dimensions[0], dimensions[1], dimensions[2],
5456 setSpacing(spacing[0], spacing[1], spacing[2]);
5460 std::string error_message(
"The field \"");
5461 error_message += info_type;
5462 error_message +=
"\" is not known.";
5463 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5471 return (sizeOf(std::string(anElementType)));
5478 if (anElementType ==
typeid(
double).name())
5479 return (
sizeof(
double));
5482 else if (anElementType ==
typeid(
float).name())
5483 return (
sizeof(
float));
5486 else if (anElementType ==
typeid(
char).name())
5487 return (
sizeof(
char));
5490 else if (anElementType ==
typeid(
unsigned char).name())
5491 return (
sizeof(
unsigned char));
5494 else if (anElementType ==
typeid(
short).name())
5495 return (
sizeof(
short));
5498 else if (anElementType ==
typeid(
unsigned short).name())
5499 return (
sizeof(
unsigned short));
5502 else if (anElementType ==
typeid(
int).name())
5503 return (
sizeof(
int));
5506 else if (anElementType ==
typeid(
unsigned int).name())
5507 return (
sizeof(
unsigned int));
5510 std::string error_message(
"The data type \"");
5511 error_message += anElementType;
5512 error_message +=
"\" is not known.";
5513 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5519 unsigned int aWidth,
5520 unsigned int aHeight,
5521 unsigned int aNumberOfSlices,
5522 bool aChangeEndianessFlag,
5523 const char* aFileName,
5524 const char* anElementType
5534 m_number_of_slices = aNumberOfSlices;
5536 unsigned int number_of_voxels(m_width * m_height * m_number_of_slices);
5539 if (!number_of_voxels)
5545 unsigned int requested_length_in_bytes(
5547 sizeOf(anElementType));
5550 char* p_temp_buffer(
new char[requested_length_in_bytes + sizeOf(anElementType)]);
5555 throw OutOfMemoryException(__FILE__, __FUNCTION__, __LINE__);
5559 int offset_current_position(anInputStream.tellg());
5560 anInputStream.seekg (0, std::ios::end);
5561 unsigned int length(
int(anInputStream.tellg()) - offset_current_position);
5562 anInputStream.seekg (offset_current_position, std::ios::beg);
5564 if (length < requested_length_in_bytes)
5567 delete [] p_temp_buffer;
5569 std::string error_message(
"The file size of \"");
5570 error_message += aFileName;
5571 error_message +=
"\" is too small to contained the specified raw data.";
5572 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5588 int offset_in_bytes(0);
5589 anInputStream.read(reinterpret_cast<char*>(p_temp_buffer), 1);
5590 if (*reinterpret_cast<char*>(p_temp_buffer) != 10)
5592 offset_in_bytes = 1;
5596 anInputStream.read(reinterpret_cast<char*>(p_temp_buffer) + offset_in_bytes, requested_length_in_bytes);
5599 anInputStream.close();
5602 if (aChangeEndianessFlag && sizeOf(anElementType) > 1)
5605 #pragma omp parallel for 5607 for (
int i = 0; i < m_width * m_height * m_number_of_slices; ++i)
5641 if (anElementType ==
typeid(T).name())
5644 m_p_image =
reinterpret_cast<T*
>(p_temp_buffer);
5650 m_p_image =
new T[number_of_voxels];
5656 delete [] p_temp_buffer;
5658 throw OutOfMemoryException(__FILE__, __FUNCTION__, __LINE__);
5662 if (std::string(anElementType) ==
typeid(
double).name())
5664 double* p_temp =
reinterpret_cast<double*
> (p_temp_buffer);
5665 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5669 else if (std::string(anElementType) ==
typeid(
float).name())
5671 float* p_temp =
reinterpret_cast<float*
> (p_temp_buffer);
5672 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5676 else if (std::string(anElementType) ==
typeid(
char).name())
5678 char* p_temp =
reinterpret_cast<char*
> (p_temp_buffer);
5679 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5683 else if (std::string(anElementType) ==
typeid(
unsigned char).name())
5685 unsigned char* p_temp =
reinterpret_cast<unsigned char*
> (p_temp_buffer);
5686 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5690 else if (std::string(anElementType) ==
typeid(
short).name())
5692 short* p_temp =
reinterpret_cast<short*
> (p_temp_buffer);
5693 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5697 else if (std::string(anElementType) ==
typeid(
unsigned short).name())
5699 unsigned short* p_temp =
reinterpret_cast<unsigned short*
> (p_temp_buffer);
5700 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5704 else if (std::string(anElementType) ==
typeid(
int).name())
5706 int* p_temp =
reinterpret_cast<int*
> (p_temp_buffer);
5707 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5711 else if (std::string(anElementType) ==
typeid(
unsigned int).name())
5713 unsigned int* p_temp =
reinterpret_cast<unsigned int*
> (p_temp_buffer);
5714 std::copy(p_temp, p_temp + number_of_voxels, m_p_image);
5720 delete [] p_temp_buffer;
5722 std::string error_message(
"The data type \"");
5723 error_message += anElementType;
5724 error_message +=
"\" is not known.";
5725 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5729 delete [] p_temp_buffer;
5735 template<
typename T>
void Image<T>::saveMetaHeader(
const std::string& aFileName,
bool useDeflateCompressionIfPossible)
const 5738 saveMetaHeader(aFileName.data(), useDeflateCompressionIfPossible);
5743 template<
typename T>
void Image<T>::saveMetaHeader(
const char* aFileName,
bool useDeflateCompressionIfPossible)
const 5747 std::ofstream meta_header(aFileName);
5750 if (!meta_header.is_open())
5752 std::string error_message;
5753 error_message =
"Cannot create the file (\"";
5754 error_message += aFileName;
5755 error_message +=
"\")";
5757 throw Exception(__FILE__, __FUNCTION__, __LINE__, error_message);
5760 meta_header <<
"ObjectType = Image" << std::endl;
5761 if (m_number_of_slices == 1)
5763 meta_header <<
"NDims = 2" << std::endl;
5764 meta_header <<
"DimSize = " << m_width <<
" " << m_height << std::endl;
5768 meta_header <<
"NDims = 3" << std::endl;
5769 meta_header <<
"DimSize = " << m_width <<
" " << m_height <<
" " << m_number_of_slices << std::endl;
5772 std::string data_type_string;
5773 if (
typeid(T) ==
typeid(
double))
5775 data_type_string =
"MET_DOUBLE";
5777 else if (
typeid(T) ==
typeid(
float))
5779 data_type_string =
"MET_FLOAT";
5781 else if (
typeid(T) ==
typeid(
char))
5783 data_type_string =
"MET_CHAR";
5785 else if (
typeid(T) ==
typeid(
unsigned char))
5787 data_type_string =
"MET_UCHAR";
5789 else if (
typeid(T) ==
typeid(
short))
5791 data_type_string =
"MET_SHORT";
5793 else if (
typeid(T) ==
typeid(
unsigned short))
5795 data_type_string =
"MET_USHORT";
5797 else if (
typeid(T) ==
typeid(
int))
5799 data_type_string =
"MET_INT";
5801 else if (
typeid(T) ==
typeid(
unsigned int))
5803 data_type_string =
"MET_UINT";
5807 throw Exception(__FILE__, __FUNCTION__, __LINE__,
"Unsupported data type");
5810 meta_header <<
"ElementType = " << data_type_string << std::endl;
5812 if (m_number_of_slices == 1)
5814 meta_header <<
"ElementSize = 1 1" << std::endl;
5815 meta_header <<
"ElementSpacing = " << m_spacing[0] <<
" " << m_spacing[1] << std::endl;
5819 meta_header <<
"ElementSize = 1 1 1" << std::endl;
5820 meta_header <<
"ElementSpacing = " << m_spacing[0] <<
" " << m_spacing[1] <<
" " << m_spacing[2] << std::endl;
5823 meta_header <<
"ElementByteOrderMSB = " <<
5826 meta_header <<
"CompressedData = " <<
5827 (useDeflateCompressionIfPossible?
"True":
"False") << std::endl;
5829 std::string raw_file_name(aFileName);
5830 if (
isMHD(aFileName))
5832 raw_file_name[raw_file_name.size() - 3] =
'r';
5833 raw_file_name[raw_file_name.size() - 2] =
'a';
5834 raw_file_name[raw_file_name.size() - 1] =
'w';
5838 raw_file_name +=
".raw";
5840 if (useDeflateCompressionIfPossible)
5842 raw_file_name +=
".gz";
5845 size_t index1(raw_file_name.find_last_of(
'\\'));
5846 size_t index2(raw_file_name.find_last_of(
'/'));
5849 if (index1 != std::string::npos)
5858 if (index2 != std::string::npos)
5867 index = std::max(index1, index2);
5870 if (
isMHD(aFileName))
5872 meta_header <<
"ElementDataFile = " << raw_file_name.substr(index, raw_file_name.size() - index) << std::endl;
5874 saveRAW(raw_file_name, useDeflateCompressionIfPossible);
5878 meta_header <<
"ElementDataFile = " <<
"LOCAL\n";
5882 if (useDeflateCompressionIfPossible)
5884 char* compressed_data =
new char[m_width * m_height * m_number_of_slices *
sizeof(T)];
5886 reinterpret_cast<char*>(m_p_image),
5887 m_width * m_height * m_number_of_slices *
sizeof(T),
5890 meta_header.write(compressed_data, data_size);
5891 delete [] compressed_data;
5896 meta_header.write(reinterpret_cast<char*>(m_p_image), m_width * m_height * m_number_of_slices *
sizeof(T));
bool isRAW(const char *aFileName)
Check if the extension of a file name is RAW.
bool isMHD(const char *aFileName)
Check if the extension of a file name is MHD.
Class to handle GLSL shaders.
Image< T > operator+(const T &aValue, const Image< T > &anImage)
T & getPixel(unsigned int i, unsigned int j, unsigned int k=0)
Accessor on a pixel value.
bool isDAT(const char *aFileName)
Check if the extension of a file name is DAT.
bool isTIFF(const char *aFileName)
Check if the extension of a file name is TIFF.
Class to handle exceptions when memory cannot be allocated dynamically.
void checkOpenGLErrorStatus(const char *aFileName, const char *aFunctionName, int aLineNumber)
Check OpenGL's error status.
bool isMHA(const char *aFileName)
Check if the extension of a file name is MHA.
Image< T > log(const Image< T > &anImage)
void setLabel(const std::string &aComputeShaderLabel)
Set the compute shader label. This is useful for debugging.
bool isPGM(const char *aFileName)
Check if the extension of a file name is PGM.
Image< T > rotate(float anAngleInDegrees) const
void normalise()
Normalise the current vector so that its length is 1.
OutOfMemoryException is a class to handle exceptions when accessing an array cell that is not accessi...
T getX() const
Accessor on the position along the x-axis.
bool isValid() const
Accessor on the validity status of the shader.
VEC3 m_spacing
The space between two successive pixels.
Image()
Default constructor.
FileDoesNotExistException is a class to handle exceptions when trying to open a read-only file that i...
T getZ() const
Accessor on the position along the z-axis.
Exception is a class to handle exceptions.
void transferHostToDevice()
Sinogram is a class to reconstruct images from a sinogram.
bool isTXT(const char *aFileName)
Check if the extension of a file name is TXT.
std::string getShaderPixelType(const std::type_info &aTypeID)
bool isJPEG(const char *aFileName)
Check if the extension of a file name is JPEG.
Image< T > operator/(const T &aValue, const Image< T > &anImage)
Class to handle exceptions when trying to open a read-only file that is not accessible.
#define gVirtualXRay_VERSION_MAJOR
#define EPSILON
Smallest value that can be stored with a real number.
Generic class to handle exceptions.
#define gVirtualXRay_VERSION_PATCH
T * getRawData()
Accessor on the raw data.
bool isDCM(const char *aFileName)
Check if the extension of a file name is DCM.
void save(const char *aFileName, bool anInvertLUTFlag=false, const char *aComment="", bool useDeflateCompressionIfPossible=false) const
Save the image in a file.
std::string getShaderRGBAPixelType(const std::type_info &aTypeID)
T getY() const
Accessor on the position along the y-axis.
const VEC3 & getSpacing() const
#define gVirtualXRay_VERSION_MINOR
void swapBytes(T &aValue)
PolygonMesh is a class to handle polygon (triangles) meshes.
Image is a class to manage a greyscale image.
std::string getShaderImageType(const std::type_info &aTypeID)
float RATIONAL_NUMBER
Type of data used to store real numbers.
unsigned int getHeight() const
Number of pixels along the vertical axis.
void setPixel(unsigned int i, unsigned int j, unsigned int k, T aValue)
Set a pixel.
Image constantPadFilter(const T &aPadValue) const
Vec3< RATIONAL_NUMBER > VEC3
Type of data used to store 3D vectors.
VEC3 getPixelPosition(unsigned int i, unsigned int j, unsigned int k=0) const
Accessor on a pixel position.
std::ostream & logWarning(const std::string &aMessage="")
unsigned int getDepth() const
Number of pixels along the Z axis.
Shader is a class to handle shaders written in GLSL.
unsigned int m_number_of_slices
Number of slices.
Some utility functions that do not fit anywhere else.
unsigned int m_width
Number of pixel along the horizontal axis.
std::ostream & logNow(const std::string &aMessage="")
bool checkExtension(const char *aFileName, const char *anExtension)
Image< T > operator-(const T &aValue, const Image< T > &anImage)
unsigned int getWidth() const
Number of pixels along the horizontal axis.
int deflate(const void *src, int srcLen, char **apDst)
Compress data using the Zlib.
Image< T > abs(const Image< T > &anImage)
virtual const char * what() const
Accessor on the error message.
std::string getShaderTypeID(const std::type_info &aTypeID)
void setSpacing(const VEC3 &aPixelSize)
void enable() const
Enable the current shader.
Image< T > gauss2D(unsigned int aSize, double aSigmaValue)
void setInternalData(int aTypeOfPrimitive, const void *aVertexArray, unsigned int aNumberOfVertices, int aVertexDataType, const void *anIndexArray, unsigned int aNumberOfIndices, int anIndexDataType, bool aCreateVBOFlag, int aTypeOfVBO)
Class to handle exceptions when accessing an array cell that is not accessible, i.e. out of bounds memory access.
void progressBar(float aPercentage, bool aNewLineFlag=false)
int getShaderOpenGLType(const std::type_info &aTypeID)
Constant values, such as the Z number of different atoms, etc.
unsigned int getTextureId() const
FFT is a class to compute the FFT of a greyscale image.
bool isMAT(const char *aFileName)
Check if the extension of a file name is MAT.
unsigned int m_height
Number of pixel along the vertical axis.
void loadSource(const std::string &aVertexShaderSourceCode, const std::string &aFragmentShaderSourceCode)
Load the shader source code.
Class to handle polygon (triangles) meshes.
Image< T > operator*(const T &aValue, const Image< T > &anImage)
std::string getPixelType(const std::string &aFileName)
T * m_p_image
The pixel data.
T & getPixelValue(unsigned int i, unsigned int j, unsigned int k=0)
Accessor on a pixel value.
bool useOpenGLCompute()
Check if OpenGL Compute Shaders are supported by the current OpenGL context.