[med-svn] [mia] 01/11: Imported Upstream version 2.2.3
Gert Wollny
gert-guest at moszumanska.debian.org
Wed Jan 14 11:08:14 UTC 2015
This is an automated email from the git hooks/post-receive script.
gert-guest pushed a commit to branch master
in repository mia.
commit 365a5390523c1afe0cff99e4355ba742c3a64695
Author: Gert Wollny <gw.fossdev at gmail.com>
Date: Wed Jan 7 12:23:35 2015 +0100
Imported Upstream version 2.2.3
---
CMakeLists.txt | 14 +-
ChangeLog | 9 +
.../test_combiner.cc => addons/jpg/jpeg-common.hh | 53 ++-
addons/jpg/jpg-gray.cc | 90 ++---
addons/jpg/jpg-rgb.cc | 74 ++---
addons/nifti/niftiimage.cc | 54 +--
addons/nifti/test_niftiimage.cc | 1 +
cmake/macros.cmake | 98 ++++--
doc/CMakeLists.txt | 42 ++-
doc/MiaDoctools.cmake | 187 +++++++++++
doc/__init__.py | 1 +
doc/extract_docu.py | 159 ---------
doc/mia-xmldoc2man.cmake | 5 +
doc/mia-xmldoc2nipype.cmake | 5 +
doc/miareadxml.py | 168 +++++++++-
doc/miaxml2html.py | 112 -------
doc/miaxml2man.py | 7 +-
doc/miaxml2nipype.py | 366 +++++++++++++++++++++
doc/miaxml2sgml.py | 2 +-
mia/2d/creator/circle.cc | 1 -
mia/2d/filter.cc | 1 -
mia/2d/filter/CMakeLists.txt | 3 +-
mia/2d/filter/labelscale.cc | 166 ++++++++++
mia/2d/{test_combiner.cc => filter/labelscale.hh} | 43 ++-
mia/2d/filter/test_labelscale.cc | 128 +++++++
mia/2d/filtertest.cc | 1 -
mia/2d/fullcost/CMakeLists.txt | 2 +-
mia/2d/fullcost/label.cc | 340 +++++++++++++++++++
mia/2d/fullcost/label.hh | 97 ++++++
mia/2d/fullcost/test_label.cc | 127 +++++++
mia/2d/imageiotest.cc | 1 -
mia/2d/imagetest.cc | 1 -
mia/2d/interpolator.cc | 2 -
mia/2d/register.cc | 3 +-
mia/2d/test_combiner.cc | 1 -
mia/2d/test_distance.cc | 1 -
mia/2d/test_filter.cc | 2 +-
mia/2d/test_filter_cast.cc | 1 -
mia/2d/test_fullcost.cc | 4 +-
mia/2d/test_ica.cc | 1 -
mia/2d/test_image.cc | 2 -
mia/2d/test_imageio.cc | 1 -
mia/2d/test_interpol.cc | 1 -
mia/2d/test_modelsolverreg.cc | 1 -
mia/2d/test_nfg.cc | 1 -
mia/2d/test_oldnewintegrate.cc | 1 -
mia/2d/test_ppmatrix.cc | 17 +-
mia/2d/test_regplugins.cc | 1 -
mia/2d/test_segframe.cc | 1 -
mia/2d/test_segmentation.cc | 1 -
mia/2d/test_shape.cc | 1 -
mia/2d/test_transformfactory.cc | 1 -
mia/2d/test_vectorfield_interpolator.cc | 1 -
mia/2d/test_vfio.cc | 1 -
mia/2d/vfiotest.cc | 1 -
mia/3d/datafield.cxx | 36 ++
mia/3d/datafield.hh | 14 +
mia/3d/fifof/morphological.cc | 1 -
mia/3d/fifof/regiongrow.cc | 2 +-
mia/3d/filter.cc | 2 -
mia/3d/filter/CMakeLists.txt | 1 +
mia/3d/filter/labelscale.cc | 177 ++++++++++
.../test_combiner.cc => 3d/filter/labelscale.hh} | 43 ++-
mia/3d/filter/test_bandpass.cc | 1 -
mia/3d/filter/test_binarize.cc | 1 -
mia/3d/filter/test_convert.cc | 1 -
mia/3d/filter/test_crop.cc | 1 -
mia/3d/filter/test_downscale.cc | 1 -
mia/3d/filter/test_gradnorm.cc | 1 -
mia/3d/filter/test_growmask.cc | 1 -
mia/3d/filter/test_invert.cc | 1 -
mia/3d/filter/test_kmeans.cc | 1 -
mia/3d/filter/test_label.cc | 1 -
mia/3d/filter/test_labelscale.cc | 169 ++++++++++
mia/3d/filter/test_load.cc | 1 -
mia/3d/filter/test_mask.cc | 1 -
mia/3d/filter/test_median.cc | 1 -
mia/3d/filter/test_mlv.cc | 1 -
mia/3d/filter/test_morphological.cc | 1 -
mia/3d/filter/test_reorient.cc | 1 -
mia/3d/filter/test_scale.cc | 1 -
mia/3d/filter/test_selectbig.cc | 1 -
mia/3d/filter/test_sepconv.cc | 1 -
mia/3d/filter/test_tee.cc | 1 -
mia/3d/fullcost/CMakeLists.txt | 2 +-
mia/3d/fullcost/label.cc | 321 ++++++++++++++++++
mia/3d/fullcost/label.hh | 100 ++++++
mia/3d/fullcost/test_label.cc | 203 ++++++++++++
mia/3d/image.hh | 21 ++
mia/3d/imageiotest.cc | 2 -
mia/3d/imagetest.cc | 1 -
mia/3d/interpolator.cc | 1 -
mia/3d/multireg.cc | 1 -
mia/3d/test_combiner.cc | 1 -
mia/3d/test_cost.cc | 3 -
mia/3d/test_deform.cc | 2 -
mia/3d/test_ica.cc | 1 -
mia/3d/test_image.cc | 1 -
mia/3d/test_interpol.cc | 1 -
mia/3d/test_nfg.cc | 1 -
mia/3d/test_orientation.cc | 3 -
mia/3d/test_regplugins.cc | 1 -
mia/3d/test_shape.cc | 1 -
mia/3d/test_transformfactory.cc | 2 -
mia/3d/test_vfio.cc | 2 -
mia/3d/transform/rotbend.cc | 72 ++--
mia/3d/transform/rotbend.hh | 6 +-
mia/3d/transform/test_rotbend.cc | 12 +-
mia/3d/vfiotest.cc | 3 +-
mia/core/CMakeLists.txt | 2 +
mia/core/attributes.hh | 6 +-
mia/core/cmdbooloption.cc | 8 +-
mia/core/cmdbooloption.hh | 3 +-
mia/core/cmdlineparser.cc | 182 +++++-----
mia/core/cmdlineparser.hh | 100 ++----
mia/core/cmdoption.cc | 19 +-
mia/core/cmdoption.hh | 5 +-
mia/core/cmdoptionflags.hh | 9 +-
mia/core/handler.hh | 12 +-
mia/core/minimizer/gdas.cc | 9 +-
mia/core/parameter.cc | 6 +-
.../test_combiner.cc => core/selftestcmdoption.cc} | 33 +-
mia/core/selftestcmdoption.hh | 89 +++++
mia/core/statistics.hh | 2 +-
mia/core/test_attributes.cc | 4 +-
miacore.pc.cmake | 3 +
src/2davgmasked.cc | 2 +-
src/2dcost.cc | 4 +-
src/2ddistance.cc | 37 ++-
src/2dgrayimage-combine-to-rgb.cc | 2 +-
src/2dimagecombine-dice.cc | 2 +-
src/2dimagefilter.cc | 4 -
src/2dimagefilterstack.cc | 6 -
src/2dimagefullstats.cc | 1 +
src/2dimageregistration.cc | 8 +-
src/2dimagestats.cc | 1 +
src/2dlerp.cc | 35 +-
src/2dmany2one-nonrigid.cc | 2 +-
src/2dmulti-force.cc | 51 ++-
src/2dmultiimageregistration.cc | 92 ++++++
src/2dmyocard-ica.cc | 3 +-
src/2dmyocard-icaseries.cc | 6 +-
src/2dmyoseries-compdice.cc | 1 +
src/2dmyoseries-dice.cc | 2 +-
src/2dsegcompare.cc | 2 +
src/2dseghausdorff.cc | 1 +
src/2dsegseriesstats.cc | 6 +-
src/2dseries-mincorr.cc | 4 +-
src/2dseries-segdistance.cc | 3 +
src/2dseries2sets.cc | 2 +-
src/2dserieshausdorff.cc | 1 +
src/2dstackfilter.cc | 5 +-
src/3dcost.cc | 2 +-
src/3ddistance-stats.cc | 5 +-
src/3dfield2norm.cc | 6 +-
src/3dgetsize.cc | 2 +-
src/3dgetslice.cc | 21 +-
src/3dimagecombine.cc | 2 +-
src/3dimagefilter.cc | 2 -
src/3dimagefilterstack.cc | 6 +-
src/3dimagestats.cc | 3 +-
src/3dlandmarks-distances.cc | 2 +-
src/3dlerp.cc | 33 +-
src/3dnonrigidreg.cc | 8 +-
src/3drigidreg.cc | 8 +-
src/3dseries-track-intensity.cc | 2 +-
src/3dvfcompare.cc | 6 +-
src/CMakeLists.txt | 20 +-
src/__init__.py | 1 +
src/filenumberpattern.cc | 1 +
src/fluid2d/CMakeLists.txt | 3 +-
src/fluid2d/main.cc | 6 +-
src/fluid3d/CMakeLists.txt | 3 +-
src/fluid3d/main.cc | 8 +-
src/isosurface/CMakeLists.txt | 4 +-
src/meshfilter.cc | 4 -
src/multihist.cc | 2 +-
src/myowavelettest.cc | 3 +-
src/plugin-help.cc | 2 +
src/test_plugins_as_installed.cc | 8 +-
180 files changed, 3563 insertions(+), 1019 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a05f081..2d90774 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -41,9 +41,9 @@ SET(VENDOR "Gert Wollny")
SET(PACKAGE_NAME "mia")
SET(MAJOR_VERSION 2)
SET(MINOR_VERSION 2)
-SET(MICRO_VERSION 2)
-SET(INTERFACE_AGE 2)
-SET(BINARY_AGE 2)
+SET(MICRO_VERSION 3)
+SET(INTERFACE_AGE 0)
+SET(BINARY_AGE 3)
SET(PACKAGE_VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}")
SET(VERSION "${MAJOR_VERSION}.${MINOR_VERSION}")
@@ -170,7 +170,7 @@ SET(FULL_DOC_INSTALL_PATH "${CMAKE_INSTALL_PREFIX}/${DOC_INSTALL_PATH}")
SET(BINARY_INSTALL_PATH "${CMAKE_INSTALL_BINDIR}")
SET(LIBRARY_INSTALL_PATH "${CMAKE_INSTALL_LIBDIR}")
SET(INCLUDE_INSTALL_PATH "${CMAKE_INSTALL_INCLUDEDIR}/${MIA_NAME}")
-
+SET(MIA_DOCTOOLS_INSTALL_ROOT "${CMAKE_INSTALL_PREFIX}/share/mia-doctools")
######################################################################################
#
@@ -437,16 +437,18 @@ ENDIF(ALWAYS_CREATE_DOC)
#
# python is needed for creating end-user documentation
#
+SET(CREATE_USERDOC FALSE)
+
FIND_PACKAGE(PythonInterp)
IF(PYTHONINTERP_FOUND)
EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import lxml" RESULT_VARIABLE LXML_ERR)
IF(LXML_ERR)
MESSAGE(python found, but no lxml, no user documantation will be created)
- SET(CREATE_USERDOC FALSE)
ELSE(LXML_ERR)
SET(CREATE_USERDOC TRUE)
ENDIF(LXML_ERR)
-ENDIF(PYTHONINTERP_FOUND)
+ENDIF(PYTHONINTERP_FOUND)
+
#############################################
#
diff --git a/ChangeLog b/ChangeLog
index 42b669b..d9bcda2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2.2.3
+
+ New features:
+
+ * Add some more speceliyed 3D image transformations
+ * Install the documentation tools
+ * Add nipype interfaces to all command line tools
+ * Add (localized) normalized cross correlation as cost function
+
2.2.2
Fixes:
diff --git a/mia/2d/test_combiner.cc b/addons/jpg/jpeg-common.hh
similarity index 52%
copy from mia/2d/test_combiner.cc
copy to addons/jpg/jpeg-common.hh
index ebf7895..3de0e57 100644
--- a/mia/2d/test_combiner.cc
+++ b/addons/jpg/jpeg-common.hh
@@ -18,26 +18,43 @@
*
*/
-#include <stdexcept>
-#include <climits>
+#include <jpeglib.h>
-#include <mia/internal/autotest.hh>
-#include <boost/filesystem/path.hpp>
-#include <mia/2d/filter.hh>
+namespace miajpeg {
+struct JpegDecompress {
+
+ JpegDecompress()
+ {
+ info.err = jpeg_std_error(&err);
+ jpeg_create_decompress(&info);
+ }
+
+ ~JpegDecompress()
+ {
+ jpeg_destroy_decompress(&info);
+ }
+
+ struct jpeg_decompress_struct info;
+ struct jpeg_error_mgr err;
+};
-NS_MIA_USE
-using namespace boost;
-using namespace std;
-namespace bfs=boost::filesystem;
+struct JpegCompress {
+
+ JpegCompress()
+ {
+ info.err = jpeg_std_error(&err);
+ jpeg_create_compress(&info);
+ }
+
+ ~JpegCompress()
+ {
+ jpeg_destroy_compress(&info);
+ }
-BOOST_AUTO_TEST_CASE( test_load_plugins )
-{
- CPathNameArray plugpath;
- plugpath.push_back(bfs::path("combiner"));
- C2DImageCombinerPluginHandler::set_search_path(plugpath);
- const C2DImageCombinerPluginHandler::Instance& handler = C2DImageCombinerPluginHandler::instance();
- BOOST_CHECK_EQUAL(handler.size(), 5u);
- BOOST_CHECK_EQUAL(handler.get_plugin_names(), "absdiff add div mul sub ");
-}
+ struct jpeg_compress_struct info;
+ struct jpeg_error_mgr err;
+};
+
+};
diff --git a/addons/jpg/jpg-gray.cc b/addons/jpg/jpg-gray.cc
index 1e93d60..d9b97fe 100644
--- a/addons/jpg/jpg-gray.cc
+++ b/addons/jpg/jpg-gray.cc
@@ -20,7 +20,7 @@
#include <cstdio>
#include <cstdlib>
-#include <jpeglib.h>
+
#include <sstream>
#include <cassert>
#include <mia/core/file.hh>
@@ -28,6 +28,11 @@
#include <mia/core/msgstream.hh>
#include <mia/2d/imageio.hh>
+#include "jpeg-common.hh"
+
+
+
+
NS_BEGIN(IMAGEIO_2D_JPG)
using namespace mia;
@@ -56,9 +61,14 @@ CJpeg2DImageIOPlugin::CJpeg2DImageIOPlugin():
}
-METHODDEF(void) mia_jpeg_error_exit (j_common_ptr /*cinfo*/)
+METHODDEF(void) mia_jpeg_load_error_exit (j_common_ptr /*cinfo*/)
+{
+ throw mia::create_exception<runtime_error>("JpegGray::load: error reading from input file");
+}
+
+METHODDEF(void) mia_jpeg_save_error_exit (j_common_ptr /*cinfo*/)
{
- throw create_exception<runtime_error>("Jpeg::load: error reading from input file");
+ throw create_exception<runtime_error>("JpegGray::save: error reading from input file");
}
@@ -66,55 +76,45 @@ C2DImageIOPlugin::PData CJpeg2DImageIOPlugin::do_load(const string& fname) const
{
CInputFile f(fname);
if (!f)
- throw create_exception<runtime_error>("CPNG2DImageIO::save:unable to open input file '", fname, "'");
+ throw create_exception<runtime_error>("C2DImageIOPlugin::load :unable to open input file '", fname, "'");
- struct jpeg_decompress_struct cdecompress_info;
- struct jpeg_error_mgr jerr;
-
- cdecompress_info.err = jpeg_std_error(&jerr);
+ miajpeg::JpegDecompress decompress;
+ decompress.err.error_exit = mia_jpeg_load_error_exit;
- jerr.error_exit = mia_jpeg_error_exit;
-
- jpeg_create_decompress(&cdecompress_info);
-
- jpeg_stdio_src(&cdecompress_info, f);
+ jpeg_stdio_src(&decompress.info, f);
// is it a jpeg image?
- if (jpeg_read_header(&cdecompress_info, TRUE) != JPEG_HEADER_OK)
+ if (jpeg_read_header(&decompress.info, TRUE) != JPEG_HEADER_OK)
return C2DImageIOPlugin::PData();
- (void) jpeg_start_decompress(&cdecompress_info);
+ jpeg_start_decompress(&decompress.info);
// only one component?
- if (cdecompress_info.output_components != 1) {
- jpeg_destroy_decompress(&cdecompress_info);
+ if (decompress.info.output_components != 1) {
throw create_exception<runtime_error>(":MIA only supports gray scale images, but got an image with ",
- cdecompress_info.output_components, " color components.");
+ decompress.info.output_components, " color components.");
}
- if (cdecompress_info.data_precision != 8) {
- jpeg_destroy_decompress(&cdecompress_info);
+ if (decompress.info.data_precision != 8) {
throw create_exception<runtime_error>(":MIA only supports 8-bit per pixel images, but got an image with ",
- cdecompress_info.data_precision, " bits data precision.");
+ decompress.info.data_precision, " bits data precision.");
}
-
- int row_stride = cdecompress_info.output_width * cdecompress_info.output_components;
+ int row_stride = decompress.info.output_width * decompress.info.output_components;
vector<JSAMPLE> buf(row_stride);
JSAMPROW buffer[1];
buffer[0] = &buf[0];
- C2DUBImage *result = new C2DUBImage(C2DBounds(cdecompress_info.output_width, cdecompress_info.output_height));
+ C2DUBImage *result = new C2DUBImage(C2DBounds(decompress.info.output_width, decompress.info.output_height));
P2DImage presult(result);
- while (cdecompress_info.output_scanline < cdecompress_info.output_height) {
- (void) jpeg_read_scanlines(&cdecompress_info, buffer, 1);
+ while (decompress.info.output_scanline < decompress.info.output_height) {
+ (void) jpeg_read_scanlines(&decompress.info, buffer, 1);
copy(buf.begin(), buf.end(),
- result->begin_at(0, cdecompress_info.output_scanline - 1));
+ result->begin_at(0, decompress.info.output_scanline - 1));
}
- jpeg_destroy_decompress(&cdecompress_info);
-
+
C2DImageIOPlugin::PData result_vector(new C2DImageIOPlugin::Data);
result_vector->push_back(presult);
return result_vector;
@@ -123,34 +123,34 @@ C2DImageIOPlugin::PData CJpeg2DImageIOPlugin::do_load(const string& fname) const
bool CJpeg2DImageIOPlugin::do_save_jpeg(FILE *f, const C2DUBImage& image) const
{
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
+ miajpeg::JpegCompress compress;
+
+ jpeg_create_compress(&compress.info);
+ compress.err.error_exit = mia_jpeg_save_error_exit;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- cinfo.image_width = image.get_size().x;
- cinfo.image_height = image.get_size().y;
+ compress.info.image_width = image.get_size().x;
+ compress.info.image_height = image.get_size().y;
vector<JSAMPLE> samples(image.get_size().x);
JSAMPROW scanline[1];
scanline[0] = &samples[0];
- cinfo.input_components = 1;
- cinfo.in_color_space = JCS_GRAYSCALE;
+ compress.info.input_components = 1;
+ compress.info.in_color_space = JCS_GRAYSCALE;
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo,100,1);
+ jpeg_set_defaults(&compress.info);
+ jpeg_set_quality(&compress.info,100,1);
- jpeg_stdio_dest(&cinfo,f);
- jpeg_start_compress(&cinfo,TRUE);
+ jpeg_stdio_dest(&compress.info,f);
+ jpeg_start_compress(&compress.info,TRUE);
for (unsigned int y = 0; y < image.get_size().y; ++y) {
- copy(image.begin_at(0,y), image.begin_at(0,y) + cinfo.image_width, scanline[0]);
- jpeg_write_scanlines(&cinfo,scanline,1);
+ copy(image.begin_at(0,y), image.begin_at(0,y) + compress.info.image_width, scanline[0]);
+ jpeg_write_scanlines(&compress.info,scanline,1);
}
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
+ jpeg_finish_compress(&compress.info);
+ jpeg_destroy_compress(&compress.info);
return true;
}
diff --git a/addons/jpg/jpg-rgb.cc b/addons/jpg/jpg-rgb.cc
index 9efae2a..2d9306e 100644
--- a/addons/jpg/jpg-rgb.cc
+++ b/addons/jpg/jpg-rgb.cc
@@ -20,7 +20,6 @@
#include <cstdio>
#include <cstdlib>
-#include <jpeglib.h>
#include <sstream>
#include <cassert>
#include <mia/core/file.hh>
@@ -28,6 +27,8 @@
#include <mia/core/msgstream.hh>
#include <mia/2d/rgbimageio.hh>
+#include "jpeg-common.hh"
+
NS_BEGIN(RGBIMAGEIO_2D_JPG)
using namespace mia;
@@ -55,9 +56,14 @@ CJpegRGB2DImageIOPlugin::CJpegRGB2DImageIOPlugin():
add_suffix(".JPEG");
}
-METHODDEF(void) mia_jpeg_error_exit (j_common_ptr /*cinfo*/)
+METHODDEF(void) mia_jpeg_load_error_exit (j_common_ptr /*cinfo*/)
+{
+ throw create_exception<runtime_error>("JpegRGB::load: error reading from input file");
+}
+
+METHODDEF(void) mia_jpeg_save_error_exit (j_common_ptr /*cinfo*/)
{
- throw create_exception<runtime_error>("Jpeg::load: error reading from input file");
+ throw create_exception<runtime_error>("JpegRGB::save: error reading from input file");
}
@@ -66,83 +72,73 @@ C2DRGBImageIOPlugin::PData CJpegRGB2DImageIOPlugin::do_load(const string& fname)
CInputFile f(fname);
if (!f)
- throw create_exception<runtime_error>("CPNG2DImageIO::save:unable to open input file '", fname, "'");
-
- struct jpeg_decompress_struct cdecompress_info;
- struct jpeg_error_mgr jerr;
-
- cdecompress_info.err = jpeg_std_error(&jerr);
+ throw create_exception<runtime_error>("CJpegRGB2DImageIO::save:unable to open input file '", fname, "'");
- jerr.error_exit = mia_jpeg_error_exit;
-
- jpeg_create_decompress(&cdecompress_info);
+ miajpeg::JpegDecompress decompress;
+ decompress.err.error_exit = mia_jpeg_load_error_exit;
- jpeg_stdio_src(&cdecompress_info, f);
+ jpeg_stdio_src(&decompress.info, f);
// is it a jpeg image?
- if (jpeg_read_header(&cdecompress_info, TRUE) != JPEG_HEADER_OK)
+ if (jpeg_read_header(&decompress.info, TRUE) != JPEG_HEADER_OK)
return C2DRGBImageIOPlugin::PData();
- (void) jpeg_start_decompress(&cdecompress_info);
+ jpeg_start_decompress(&decompress.info);
// only one component?
- if (cdecompress_info.output_components != 3) {
- jpeg_destroy_decompress(&cdecompress_info);
+ if (decompress.info.output_components != 3) {
throw create_exception<runtime_error>(":MIA this plugin only supports RGB images, but got an image with ",
- cdecompress_info.output_components, " color components.");
+ decompress.info.output_components, " color components.");
}
- int row_stride = cdecompress_info.output_width * cdecompress_info.output_components * 3;
+ int row_stride = decompress.info.output_width * decompress.info.output_components * 3;
vector<JSAMPLE> buf(row_stride);
JSAMPROW buffer[1];
buffer[0] = &buf[0];
- CRGB2DImage *result = new CRGB2DImage(C2DBounds(cdecompress_info.output_width, cdecompress_info.output_height));
+ CRGB2DImage *result = new CRGB2DImage(C2DBounds(decompress.info.output_width, decompress.info.output_height));
PRGB2DImage presult(result);
- while (cdecompress_info.output_scanline < cdecompress_info.output_height) {
- (void) jpeg_read_scanlines(&cdecompress_info, buffer, 1);
+ while (decompress.info.output_scanline < decompress.info.output_height) {
+ (void) jpeg_read_scanlines(&decompress.info, buffer, 1);
copy(buf.begin(), buf.end(),
- result->pixel() + ((cdecompress_info.output_scanline - 1) * row_stride));
+ result->pixel() + ((decompress.info.output_scanline - 1) * row_stride));
}
- jpeg_destroy_decompress(&cdecompress_info);
return presult;
}
bool CJpegRGB2DImageIOPlugin::do_save_jpeg(FILE *f, const CRGB2DImage& image) const
{
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
+ miajpeg::JpegCompress compress;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
+ jpeg_create_compress(&compress.info);
+ compress.err.error_exit = mia_jpeg_save_error_exit;
- cinfo.image_width = image.get_size().x;
- cinfo.image_height = image.get_size().y;
+ compress.info.image_width = image.get_size().x;
+ compress.info.image_height = image.get_size().y;
vector<JSAMPLE> samples(image.get_size().x * 3);
JSAMPROW scanline[1];
scanline[0] = &samples[0];
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
+ compress.info.input_components = 3;
+ compress.info.in_color_space = JCS_RGB;
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo,80,1);
+ jpeg_set_defaults(&compress.info);
+ jpeg_set_quality(&compress.info,80,1);
- jpeg_stdio_dest(&cinfo,f);
- jpeg_start_compress(&cinfo,TRUE);
+ jpeg_stdio_dest(&compress.info,f);
+ jpeg_start_compress(&compress.info,TRUE);
int dx = image.get_size().x * 3;
for (unsigned int y = 0; y < image.get_size().y; ++y) {
copy(image.pixel() + y * dx, image.pixel() + (y + 1) * dx, scanline[0]);
- jpeg_write_scanlines(&cinfo,scanline,1);
+ jpeg_write_scanlines(&compress.info,scanline,1);
}
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
+ jpeg_finish_compress(&compress.info);
return true;
}
diff --git a/addons/nifti/niftiimage.cc b/addons/nifti/niftiimage.cc
index 80d0766..d908d3a 100644
--- a/addons/nifti/niftiimage.cc
+++ b/addons/nifti/niftiimage.cc
@@ -86,6 +86,8 @@ struct NiftiDeallocator {
void copy_attributes(C3DImage& image, const nifti_image& ni)
{
// set position and orientation
+ image.set_attribute(AttrID_nifti_qform_code, ni.qform_code);
+
if (ni.qform_code == 0) { // method 1
image.set_orientation(ior_default);
image.set_voxel_size(C3DFVector(ni.dx, ni.dy, ni.dz));
@@ -97,7 +99,6 @@ void copy_attributes(C3DImage& image, const nifti_image& ni)
ni.quatern_c * ni.quatern_c +
ni.quatern_d * ni.quatern_d));
image.set_rotation(Quaternion(qa, ni.quatern_b, ni.quatern_c, ni.quatern_d));
- image.set_attribute(AttrID_nifti_qform_code, ni.qform_code);
}
if (ni.sform_code > 0) { // method 3
@@ -342,29 +343,42 @@ bool CNifti3DImageIOPlugin::do_save(const std::string& fname, const Data& data)
// need to see whether to support this
output->cal_min = 0.0f;
output->cal_max = 0.0f ;
-
- // here starts the orientation insanity
- // todo: re-check how this qfac is actually used
- output->qfac = 1;
- switch (image.get_orientation()) {
- // Coverty complains here.
- // flipped needs to sent an extra parameter and
- // then fall through to the next case
- case ior_xyz_flipped: output->qfac = -1;
- case ior_undefined:
- case ior_xyz: {
- output->qform_code = 1;
+
+ if (image.has_attribute(AttrID_nifti_qform_code)) {
+ output->qform_code = image.get_attribute_as<int>(AttrID_nifti_qform_code);
+ } else {
+ output->qform_code = 0; // default to method 2
+ }
+
+ // Analyze 7.5 like data
+ if (output->qform_code == 0) {
+ // here starts the orientation insanity
+ // todo: re-check how this qfac is actually used
+
+ auto org = image.get_origin();
+ output->qoffset_x = org.x;
+ output->qoffset_y = org.y;
+ output->qoffset_z = org.z;
+ output->quatern_b = 0.0;
+ output->quatern_c = 0.0;
+ output->quatern_d = 0.0;
+
+ switch (image.get_orientation()) {
+ case ior_undefined:
+ case ior_xyz: break;
+ default:
+ cvwarn() << __FUNCTION__ << "FIXME:manual set orientation detected, but ignored\n";
+ }
+ } else {
+ output->qfac = (image.get_orientation() == ior_xyz_flipped) ? -1 : 1;
auto org = image.get_origin();
output->qoffset_x = org.x;
output->qoffset_y = org.y;
output->qoffset_z = org.z;
- auto rot = image.get_rotation().as_quaternion();
+ auto rot = image.get_rotation().as_quaternion();
output->quatern_b = rot.x();
output->quatern_c = rot.y();
output->quatern_d = rot.z();
- } break;
- default:
- cvwarn() << __FUNCTION__ << "FIXME:manual set orientation detected, but ignored\n";
}
// copy s-form if available
@@ -398,9 +412,9 @@ bool CNifti3DImageIOPlugin::do_save(const std::string& fname, const Data& data)
output->time_units = image.get_attribute_as<int>(AttrID_nifti_time_units, NIFTI_UNITS_SEC);
output->intent_code = image.get_attribute_as<int>(AttrID_nifti_intent_code, 0);
- output->intent_p1 = image.get_attribute_as<int>(AttrID_nifti_intent_p1, 0);
- output->intent_p2 = image.get_attribute_as<int>(AttrID_nifti_intent_p2, 0);
- output->intent_p3 = image.get_attribute_as<int>(AttrID_nifti_intent_p3, 0);
+ output->intent_p1 = image.get_attribute_as<float>(AttrID_nifti_intent_p1, 0);
+ output->intent_p2 = image.get_attribute_as<float>(AttrID_nifti_intent_p2, 0);
+ output->intent_p3 = image.get_attribute_as<float>(AttrID_nifti_intent_p3, 0);
string intent_name = image.get_attribute_as<string>(AttrID_nifti_intent_name, "");
if (!intent_name.empty()) {
strncpy(output->intent_name, intent_name.c_str(), 14);
diff --git a/addons/nifti/test_niftiimage.cc b/addons/nifti/test_niftiimage.cc
index a427453..6a2ed1d 100644
--- a/addons/nifti/test_niftiimage.cc
+++ b/addons/nifti/test_niftiimage.cc
@@ -67,6 +67,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_simple_write_read, T, type )
pimage->set_voxel_size(voxel);
pimage->set_origin(origin);
pimage->set_rotation(rot);
+ pimage->set_attribute("nifti-qform-code", 1);
CNifti3DImageIOPlugin io;
CNifti3DImageIOPlugin::Data images;
diff --git a/cmake/macros.cmake b/cmake/macros.cmake
index 8c495d7..907a644 100644
--- a/cmake/macros.cmake
+++ b/cmake/macros.cmake
@@ -120,30 +120,70 @@ MACRO(ASSERT_SIZE NAME EXPECTED)
ENDIF(NOT ${${NAME}_TYPE_SIZE} EQUAL ${EXPECTED})
ENDMACRO(ASSERT_SIZE)
-MACRO(CREATE_EXE_DOCU name)
-
+
+
+#
+# This macro runs the program to create the XMLprogram descrition
+# that is used to create documentation and interfaced
+#
+MACRO(CREATE_EXE_XML_HELP name)
ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml
COMMAND MIA_PLUGIN_TESTPATH=${PLUGIN_TEST_ROOT}/${PLUGIN_INSTALL_PATH}
./mia-${name} --help-xml ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml
COMMAND rm -f ${CMAKE_SOURCE_DIR}/doc/userref.stamp
- DEPENDS mia-${name} plugin_test_links )
+ DEPENDS mia-${name} )
ADD_CUSTOM_TARGET(mia-${name}-xml DEPENDS ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml)
ADD_DEPENDENCIES(XMLDOC mia-${name}-xml)
-
- SET(${name}-manfile ${CMAKE_BINARY_DIR}/doc/man/mia-${name}.1)
-
- ADD_CUSTOM_COMMAND(OUTPUT ${${name}-manfile}
- COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/doc/miaxml2man.py
- ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml >${${name}-manfile}
- MAIN_DEPENDENCY ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml
- DEPENDS mandir mia-${name}-xml
- )
- ADD_CUSTOM_TARGET(mia-${name}-man DEPENDS ${${name}-manfile})
- add_dependencies(manpages mia-${name}-man)
-ENDMACRO(CREATE_EXE_DOCU)
+ENDMACRO(CREATE_EXE_XML_HELP)
+
+
+MACRO(CREATE_NIPYPE_FROM_XML name)
+ IF(CREATE_NIPYPE_INTERFACES)
+ STRING(REPLACE "-" "_" PythonName ${name})
+
+ SET(${name}-nipype-interface ${CMAKE_CURRENT_BINARY_DIR}/mia_${PythonName}.py)
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${${name}-nipype-interface}
+ COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/doc/miaxml2nipype.py
+ -i ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml -o ${${name}-nipype-interface}
+ MAIN_DEPENDENCY ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml)
+
+ ADD_CUSTOM_TARGET(mia-${name}-nipype DEPENDS ${${name}-nipype-interface})
+ ADD_DEPENDENCIES(nipypeinterfaces mia-${name}-nipype)
+
+ INSTALL(FILES ${${name}-nipype-interface} DESTINATION ${NIPYPE_INTERFACE_DIR}/mia)
+
+ ENDIF(CREATE_NIPYPE_INTERFACES)
+ENDMACRO(CREATE_NIPYPE_FROM_XML)
+#
+#
+# man pages can only be created if the python + lxml packages are available
+#
+MACRO(CREATE_MANPAGE_FROM_XML name)
+ IF(CREATE_USERDOC)
+
+ SET(${name}-manfile ${CMAKE_BINARY_DIR}/doc/man/mia-${name}.1)
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${${name}-manfile}
+ COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/doc/miaxml2man.py
+ ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml >${${name}-manfile}
+ MAIN_DEPENDENCY ${CMAKE_BINARY_DIR}/doc/mia-${name}.xml
+ DEPENDS mandir mia-${name}-xml
+ )
+ ADD_CUSTOM_TARGET(mia-${name}-man DEPENDS ${${name}-manfile})
+ add_dependencies(manpages mia-${name}-man)
+ ENDIF(CREATE_USERDOC)
+
+ENDMACRO(CREATE_MANPAGE_FROM_XML)
+#MACRO(MIA_EXE_CREATE_DOCU_AND_INTERFACE name)
+# CREATE_EXE_XML_HELP(${name})
+# CREATE_MANPAGE_FROM_XML(${name})
+# CREATE_NIPYPE_FROM_XML(${name})
+# ENDMACRO(MIA_EXE_CREATE_DOCU_AND_INTERFACE)
+
MACRO(DEFEXE name libraries)
ADD_EXECUTABLE(mia-${name} ${name}.cc)
FOREACH(lib ${libraries})
@@ -152,20 +192,25 @@ MACRO(DEFEXE name libraries)
TARGET_LINK_LIBRARIES(mia-${name} ${BASELIBS})
INSTALL(TARGETS mia-${name} RUNTIME DESTINATION "bin")
- CREATE_EXE_DOCU(${name})
+ ADD_DEPENDENCIES(mia-${name} plugin_test_links)
+ MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia ${name})
ENDMACRO(DEFEXE)
+
MACRO(DEFCHKEXE name deps)
- ADD_EXECUTABLE(mia-${name} ${name}.cc)
-
- FOREACH(lib ${deps})
- TARGET_LINK_LIBRARIES(mia-${name} ${lib})
- ENDFOREACH(lib)
- SET_TARGET_PROPERTIES(mia-${name} PROPERTIES COMPILE_FLAGS -DVSTREAM='\\\"TEST-2D\\\"' COMPILE_FLAGS -DBOOST_TEST_DYN_LINK)
- TARGET_LINK_LIBRARIES(mia-${name} ${BASELIBS})
- TARGET_LINK_LIBRARIES(mia-${name} ${BOOST_UNITTEST})
- INSTALL(TARGETS mia-${name} RUNTIME DESTINATION "bin")
- CREATE_EXE_DOCU(${name})
+ ADD_EXECUTABLE(mia-${name} ${name}.cc)
+
+ FOREACH(lib ${deps})
+ TARGET_LINK_LIBRARIES(mia-${name} ${lib})
+ ENDFOREACH(lib)
+ SET_TARGET_PROPERTIES(mia-${name} PROPERTIES COMPILE_FLAGS -DVSTREAM='\\\"TEST-2D\\\"' COMPILE_FLAGS -DBOOST_TEST_DYN_LINK)
+ TARGET_LINK_LIBRARIES(mia-${name} ${BASELIBS})
+ TARGET_LINK_LIBRARIES(mia-${name} ${BOOST_UNITTEST})
+ INSTALL(TARGETS mia-${name} RUNTIME DESTINATION "bin")
+
+ MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia ${name})
+ ADD_DEPENDENCIES(mia-${name} plugin_test_links)
+ ADD_TEST(${name} mia-${name} --selftest)
ENDMACRO(DEFCHKEXE)
@@ -177,5 +222,6 @@ MACRO(NEW_TEST name libs)
IF (NOT WIN32)
TARGET_LINK_LIBRARIES(${EXENAME} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
ENDIF (NOT WIN32)
+ ADD_DEPENDENCIES(${EXENAME} plugin_test_links)
ADD_TEST(${name} ${EXENAME})
ENDMACRO(NEW_TEST)
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index 8df7b73..3f7cd58 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -19,18 +19,32 @@
INCLUDE (${CMAKE_ROOT}/Modules/FindDoxygen.cmake)
+
ADD_CUSTOM_TARGET(docs echo "creating documentation")
add_dependencies(doc docs)
-IF(CREATE_USERDOC)
+SET(MIADOCTOOLS_FILES
+ miareadxml.py
+ miawritprogram.py
+ MiaDoctools.cmake
+ __init__.py
+ )
- add_dependencies(docs manpages)
- IF(ALWAYS_CREATE_DOC)
- INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/man/ DESTINATION share/man/man1/)
- ENDIF(ALWAYS_CREATE_DOC)
+SET(MIADOCTOOLS_PYTHON_EXE
+ miaxml2man.py
+ miaxml2nipype.py
+ miaxml2sgml.py
+ )
+
+INSTALL(FILES ${MIADOCTOOLS_FILES} DESTINATION ${MIA_DOCTOOLS_INSTALL_ROOT})
+
+INSTALL(PROGRAMS ${MIADOCTOOLS_PYTHON_EXE} DESTINATION ${MIA_DOCTOOLS_INSTALL_ROOT})
+
+
+IF(CREATE_USERDOC)
##################################################################
- # for html userref xsltproc and the style sheet is needed
+ # for html userref xsltproc and the style sheet is needed
#
find_program(XSLTPROC xsltproc)
IF(XSLTPROC)
@@ -59,6 +73,14 @@ IF(CREATE_USERDOC)
COMMAND ln ARGS -sf ${CMAKE_CURRENT_SOURCE_DIR}/progref.xml ${CMAKE_CURRENT_BINARY_DIR}/progref.xml)
ADD_CUSTOM_TARGET(progref_link DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/progref.xml)
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/program.xml
+ COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_CURRENT_SOURCE_DIR}/miaxml2sgml.py ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS xmldoc
+ )
+
+ ADD_CUSTOM_TARGET(process_xml DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/program.xml)
+
ADD_CUSTOM_COMMAND(OUTPUT "userref.stamp"
COMMAND
@@ -70,10 +92,10 @@ IF(CREATE_USERDOC)
--output "userref/"
${HTML_CHUNK_FILEPATH}/chunk.xsl progref.xml
COMMAND touch ARGS userref.stamp
- DEPENDS process_xml userref_css userref_outdir progref_link ${CMAKE_CURRENT_BINARY_DIR}/program.xml
- )
+ DEPENDS process_xml userref_css userref_outdir progref_link ${CMAKE_CURRENT_BINARY_DIR}/program.xml )
+
ADD_CUSTOM_TARGET(userref DEPENDS userref.stamp)
- add_dependencies(docs userref)
+ add_dependencies(docs userref)
####################################################
#
@@ -85,7 +107,7 @@ IF(CREATE_USERDOC)
ENDIF(ALWAYS_CREATE_DOC)
ENDIF(HTML_CHUNK_FILEPATH)
-ENDIF(CREATE_USERDOC)
+ENDIF(CREATE_USERDOC)
IF (DOXYGEN_FOUND)
ADD_CUSTOM_TARGET(LibraryDoc echo "creating user library documentation")
diff --git a/doc/MiaDoctools.cmake b/doc/MiaDoctools.cmake
new file mode 100644
index 0000000..b9e4ca1
--- /dev/null
+++ b/doc/MiaDoctools.cmake
@@ -0,0 +1,187 @@
+#
+# This file is part of MIA - a toolbox for medical image analysis
+# Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+#
+# MIA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+
+
+#
+# This macro is used to prepare the creation of the man pages and
+# interfaces
+# - prefix will be used to set the prefix of the executables and the
+# target directory of the nipype interface
+#
+MACRO(MIA_PREPARE_AUTODOC prefix)
+
+ IF(NOT MIA_DOCTOOLS_ROOT)
+ SET(MIA_DOCTOOLS_ROOT "${CMAKE_SOURCE_DIR}/doc")
+ ENDIF(NOT MIA_DOCTOOLS_ROOT)
+
+ OPTION(MIA_CREATE_MANPAGES "Create the man pages for the executables (Required Python and python-lxml)" OFF)
+ OPTION(MIA_CREATE_NIPYPE_INTERFACES "Create the nipype interfaces for the executables (Required Python,python-lxml, and nipype)" OFF)
+
+ IF(MIA_CREATE_MANPAGES OR MIA_CREATE_NIPYPE)
+
+ FIND_PACKAGE(PythonInterp REQUIRED)
+ EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import lxml" RESULT_VARIABLE LXML_ERR)
+ IF(LXML_ERR)
+ MESSAGE(FATAL "Python found, but no pythonl-xml")
+ ENDIF(LXML_ERR)
+
+ IF(MIA_CREATE_MANPAGES)
+ ADD_CUSTOM_TARGET(manpages ALL)
+ ENDIF()
+
+ IF(MIA_CREATE_NIPYPE_INTERFACES)
+ file(WRITE ${NIPYPE_INTERFACE_INIT_FILE} "# Automatically generated file, do not edit\n")
+
+ STRING(COMPARE EQUAL "${CMAKE_INSTALL_PREFIX}" "/usr" INSTALLROOT_IS_USER)
+
+ IF(INSTALLROOT_IS_USER)
+ EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib\nimport sys\nsys.stdout.write(get_python_lib())"
+ RESULT_VARIABLE SITEPACKGE_ERR
+ OUTPUT_VARIABLE SITEPACKGE_BASE_PATH)
+ ELSE()
+ EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} -c "import site\nimport sys\nsys.stdout.write(site.getusersitepackages())"
+ RESULT_VARIABLE SITEPACKGE_ERR
+ OUTPUT_VARIABLE SITEPACKGE_BASE_PATH)
+ ENDIF()
+
+ IF(SITEPACKGE_ERR)
+ MESSAGE(FATAL "Something went wrong identifying the nipype installation loaction")
+ ENDIF()
+
+ SET(NIPYPE_INTERFACE_DIR "${SITEPACKGE_BASE_PATH}/${prefix}/nipype/interfaces/")
+
+
+
+ MESSAGE(STATUS "Will create nipype interfaces and install to " ${NIPYPE_INTERFACE_DIR})
+
+ ADD_CUSTOM_TARGET(nipypeinterfaces ALL)
+ INSTALL(FILES ${NIPYPE_INTERFACE_INIT_FILE} DESTINATION ${NIPYPE_INTERFACE_DIR})
+ ENDIF()
+ ENDIF()
+
+ # install empty init files
+ INSTALL(FILES ${MIA_DOCTOOLS_ROOT}/__init__.py DESTINATION ${SITEPACKGE_BASE_PATH}/${prefix})
+ INSTALL(FILES ${MIA_DOCTOOLS_ROOT}/__init__.py DESTINATION ${SITEPACKGE_BASE_PATH}/${prefix}/nipype)
+
+ENDMACRO(MIA_PREPARE_AUTODOC)
+
+
+#
+# INTERNAL USE
+# This macro runs the program to create the XML program descrition
+# that is used to create documentation and interfaced
+# TODO: add possible plug-ins that come directly from the software package
+#
+MACRO(MIA_CREATE_EXE_XML_HELP prefix name)
+ ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml
+ COMMAND MIA_PLUGIN_TESTPATH=${PLUGIN_TEST_ROOT}/${PLUGIN_INSTALL_PATH} ./${prefix}-${name} --help-xml ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml
+ DEPENDS ${prefix}-${name})
+
+ ADD_CUSTOM_TARGET(${prefix}-${name}-xml DEPENDS ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml)
+ ADD_DEPENDENCIES(xmldoc ${prefix}-${name}-xml)
+ENDMACRO(MIA_CREATE_EXE_XML_HELP)
+
+#
+# INTERNAL USE
+# Create the nipype interface from the xml doc description
+# and add it to the install target
+#
+
+MACRO(MIA_CREATE_NIPYPE_FROM_XML prefix name)
+ STRING(REPLACE "-" "_" PythonName ${name})
+
+ SET(${prefix}-${name}-nipype-interface ${CMAKE_CURRENT_BINARY_DIR}/${prefix}_${PythonName}.py)
+
+ ADD_CUSTOM_COMMAND(OUTPUT ${${prefix}-${name}-nipype-interface}
+ COMMAND ${PYTHON_EXECUTABLE} ${MIA_DOCTOOLS_ROOT}/miaxml2nipype.py -i ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml -o ${${prefix}-${name}-nipype-interface}
+ MAIN_DEPENDENCY ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml)
+
+ FILE(APPEND ${NIPYPE_INTERFACE_INIT_FILE} "from .${prefix}_${PythonName} import ${prefix}_${PythonName}\n")
+
+ ADD_CUSTOM_TARGET(${prefix}-${name}-nipype DEPENDS ${${prefix}-${name}-nipype-interface})
+ ADD_DEPENDENCIES(nipypeinterfaces ${prefix}-${name}-nipype)
+
+ INSTALL(FILES ${${prefix}-${name}-nipype-interface} DESTINATION ${NIPYPE_INTERFACE_DIR})
+ENDMACRO(MIA_CREATE_NIPYPE_FROM_XML)
+
+#
+# INTERNAL USE
+# Create the man page from the xml doc description
+# and add it to the install target
+#
+MACRO(MIA_CREATE_MANPAGE_FROM_XML prefix name)
+ SET(${prefix}-${name}-manfile ${CMAKE_CURRENT_BINARY_DIR}/${prefix}-${name}.1)
+ ADD_CUSTOM_COMMAND(OUTPUT ${${prefix}-${name}-manfile}
+ COMMAND ${PYTHON_EXECUTABLE} ${MIA_DOCTOOLS_ROOT}/miaxml2man.py ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml >${${prefix}-${name}-manfile}
+ MAIN_DEPENDENCY ${CMAKE_BINARY_DIR}/doc/${prefix}-${name}.xml
+ )
+ ADD_CUSTOM_TARGET(${prefix}-${name}-man DEPENDS ${${prefix}-${name}-manfile})
+ add_dependencies(manpages ${prefix}-${name}-man)
+ INSTALL(FILES ${${prefix}-${name}-manfile} DESTINATION "share/man/man1")
+ENDMACRO(MIA_CREATE_MANPAGE_FROM_XML)
+
+
+#
+# INTERNAL USE
+# Run the necessary steps to create the documentation
+# and nipype interfaces (if enabled)
+#
+
+MACRO(MIA_EXE_CREATE_DOCU_AND_INTERFACE prefix name)
+ MIA_CREATE_EXE_XML_HELP(${prefix} ${name})
+
+ IF(MIA_CREATE_MANPAGES)
+ MIA_CREATE_MANPAGE_FROM_XML(${prefix} ${name})
+ ENDIF(MIA_CREATE_MANPAGES)
+
+ IF(MIA_CREATE_NIPYPE_INTERFACES)
+ MIA_CREATE_NIPYPE_FROM_XML(${prefix} ${name})
+ ENDIF(MIA_CREATE_NIPYPE_INTERFACES)
+
+ENDMACRO(MIA_EXE_CREATE_DOCU_AND_INTERFACE)
+
+#
+# Create an executable and its documentation and nipype interface
+# Parameters:
+# prefix: napespace prefix of the exe
+# name: functional name of the exe
+# libraries: libraries to link this exe against
+#
+MACRO(MIA_DEFEXE prefix name libraries)
+ ADD_EXECUTABLE(${prefix}-${name} ${name}.cc)
+ TARGET_LINK_LIBRARIES(${prefix}-${name} ${libraries})
+ INSTALL(TARGETS ${prefix}-${name} RUNTIME DESTINATION "bin")
+ MIA_EXE_CREATE_DOCU_AND_INTERFACE(${prefix} ${name})
+
+ENDMACRO(MIA_DEFEXE)
+
+#
+# Create an executable and its documentation and nipype interface
+# that also provides a selftest
+#
+# Parameters:
+# prefix: napespace prefix of the exe
+# name: functional name of the exe
+# libraries: libraries to link this exe against
+#
+MACRO(MIA_DEFEXE_WITH_TEST prefix name deps)
+
+ MIA_DEFEXE(${prefix} ${name} ${deps})
+ ADD_TEST(${name} ${prefix}-${name} --selftest)
+
+ENDMACRO(MIA_DEFEXE_WITH_TEST)
diff --git a/doc/__init__.py b/doc/__init__.py
new file mode 100644
index 0000000..2129291
--- /dev/null
+++ b/doc/__init__.py
@@ -0,0 +1 @@
+# Emty file to ensure python finds the modules
diff --git a/doc/extract_docu.py b/doc/extract_docu.py
deleted file mode 100644
index e55fcf6..0000000
--- a/doc/extract_docu.py
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (C) 2011 Gert Wollny <gw.fossdev at gmail.com>
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-
-import sys
-import re
-import string
-from fnmatch import fnmatch
-from os.path import walk
-
-
-
-class CPatternCollector:
- def __init__(self, pattern):
- self.pattern = pattern
- self.files=[]
-
-
-def collect_files(arg, dirname, names):
- for f in names:
- if fnmatch(f, arg.pattern):
- arg.files.append(dirname + "/" + f)
-
-
-
-def find_files(root, pattern):
- arg = CPatternCollector(pattern)
- walk(root, collect_files, arg)
- return arg.files
-
-class DocuSection:
- def __init__(self):
- self.body = []
- self.subsections = {}
- self.unspecified = []
-
- def append_to_body(self, text_block):
- self.body.extend(text_block)
-
- def append_plugin(self, text_block):
- for l in text_block:
- e = re.search("subsection\{(.*)\}", l)
- if e:
- self.subsections[e.group(1)] = text_block
- return
- self.unspecified.extend(text_block)
-
- def write(self, output):
- for l in self.body:
- output.write(l)
- for k in sorted(self.subsections.keys()):
- sys.stderr.write(" {}\n".format(k))
- for l in self.subsections[k]:
- output.write(l)
-
- for l in self.unspecified:
- output.write(l)
-
-
-class DocuCharpter:
- def __init__(self):
- self.sections = {}
-
- def add(self, key1, key2, text_block):
- if not self.sections.has_key(key2):
- self.sections[key2] = DocuSection()
-
- if key1 == "Section":
- self.sections[key2].append_to_body(text_block)
-
- if key1 == "Description":
- self.sections[key2].append_plugin(text_block)
-
- def write(self, output):
- for s in sorted(self.sections.keys()):
- sys.stderr.write("{0}\n".format(s))
- output.write("\\section{{{0}}}".format(s))
- self.sections[s].write(output)
-
-
-# this will be a list of lists containing all the documentation comment blocks
-comment_blocks = []
-
-
-root= sys.argv[1]
-program_filename = sys.argv[2]
-plugin_filename = sys.argv[3]
-files = find_files(root, "*.cc")
-
-# read all files and extract comment blocks
-for f in files:
-
- # ignore some emacs security copies
- h = re.search("/\.#[-a-z0-9]*\.cc", f)
- if h:
- continue
-
-
- infile = open(f,"r")
- lines = infile.readlines()
-
- current_block = []
- is_text = False
-
- for l in lines:
- if is_text:
- e = re.search("(?<=LatexEnd)", l)
- if not e:
- current_block.append(l)
- else:
- comment_blocks.append(current_block)
- is_text = False
- else:
- m = re.search("LatexBegin", l)
- if not m:
- continue
- else:
- current_block = [l]
- is_text = True
-
- if is_text:
- print "No LatexEnd in {}".format(f)
- exit(1)
- infile.close()
-
-
-plugin_sections = DocuCharpter()
-program_sections = DocuCharpter()
-
-for b in comment_blocks:
- m = re.search(" *LatexBegin(P[a-z]*)([A-Z][a-z]*){(.*)}", b[0])
-
- type_key = m.group(1)
- if type_key == "Plugin":
- plugin_sections.add(m.group(2), m.group(3), b[1:])
- elif type_key == "Program":
- program_sections.add(m.group(2), m.group(3), b[1:])
-
-
-
-
-program_file = open(program_filename,"w")
-program_sections.write(program_file)
-
-
-plugin_file = open(plugin_filename,"w")
-plugin_sections.write(plugin_file)
-
diff --git a/doc/mia-xmldoc2man.cmake b/doc/mia-xmldoc2man.cmake
new file mode 100644
index 0000000..0e3712b
--- /dev/null
+++ b/doc/mia-xmldoc2man.cmake
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+miadoctoolroot=@MIA_DOCTOOLS_ROOT@
+
+$miadoctoolroot/miaxml2man.py $1 >$2
diff --git a/doc/mia-xmldoc2nipype.cmake b/doc/mia-xmldoc2nipype.cmake
new file mode 100644
index 0000000..cf5e14a
--- /dev/null
+++ b/doc/mia-xmldoc2nipype.cmake
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+miadoctoolroot=@MIA_DOCTOOLS_ROOT@
+
+$miadoctoolroot/miaxml2nipype.py -i $1 -o $2
diff --git a/doc/miareadxml.py b/doc/miareadxml.py
index feef71e..d700bb4 100644
--- a/doc/miareadxml.py
+++ b/doc/miareadxml.py
@@ -27,6 +27,7 @@ xmlns = "{%s}" % xml_namespace
# supported tags:
# program main tag
# name text: program name
+# version text: package version number
# section text: program type
# description text: basic description of the program
# basic_usage text: generic call
@@ -83,24 +84,54 @@ class CTextNode:
if not expect is None and node.tag != expect:
raise ValueError("expected '%s' got '%s'" % (expect, node.tag))
+ self.required = False
+ self.is_input = False
+ self.is_output = False
+ self.no_nipype = False
self.entry = node.tag
- self.flags = []
+ self.flags = set()
self.text = ""
if node.text is not None:
self.text = self.text + node.text
for child in node.iter("flags"):
- self.flags = self.flags + string.split(child.text)
+ f = string.split(child.text)
+ for ff in f:
+ self.flags.add(ff)
if child.tail is not None:
self.text = self.text + child.tail
+ for f in self.flags:
+ p = {
+ "required": self.set_is_required,
+ "input": self.set_is_input,
+ "output": self.set_is_output,
+ "nonipype": self.set_nipype_ignore,
+ }.get(f, self.dummy)(f)
+
+ def set_is_required(self, f):
+ self.required = True
+
+ def set_is_input(self, f):
+ self.is_input = True
+
+ def set_is_output(self, f):
+ self.is_output = True
+
+ def set_nipype_ignore(self, f):
+ self.no_nipype = True
+
+ def dummy(self, f):
+ warnings.warn ('Unknown flag "{}" encountered'.format(f))
+
+
class COption(CTextNode):
def __init__(self, node):
CTextNode.__init__(self, node, "option")
self.short = node.get("short")
self.long = node.get("long")
- self.required = int(node.get("required"))
+# self.required = int(node.get("required"))
self.default = node.get("default")
self.type = node.get("type")
@@ -111,9 +142,13 @@ class COption(CTextNode):
short = " ";
if len(self.flags) > 0:
- flagstring = self.flags[0]
- for f in self.flags[1:]:
- flagstring = flagstring + ',' + f
+ flagstring = ""
+ for f in self.flags:
+ if f != "nonipype":
+ if len(flagstring) == 0:
+ flagstring = f
+ else:
+ flagstring = flagstring + ', ' + f
print ".IP \"%s \-\-%s=(%s)\""% (short, self.long, flagstring)
else:
if not self.type == "bool":
@@ -135,9 +170,15 @@ class COption(CTextNode):
termtext = termtext + "-" + self.long
if len(self.flags) > 0:
- termtext = termtext + "=(" + self.flags[0]
- for f in self.flags[1:]:
- termtext = termtext + ',' + f
+ termtext = termtext + "=("
+ first = True
+ for f in self.flags:
+ if f != "nonipype":
+ if first:
+ termtext = termtext + f
+ first=False
+ else:
+ termtext = termtext + ", " + f
termtext = termtext + ")"
elif self.type != "bool":
termtext = termtext + "="
@@ -164,6 +205,11 @@ class CDictOption(COption):
for child in node.iter("dict"):
for v in child:
self.dict[v.get("name")] = v.text
+ def get_names_as_string(self):
+ result = ""
+ for k in self.dict.keys():
+ result = result + '"' + k + '", '
+ return result
def do_print_man(self):
if len(self.dict) > 0:
@@ -182,6 +228,44 @@ class CDictOption(COption):
parent.append(opttable)
+class CSetOption(COption):
+ def __init__(self, node):
+ COption.__init__(self, node)
+ self.set = []
+ for child in node.iter("set"):
+ for cc in child.iter("value"):
+ self.set.append(cc.get("name"))
+
+ def get_names_as_string(self):
+ result = ""
+ for k in self.set:
+ result = result + '"' + k + '", '
+ return result
+
+ def do_print_man(self):
+ if len(self.set) > 0:
+ print ""
+ print ".RS 10"
+ print ".I"
+
+ print "Supported values are:(",
+ for k in self.set:
+ print "%s, " % (escape_dash(k)),
+ print ")"
+ print ".RE"
+
+
+ def do_write_xml(self, parent):
+ if len(self.set) > 0:
+ e = etree.SubElement(parent, "entry", align="left", valign="top")
+ str_list = [" Supported values are:("]
+
+ for k in self.set:
+ str_list.append("%s, " % (k))
+ str_list.append(")")
+ e.text = ''.join(str_list)
+
+
class CIOOption(COption):
def __init__(self, node):
COption.__init__(self, node)
@@ -248,6 +332,7 @@ class CGroup:
"io": lambda n: CIOOption(n),
"factory": lambda n: CFactoryOption(n),
"dict": lambda n: CDictOption(n),
+ "set": lambda n: CSetOption(n),
}.get(child.get("type"), lambda n: COption(n))(child)
self.options.append(p)
else:
@@ -266,12 +351,15 @@ class CParam:
self.name = node.get("name")
self.type = node.get("type")
self.default = node.get("default")
- self.required = int(node.get("required"))
self.text = node.text
- self.flags = []
+ self.required = False
+ self.no_nipype = False
+ self.flags = set()
for child in node.iter("flags"):
- self.flags = self.flags + string.split(child.text)
+ f = string.split(child.text)
+ for ff in f:
+ self.flags.add(ff)
if child.tail is not None:
self.text = self.text + child.tail
@@ -280,13 +368,45 @@ class CParam:
if m is not None:
self.default = "[" + self.default + "]"
+ for f in self.flags:
+ p = {
+ "required": self.set_is_required,
+ "input": self.set_is_input,
+ "output": self.set_is_output,
+ "nonipype": self.set_nipype_ignore,
+ }.get(f, self.dummy)(f)
+
+ def set_is_required(self, f):
+ self.required = True
+
+ def set_is_input(self, f):
+ self.is_input = True
+
+ def set_is_output(self, f):
+ self.is_output = True
+
+ def set_nipype_ignore(self, f):
+ self.no_nipype = True
+
+ def dummy(self, f):
+ warnings.warn ('Unknown flag "{}" encountered'.format(f))
+
+
def print_man(self):
print ".I"
print self.name
+
+
if len(self.flags) > 0:
- termtext = "=(" + self.flags[0]
- for f in self.flags[1:]:
- termtext = termtext + ',' + f
+ termtext = ""
+ for f in self.flags:
+ if f == "nonipype":
+ continue
+ if len(termtext) == 0:
+ termtext = "=(" + f
+ else:
+ termtext = termtext + ', ' + f
+
termtext = termtext + ", %s)"
print termtext % (self.type)
elif self.required:
@@ -308,10 +428,17 @@ class CParam:
e = etree.SubElement(row, "entry", align="center", valign="top")
e.text = self.type
e = etree.SubElement(row, "entry", align="center", valign="top")
+
if len(self.flags) > 0:
- e.text = "(" + self.flags[0]
- for f in self.flags[1:]:
- e.text = e.text + ',' + f
+ first = True
+ for f in self.flags:
+ if f == "nonipype":
+ continue
+ if first:
+ e.text = "(" + f
+ first = False
+ else:
+ e.text = e.text + ',' + f
e.text = e.text + ')'
elif self.required:
e.text = "(required)"
@@ -585,6 +712,7 @@ class CDescription:
def __init__(self, node):
self.Example = None
self.FreeParams = None
+ self.stdout_is_result = False
self.option_groups = []
self.handlers = {}
for n in node:
@@ -592,6 +720,8 @@ class CDescription:
self.name = n.text
elif n.tag == 'section':
self.section = n.text
+ elif n.tag == 'version':
+ self.version = n.text
elif n.tag == 'whatis':
self.whatis = n.text
elif n.tag == 'description':
@@ -609,6 +739,8 @@ class CDescription:
self.author = n.text
elif n.tag == 'freeparams':
self.FreeParams = n.get("name")
+ elif n.tag == "stdout-is-result":
+ self.stdout_is_result = True
else:
print "unknown tag '%s'"% (n.tag)
self.anchor = make_sec_ancor("Sec", self.name)
diff --git a/doc/miaxml2html.py b/doc/miaxml2html.py
deleted file mode 100644
index 26b0a03..0000000
--- a/doc/miaxml2html.py
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/env python
-
-import sys
-import re
-from lxml import etree
-
-sys.dont_write_bytecode = True
-
-modules = {'miareadxml' : [0, '', 'none://miareadxml.py' ]
- }
-from miareadxml import parse_file
-
-def make_ancor(text):
- """remove spaces and hyphens from the input string"""
- return re.sub("[ -]", "", text)
-
-class CPatternCollector:
- def __init__(self, pattern):
- self.pattern = pattern
- self.files=[]
-
-
-def collect_files(arg, dirname, names):
- for f in names:
- if fnmatch(f, arg.pattern):
- arg.files.append(dirname + "/" + f)
-
-def find_files(root, pattern):
- arg = CPatternCollector(pattern)
- walk(root, collect_files, arg)
- return arg.files
-
-def create_text_node(tag, text):
- node = etree.Element(tag)
- node.set_text(text)
-
-def get_program(prog):
- progsec = etree.Element("section", id=make_ancor(prog.name))
- title = create_text_node("title", prog.name)
- descr = create_text_node("para", prog.description)
- basic_usage = create_text_node("code", prog.description)
- progsec.append(title)
- progsec.append(descr)
- return progsec
-
-
-def get_section(name, programs):
- section = etree.Element("section", id=make_ancor(name))
- title = etree.Element("title")
- title.set_text(name)
- section.append(title)
- for p in sec.programs:
- section.append(get_program(p))
- return section
-
-def get_plugin(plugin):
- section = etree.Element("section", id=make_ancor(name))
-
-def get_plugins(name, plugins):
- section = etree.Element("section", id=make_ancor(name))
- title = create_text_node("title", name)
- section.append(title)
- for p in plugins:
- section.append(get_plugin(p))
- return section
-
-
-
-files = find_files(".", "mia-*.xml")
-
-descriptions=[]
-
-for f in files:
- d = parse_file(f)
- descriptions.append(d)
-
-program_sections = {}
-
-
-plugin_types = {}
-
-for d in descriptions:
- if not program_sections.has_key(d.section):
- program_sections[d.section] = []
- program_sections[d.section].append(d)
-
- for h in d.handlers:
- if not plugin_types.has_key(h.name):
- plugin_types[h.name] = h
- plugin_types[h.name].append_user(d.name)
-
-
-
-#Now convert to linuxdoc format - these are also XML files
-prog_xml = etree.Element("chapter", id="programs")
-title = create_text_node("title", "Program Reference")
-prog_xml.append(title)
-
-for s in program_sections.keys():
- prog_xml.append(get_section(s, program_sections[s]))
-
-
-plug_xml = etree.Element("chapter", id="plugins")
-title = create_text_node("title", "Plugin Reference")
-plug_xml.append(title)
-
-for s in plugin_types.keys():
- plug_xml.append(get_plugins(s, program_sections[s]))
-
-
-
-
diff --git a/doc/miaxml2man.py b/doc/miaxml2man.py
index 0dbec76..f194a5a 100644
--- a/doc/miaxml2man.py
+++ b/doc/miaxml2man.py
@@ -1,4 +1,4 @@
-#!/bin/env python
+#!/usr/bin/env python
#
# Copyright (c) Leipzig, Madrid 1999-2012 Gert Wollny
#
@@ -39,9 +39,6 @@ def get_date_string():
lt = time.localtime(time.time())
return "%d %s %d"% (lt.tm_mday, calendar.month_name[lt.tm_mon], lt.tm_year)
-def get_version():
- return "2.0.10"
-
#taken from http://effbot.org/zone/re-sub.htm#unescape-html
def unescape(text):
@@ -74,7 +71,7 @@ def clean (text):
def write_man_file(descr):
name = escape_dash(descr.name)
- print ".TH %s 1 \"%s\" \"%s\" \"USER COMMANDS\"" %(escape_dash(descr.name), get_date_string(), get_version())
+ print ".TH %s 1 \"%s\" \"v%s\" \"USER COMMANDS\"" %(escape_dash(descr.name), get_date_string(), descr.version)
print ".SH NAME"
print name,
print "\- %s" % (clean(descr.whatis))
diff --git a/doc/miaxml2nipype.py b/doc/miaxml2nipype.py
new file mode 100644
index 0000000..35b6ceb
--- /dev/null
+++ b/doc/miaxml2nipype.py
@@ -0,0 +1,366 @@
+#!/usr/bin/env python
+#
+# Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+# this program is used to translate the XML files obtained by running
+# a mia-* program with --help-xml into a nipype interface
+
+import sys
+import time
+import calendar
+import string
+import htmlentitydefs
+import re
+from os import path
+
+from argparse import ArgumentParser
+from argparse import RawTextHelpFormatter
+
+sys.dont_write_bytecode = True
+
+modules = {'miareadxml' : [0, '', 'none://miareadxml.py' ]
+ }
+
+
+nipype_header = """from nipype.interfaces.base import (
+ TraitedSpec,
+ CommandLineInputSpec,
+ CommandLine,
+ File,
+ traits
+ )
+import os"""
+
+
+from miareadxml import parse_file
+
+def get_date_string():
+ lt = time.localtime(time.time())
+ return "%d %s %d"% (lt.tm_mday, calendar.month_name[lt.tm_mon], lt.tm_year)
+
+#taken from http://effbot.org/zone/re-sub.htm#unescape-html
+
+def unescape(text):
+ def fixup(m):
+ text = m.group(0)
+ if text[:2] == "&#":
+ # character reference
+ try:
+ if text[:3] == "&#x":
+ return unichr(int(text[3:-1], 16))
+ else:
+ return unichr(int(text[2:-1]))
+ except ValueError:
+ pass
+ else:
+ # named entity
+ try:
+ text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
+ except KeyError:
+ pass
+ return text # leave as is
+ return re.sub("&#?\w+;", fixup, text)
+
+def dash_to_underscore(text):
+ return re.sub(r'-', r'_', text)
+
+def clean (text):
+ text = unescape(text)
+ return escape_dash(text)
+
+
+class NipypeOutput:
+ def __init__(self, input_file, output_file):
+ self.input_file = input_file
+ self.output_file = output_file
+ self.descr = parse_file(input_file)
+ self.out=open(output_file, 'w')
+ self.ParamTable = {
+ "2dbounds" : lambda i : self.create_vint_param(i),
+ "3dbounds" : lambda i : self.create_vint_param(i),
+ "vshort": lambda i : self.create_vint_param(i),
+ "vint": lambda i : self.create_vint_param(i),
+ "vlong": lambda i : self.create_vint_param(i),
+ "vushort": lambda i : self.create_vint_param(i),
+ "vuint": lambda i : self.create_vint_param(i),
+ "vulong": lambda i : self.create_vint_param(i),
+
+ "2dfvector" :lambda i : self.create_vfloat_param(i),
+ "3dfvector" :lambda i : self.create_vfloat_param(i),
+ "vdouble" :lambda i : self.create_vfloat_param(i),
+ "vfloat" :lambda i : self.create_vfloat_param(i),
+
+ "bool" : lambda i : self.create_Bool_param(i),
+ "short" : lambda i : self.create_Integral_param(i),
+ "int" : lambda i : self.create_Integral_param(i),
+ "long" : lambda i : self.create_Integral_param(i),
+ "ushort": lambda i : self.create_Integral_param(i),
+ "uint" : lambda i : self.create_Integral_param(i),
+ "ulong" : lambda i : self.create_Integral_param(i),
+ "float" : lambda i : self.create_Float_param(i),
+ "double": lambda i : self.create_Float_param(i),
+
+ "vstring": lambda i : self.create_input_VString_param(i),
+
+ "dict" : lambda i : self.create_Dict_param(i),
+ "set" : lambda i : self.create_Set_param(i),
+ "factory" : lambda i : self.create_Factory_param(i)
+ }
+
+
+ def create_trait_input_param_start(self, param, trait, enums=""):
+ dash_removed_name = dash_to_underscore(param.long)
+ # this should be implemented for all python keywords
+ if dash_removed_name == "lambda":
+ dash_removed_name = dash_removed_name + "_"
+ self.out.write ( "\t{} = traits.{}({} desc=\"\"\"{}\"\"\", ".format(dash_removed_name,
+ trait, enums, param.text)),
+
+ def create_param_tail(self, param):
+ if param.required:
+ self.out.write (', mandatory = True '),
+ self.out.write( ')\n')
+
+ def create_Bool_param(self, param):
+ self.create_trait_input_param_start(param, 'Bool')
+ self.out.write('argstr="--{}" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_vint_param(self, param):
+ self.create_trait_input_param_start(param, 'ListInt')
+ self.out.write('argstr="--{} %s", sep=","'.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_vfloat_param(self, param):
+ self.create_trait_input_param_start(param, 'ListFloat')
+ self.out.write('argstr="--{} %s", sep=","'.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_input_VString_param(self, param):
+ self.create_trait_input_param_start(param, 'ListString')
+ self.out.write('argstr="--{} %s", sep=","'.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_Integral_param(self, param):
+ self.create_trait_input_param_start(param, 'Int')
+ self.out.write('argstr="--{} %d" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_Float_param(self, param):
+ self.create_trait_input_param_start(param, 'Float')
+ self.out.write('argstr="--{} %f" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_Dict_param(self, param):
+ self.create_trait_input_param_start(param, 'Enum', param.get_names_as_string())
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_Set_param(self, param):
+ self.create_trait_input_param_start(param, 'Enum', param.get_names_as_string())
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_Factory_param(self, param):
+ self.create_trait_input_param_start(param, 'String')
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_input_String_param(self, param):
+ self.create_trait_input_param_start(param, 'String')
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_input_File_param(self, param):
+ self.create_trait_input_param_start(param, 'File')
+ self.out.write('argstr="--{} %s", exists=True '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_output_String_param(self, param):
+ self.out.write ( '\t{} = traits.String(desc="{}", '.format(dash_to_underscore(param.long), param.text)),
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_output_File_param(self, param):
+ self.out.write ( '\t{} = File(desc="{}", '.format(dash_to_underscore(param.long), param.text)),
+ self.out.write('argstr="--{} %s" '.format(param.long)),
+ self.create_param_tail(param)
+
+ def create_output_File_param_outspec(self, param):
+ self.out.write ( '\t{} = File(desc="{}"'.format(dash_to_underscore(param.long), param.text)),
+ if param.required:
+ self.out.write (', exists = True '),
+ self.out.write( ')\n')
+
+ def write_unknown_type(self, param):
+ print ("WARNING: Unknown parameter type '{}' encounterd for option '{}', \n".format(param.long, param.type)),
+
+ def write_input_spec(self, name, inputs, params):
+
+ self.out.write ("class {}_InputSpec(CommandLineInputSpec):\n".format(name))
+
+ InputTable = self.ParamTable
+ InputTable["string"] = lambda i :self.create_input_File_param(i)
+ InputTable["io"] = lambda i :self.create_input_File_param(i)
+
+ for i in inputs:
+ InputTable.get(i.type, self.write_unknown_type)(i)
+
+ ParamTableCopy = self.ParamTable
+ ParamTableCopy["string"] = lambda i :self.create_input_String_param(i)
+
+ for i in params:
+ ParamTableCopy.get(i.type, self.write_unknown_type)(i)
+
+ def write_input_outputs(self, name, outputs, params):
+
+ InputTable = self.ParamTable
+ InputTable["string"] = lambda i :self.create_output_File_param(i)
+ InputTable["io"] = lambda i :self.create_output_File_param(i)
+
+ for i in outputs:
+ InputTable.get(i.type, self.write_unknown_type)(i)
+
+ def write_input_free_params_spec(self, freeparams):
+ self.out.write ( '\tfree_params = traits.ListStr(desc="Plug-in specifications of type {}", '.format(freeparams)),
+ self.out.write ( 'argstr="%s")')
+
+ def write_output_spec(self, name, outputs, params):
+
+ self.out.write ("class {}_OutputSpec(TraitedSpec):\n".format(name))
+
+ ParamTableCopy = self.ParamTable
+ ParamTableCopy["string"] = lambda i :self.create_output_File_param_outspec(i)
+ ParamTableCopy["io"] = lambda i :self.create_output_File_param_outspec(i)
+
+ for i in outputs:
+ ParamTableCopy.get(i.type, self.write_unknown_type)(i)
+
+ if self.descr.stdout_is_result:
+ self.out.write ( '\tstdout = traits.Str(\'result from stdout\')\n')
+
+ self.out.write ("\n")
+
+ def write_task(self, name, outputs):
+
+ self.out.write('class {}(CommandLine):\n'.format(name))
+ self.out.write('\tinput_spec = {}_InputSpec\n'.format(name))
+ self.out.write('\toutput_spec = {}_OutputSpec\n'.format(name))
+ self.out.write('\t_cmd = "{}"\n\n'.format(self.descr.name))
+
+ self.out.write('\tdef _list_outputs(self):\n')
+ self.out.write('\t\toutputs = self.output_spec().get()\n')
+
+ for i in outputs:
+ # there is a problem here: for files that are given as pattern this will fail.
+ if i.type == "io" or i.type == "string":
+ name = dash_to_underscore(i.long)
+ self.out.write('\t\toutputs[\'{}\']=os.path.abspath(self.inputs.{})\n'.format(name,name))
+ else:
+ print('Only io or string supported for output, but got {}'.format(i))
+
+ self.out.write('\t\treturn outputs\n')
+
+ if self.descr.stdout_is_result:
+ self.out.write('\tdef aggregate_outputs(self, runtime=None, needed_outputs=None):\n')
+ self.out.write('\t\toutputs = super({}, self).aggregate_outputs(runtime, needed_outputs)\n'.format(name))
+ self.out.write('\t\toutputs.stdout = runtime.stdout\n')
+ self.out.write('\t\treturn outputs\n')
+
+ def write_main(self, name):
+
+ self.out.write( 'if __name__ == "__main__":\n')
+ self.out.write( '\tmia_prog = {}()\n'.format(name))
+ self.out.write( '\tprint( mia_prog.cmdline)\n')
+
+ def write_nipype_file(self):
+
+ name = dash_to_underscore(self.descr.name)
+
+ inputs =[]
+ outputs = []
+ params = []
+
+ for g in self.descr.option_groups:
+ for o in g.options:
+ if o.no_nipype:
+ continue
+ if o.is_input:
+ inputs.append(o)
+ elif o.is_output:
+ outputs.append(o)
+ else:
+ params.append(o)
+
+ self.out.write("# This file was generated by running 'miaxml2nipype.py {} {}'\n".format(
+ self.input_file, self.output_file))
+ self.out.write("# '{}' can be created by running '{} --help-xml >{}'\n".format(
+ self.output_file, self.descr.name, self.output_file))
+ self.out.write("\n")
+
+ self.out.write(nipype_header)
+ self.out.write("\n#\n# Input specification\n#\n");
+ self.write_input_spec(name, inputs, params)
+ self.write_input_outputs(name, outputs, params)
+ if self.descr.FreeParams is not None:
+ self.write_input_free_params_spec(self.descr.FreeParams)
+
+ self.out.write("\n#\n# Output specification\n#\n");
+ self.write_output_spec(name, outputs, params)
+
+ self.out.write("\n#\n# Task class specification\n#\n");
+ self.write_task(name, outputs)
+
+ self.out.write("\n#\n# Main function used for testing\n#\n");
+ self.write_main(name)
+
+
+
+def SanitizeName(matchobj):
+ s = matchobj.group(0)
+ if s[0] == '-':
+ s = s[1:]
+ return s.upper()
+
+
+#
+# main program
+#
+
+parser = ArgumentParser(description='Convert MIA style command line tools description into a nipype interface.',
+ formatter_class=RawTextHelpFormatter)
+
+group = parser.add_argument_group('File I/O')
+group.add_argument("-i", "--input", action="store", required=True, help="input XML file containing the description")
+group.add_argument("-o", "--output", action="store", help="output file name, if not given, the name will be deducted from the input file")
+group.add_argument("-p", "--outpath", action="store", help="output path for the nipype interface file")
+
+
+options = parser.parse_args()
+
+if options.output is None:
+ (name , ext) = path.splitext(options.input)
+ options.output = re.sub(r'(^[a-z]|-[a-z]|-[0-9][a-z])', SanitizeName, name) + ".py"
+
+if options.outpath is not None:
+ options.output = path.join(options.outpath, options.output)
+
+
+a = NipypeOutput(options.input, options.output)
+a.write_nipype_file()
+
diff --git a/doc/miaxml2sgml.py b/doc/miaxml2sgml.py
index 96f08d6..7e6ddda 100644
--- a/doc/miaxml2sgml.py
+++ b/doc/miaxml2sgml.py
@@ -1,4 +1,4 @@
-#!/bin/env python
+#!/usr/bin/env python
#
# Copyright (c) Leipzig, Madrid 1999-2012 Gert Wollny
#
diff --git a/mia/2d/creator/circle.cc b/mia/2d/creator/circle.cc
index dbd5d5e..6855e97 100644
--- a/mia/2d/creator/circle.cc
+++ b/mia/2d/creator/circle.cc
@@ -29,7 +29,6 @@
NS_BEGIN(creator_circle_2d);
using namespace mia;
using namespace std;
-using namespace boost;
class C2DCircleCreator : public C2DImageCreator {
public:
diff --git a/mia/2d/filter.cc b/mia/2d/filter.cc
index 1edadab..6ab7bcb 100644
--- a/mia/2d/filter.cc
+++ b/mia/2d/filter.cc
@@ -30,7 +30,6 @@
#include <mia/template/combiner.cxx>
NS_MIA_BEGIN
-using namespace boost;
using std::invalid_argument;
P2DImage EXPORT_2D run_filter_chain(P2DImage image, size_t nfilters, const char *filters[])
diff --git a/mia/2d/filter/CMakeLists.txt b/mia/2d/filter/CMakeLists.txt
index 932d36f..b16c6b4 100644
--- a/mia/2d/filter/CMakeLists.txt
+++ b/mia/2d/filter/CMakeLists.txt
@@ -26,10 +26,8 @@ SET (NOTHING
harmmean
ianiso
kuwahara
- labelmap
lnfft
midpoint
- regiongrow
rgg
variation
wmean
@@ -52,6 +50,7 @@ SET(filters2dNew_base
kmeans
label
labelmap
+ labelscale
load
mask
mean
diff --git a/mia/2d/filter/labelscale.cc b/mia/2d/filter/labelscale.cc
new file mode 100644
index 0000000..e171a95
--- /dev/null
+++ b/mia/2d/filter/labelscale.cc
@@ -0,0 +1,166 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <mia/2d/filter/labelscale.hh>
+
+NS_BEGIN( labelscale_2dimage_filter)
+
+using namespace mia;
+using std::vector;
+using std::pair;
+using std::make_pair;
+using std::invalid_argument;
+
+C2DLabelscale::C2DLabelscale(const C2DBounds& out_size):
+ m_out_size(out_size)
+{
+}
+
+inline pair<unsigned, unsigned> clamp_coord(unsigned i, unsigned di, unsigned ni)
+{
+ unsigned first = i * di;
+ unsigned second = first + di;
+ return make_pair(first, second > ni? ni: second);
+};
+
+
+template <typename T>
+T get_max_represented(const vector<T>& buffer)
+{
+ T max_elm = T();
+ if (buffer.empty())
+ return max_elm;
+ unsigned int max_num = 1;
+ unsigned int cur_num = 1;
+
+ max_elm = buffer[0];
+
+ T cur_elm = max_elm;
+
+ for (auto ib = buffer.begin() + 1; ib != buffer.end() ; ++ib) {
+ if (cur_elm == *ib) {
+ ++cur_num;
+ }else{
+ if (cur_num > max_num) {
+ max_num = cur_num;
+ max_elm = cur_elm;
+ }
+ cur_num = 1;
+ cur_elm = *ib;
+ }
+ }
+ if (cur_num > max_num) {
+ max_elm = cur_elm;
+ }
+ return max_elm;
+};
+
+template <typename T>
+typename C2DLabelscale::result_type C2DLabelscale::operator () (const T2DImage<T>& data) const
+{
+ T2DImage<T> *result = new T2DImage<T>(m_out_size, data);
+
+ C2DBounds block_size = C2DBounds::_1;
+ C2DFVector coordinate_scale = C2DFVector::_1;
+
+ if (m_out_size.x < data.get_size().x ){
+ block_size.x = (data.get_size().x + m_out_size.x - 1) / m_out_size.x;
+ }else{
+ coordinate_scale.x = float(data.get_size().x) / float(m_out_size.x);
+ }
+
+
+ if (m_out_size.y < data.get_size().y ) {
+ block_size.y = (data.get_size().y + m_out_size.y - 1) / m_out_size.y;
+ }else{
+ coordinate_scale.y = float(data.get_size().y) / float(m_out_size.y);
+ }
+
+ vector<T> buffer;
+ buffer.reserve(block_size.product());
+ auto ir = result->begin();
+
+ for (unsigned y = 0; y < m_out_size.y; ++y) {
+ unsigned iy = static_cast<unsigned>(floor(y * coordinate_scale.y));
+ auto rangey = clamp_coord(iy, block_size.y, data.get_size().y);
+ for (unsigned x = 0; x < m_out_size.x; ++x, ++ir) {
+ unsigned ix = static_cast<unsigned>(floor(x * coordinate_scale.x));
+ auto rangex = clamp_coord(ix, block_size.x, data.get_size().x);
+ C2DBounds ibegin(rangex.first, rangey.first);
+ C2DBounds iend(rangex.second, rangey.second);
+
+ buffer.clear();
+ for_each(data.begin_range(ibegin, iend), data.end_range(ibegin, iend),
+ [&buffer](T pixel) {
+ buffer.push_back(pixel);
+ });
+
+ sort(buffer.begin(), buffer.end());
+ *ir = get_max_represented(buffer);
+ }
+ }
+
+ C2DFVector pixel_size = data.get_pixel_size();
+ C2DFVector factor(float(data.get_size().x / float(m_out_size.x) ),
+ float(data.get_size().y / float(m_out_size.y) ));
+
+ result->set_pixel_size(pixel_size * factor);
+
+ return P2DImage(result);
+
+
+}
+
+P2DImage C2DLabelscale::do_filter(const C2DImage& image) const
+{
+ return mia::filter(*this, image);
+}
+
+C2DLabelscaleFilterPluginFactory::C2DLabelscaleFilterPluginFactory():
+C2DFilterPlugin("labelscale")
+{
+ add_parameter("out-size", new C2DBoundsParameter(m_out_size, true, "target size given as two coma separated values"));
+}
+
+C2DFilter *C2DLabelscaleFilterPluginFactory::do_create()const
+{
+ if (m_out_size.x < 1 || m_out_size.y < 1) {
+ throw create_exception<invalid_argument>("labelscale: Output sizes must be positive (got",
+ m_out_size, ")");
+ }
+ return new C2DLabelscale(m_out_size);
+}
+
+const std::string C2DLabelscaleFilterPluginFactory::do_get_descr()const
+{
+ return "A filter that only creates output voxels that are already created in "
+ "the input image. Scaling is done by using a voting algorithms that "
+ "selects the target pixel value based on the highest pixel count of a "
+ "certain label in the corresponding source region. If the region "
+ "comprises two labels with the same count, the one with the lower number "
+ "wins.";
+}
+
+extern "C" EXPORT CPluginBase *get_plugin_interface()
+{
+ return new C2DLabelscaleFilterPluginFactory();
+}
+
+
+NS_END
diff --git a/mia/2d/test_combiner.cc b/mia/2d/filter/labelscale.hh
similarity index 56%
copy from mia/2d/test_combiner.cc
copy to mia/2d/filter/labelscale.hh
index ebf7895..4d9f158 100644
--- a/mia/2d/test_combiner.cc
+++ b/mia/2d/filter/labelscale.hh
@@ -18,26 +18,33 @@
*
*/
-#include <stdexcept>
-#include <climits>
-
-#include <mia/internal/autotest.hh>
-#include <boost/filesystem/path.hpp>
#include <mia/2d/filter.hh>
+NS_BEGIN( labelscale_2dimage_filter)
+
+class C2DLabelscale : public mia::C2DFilter {
+public:
+ C2DLabelscale(const mia::C2DBounds& out_size);
+
+ template <class T>
+ typename C2DLabelscale::result_type operator () (const mia::T2DImage<T>& data) const ;
+private:
+ virtual mia::P2DImage do_filter(const mia::C2DImage& image) const;
+
+ mia::C2DBounds m_out_size;
+
+};
+
+class C2DLabelscaleFilterPluginFactory: public mia::C2DFilterPlugin {
+public:
+ C2DLabelscaleFilterPluginFactory();
+private:
+ virtual mia::C2DFilter *do_create()const;
+ virtual const std::string do_get_descr()const;
+
+ mia::C2DBounds m_out_size;
+};
-NS_MIA_USE
-using namespace boost;
-using namespace std;
-namespace bfs=boost::filesystem;
-BOOST_AUTO_TEST_CASE( test_load_plugins )
-{
- CPathNameArray plugpath;
- plugpath.push_back(bfs::path("combiner"));
- C2DImageCombinerPluginHandler::set_search_path(plugpath);
- const C2DImageCombinerPluginHandler::Instance& handler = C2DImageCombinerPluginHandler::instance();
- BOOST_CHECK_EQUAL(handler.size(), 5u);
- BOOST_CHECK_EQUAL(handler.get_plugin_names(), "absdiff add div mul sub ");
-}
+NS_END
diff --git a/mia/2d/filter/test_labelscale.cc b/mia/2d/filter/test_labelscale.cc
new file mode 100644
index 0000000..3538824
--- /dev/null
+++ b/mia/2d/filter/test_labelscale.cc
@@ -0,0 +1,128 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mia/internal/plugintester.hh>
+#include <mia/2d/filter/labelscale.hh>
+
+using namespace labelscale_2dimage_filter;
+using namespace mia;
+
+BOOST_AUTO_TEST_CASE ( test_labelscale_downscale )
+{
+ const C2DBounds in_size(10, 12);
+
+ const unsigned char in_image[120] = {
+ 1, 1, 1, 2, 2, 2, 2, 3, 3, 3,
+ 1, 1, 1, 2, 2, 2, 2, 3, 3, 3,
+ 1, 1, 1, 2, 2, 3, 3, 3, 3, 4,
+ 5, 5, 5, 2, 2, 2, 3, 3, 4, 4,
+ 5, 5, 2, 2, 2, 3, 3, 3, 4, 4,
+ 5, 5, 5, 2, 7, 2, 3, 3, 3, 3,
+ 5, 6, 5, 7, 7, 7, 7, 3, 3, 3,
+ 6, 6, 6, 7, 7, 7, 7, 3, 3, 3,
+ 6, 6, 8, 7, 7, 7, 7, 3, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ };
+
+ const C2DBounds out_size(5, 3);
+ const unsigned char out_image[15] = {
+ 1, 2, 2, 3, 3,
+ 5, 2, 7, 3, 3,
+ 8, 8, 7, 7, 3
+ };
+
+ auto f = BOOST_TEST_create_from_plugin<C2DLabelscaleFilterPluginFactory>("labelscale:out-size=[5,3]");
+
+
+ C2DUBImage fimage(in_size, in_image );
+ fimage.set_pixel_size(C2DFVector(2.0, 3.0));
+
+ P2DImage scaled = f->filter(fimage);
+
+ BOOST_CHECK_EQUAL(scaled->get_size(),C2DBounds(5,3));
+
+ const C2DUBImage& fscaled = dynamic_cast<const C2DUBImage& >(*scaled);
+ BOOST_REQUIRE(scaled->get_size() == C2DBounds(5,3));
+
+ BOOST_CHECK_EQUAL(fscaled.get_pixel_size(), C2DFVector(4.0f, 12.f));
+
+ for (size_t i = 0; i < 15; ++i) {
+ cvdebug() << i << ":" << fscaled[i] << " - " << out_image[i] << '\n';
+ BOOST_CHECK_EQUAL(fscaled[i], out_image[i]);
+ }
+
+}
+
+
+
+BOOST_AUTO_TEST_CASE ( test_labelscale_upscale )
+{
+ const C2DBounds out_size(10, 12);
+
+ const unsigned char out_image[120] = {
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ };
+
+ const C2DBounds in_size(5, 3);
+ const unsigned char in_image[15] = {
+ 1, 2, 2, 3, 3,
+ 5, 2, 7, 3, 3,
+ 8, 8, 7, 7, 3
+ };
+
+ auto f = BOOST_TEST_create_from_plugin<C2DLabelscaleFilterPluginFactory>("labelscale:out-size=[10,12]");
+
+
+ C2DUBImage fimage(in_size, in_image );
+ fimage.set_pixel_size(C2DFVector(2.0, 3.0));
+
+ P2DImage scaled = f->filter(fimage);
+
+ BOOST_CHECK_EQUAL(scaled->get_size(),C2DBounds(10,12));
+
+ const C2DUBImage& fscaled = dynamic_cast<const C2DUBImage& >(*scaled);
+ BOOST_REQUIRE(scaled->get_size() == C2DBounds(10,12));
+
+ BOOST_CHECK_EQUAL(fscaled.get_pixel_size(), C2DFVector(1.0f, 0.75f));
+
+ for (size_t i = 0; i < 120; ++i) {
+ cvdebug() << i << ":" << int(fscaled[i]) << " - " << int(out_image[i]) << '\n';
+ BOOST_CHECK_EQUAL(fscaled[i], out_image[i]);
+ }
+
+}
+
diff --git a/mia/2d/filtertest.cc b/mia/2d/filtertest.cc
index 1a03c80..ec7a503 100644
--- a/mia/2d/filtertest.cc
+++ b/mia/2d/filtertest.cc
@@ -32,7 +32,6 @@
NS_MIA_BEGIN
using namespace std;
-using namespace boost;
namespace bfs=::boost::filesystem;
using namespace boost::unit_test;
diff --git a/mia/2d/fullcost/CMakeLists.txt b/mia/2d/fullcost/CMakeLists.txt
index bd832f5..5545095 100644
--- a/mia/2d/fullcost/CMakeLists.txt
+++ b/mia/2d/fullcost/CMakeLists.txt
@@ -16,5 +16,5 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
-SET(fullcost image maskedimage)
+SET(fullcost image maskedimage label)
PLUGINGROUP_WITH_TEST_AND_PREFIX2("2dimage" "fullcost" "${fullcost}" mia2dtest )
diff --git a/mia/2d/fullcost/label.cc b/mia/2d/fullcost/label.cc
new file mode 100644
index 0000000..c448b14
--- /dev/null
+++ b/mia/2d/fullcost/label.cc
@@ -0,0 +1,340 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <cmath>
+
+#include <mia/2d/fullcost/label.hh>
+#include <mia/2d/filter.hh>
+#include <mia/core/distance.hh>
+#include <mia/2d/distance.hh>
+
+NS_MIA_BEGIN
+using namespace std;
+
+C2DLabelFullCost::C2DLabelFullCost(const std::string& src,
+ const std::string& ref,
+ double weight,
+ int maxlabels, int debug):
+ C2DFullCost(weight),
+ m_src_key(C2DImageIOPluginHandler::instance().load_to_pool(src)),
+ m_ref_key(C2DImageIOPluginHandler::instance().load_to_pool(ref)),
+ m_ref_label_exists(maxlabels),
+ m_ref_distances(maxlabels),
+ m_debug(debug)
+{
+ add(::mia::property_gradient);
+}
+
+bool C2DLabelFullCost::do_get_full_size(C2DBounds& size) const
+{
+ TRACE_FUNCTION;
+ assert(m_src);
+ if (size == C2DBounds::_0) {
+ size = m_src->get_size();
+ return true;
+ }else
+ return size == m_src->get_size();
+}
+
+
+double C2DLabelFullCost::do_value(const C2DTransformation& t) const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+ P2DImage temp = t(m_src_scaled);
+ const C2DUBImage& temp_ubyte = static_cast<const C2DUBImage&>(*temp);
+
+ double result = 0.0;
+ for (size_t i = 0; i < temp_ubyte.size(); ++i) {
+ double v = value(i, temp_ubyte[i]);
+ result += v;
+ }
+ return result;
+}
+
+double C2DLabelFullCost::do_value() const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+ // one should apply an identity transform here, to ensure that the test image is
+ // of the same size like the reference image
+
+ double result = 0.0;
+ for (size_t i = 0; i < m_src_scaled.size(); ++i) {
+ result += value(i, m_src_scaled[i]);
+ }
+ return result;
+}
+
+
+double C2DLabelFullCost::do_evaluate(const C2DTransformation& t, CDoubleVector& gradient) const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+
+ P2DImage temp = t(m_src_scaled);
+ const C2DUBImage& temp_ubyte = static_cast<const C2DUBImage&>(*temp);
+
+ C2DFVectorfield force(get_current_size());
+
+ C2DBounds pos(0,0);
+
+ double result = value_and_gradient(0, temp_ubyte[0], force[0], pos, eb_xlow | eb_ylow);
+ int idx = 1;
+
+ for (pos.x = 1; pos.x < temp_ubyte.get_size().x - 1; ++pos.x, ++idx) {
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_ylow);
+ }
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_xhigh | eb_ylow);
+ ++idx;
+
+ for (pos.y = 1; pos.y < temp_ubyte.get_size().y-1; ++pos.y) {
+ pos.x = 0;
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_xlow);
+ ++idx;
+
+ for (pos.x = 1; pos.x < temp_ubyte.get_size().x - 1; ++pos.x, ++idx) {
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_none);
+ }
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_xhigh);
+ ++idx;
+ }
+
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_xlow | eb_yhigh);
+ ++idx;
+
+ for (pos.x = 1; pos.x < temp_ubyte.get_size().x-1; ++pos.x, ++idx) {
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_yhigh);
+ }
+ result += value_and_gradient(idx, temp_ubyte[idx], force[idx], pos, eb_xhigh | eb_yhigh);
+
+
+ // at this point one could inject a hole-filling algorithm to
+ // add forces inside of the homogen overlapping label regions
+
+ t.translate(force, gradient);
+
+ cvdebug() << "Image cost =" << result << "\n";
+ return result;
+
+}
+
+void C2DLabelFullCost::do_set_size()
+{
+ TRACE_FUNCTION;
+ assert(m_src);
+ assert(m_ref);
+
+ if (m_src_scaled.size() || m_src_scaled.get_size() != get_current_size() ||
+ m_ref_scaled.size() || m_ref_scaled.get_size() != get_current_size() ) {
+ if (get_current_size() == m_src->get_size()) {
+ m_src_scaled = static_cast<const C2DUBImage&>(*m_src);
+ m_ref_scaled = static_cast<const C2DUBImage&>(*m_ref);
+ }else{
+ stringstream filter_descr;
+ filter_descr << "labelscale:out-size=[" << get_current_size()<<"]";
+ auto scaler = C2DFilterPluginHandler::instance().produce(filter_descr.str());
+ assert(scaler);
+ cvdebug() << "C2DLabelFullCost:scale images to " << get_current_size() <<
+ " using '" << filter_descr.str() << "'\n";
+ m_src_scaled = static_cast<const C2DUBImage&>(*scaler->filter(*m_src));
+ m_ref_scaled = static_cast<const C2DUBImage&>(*scaler->filter(*m_ref));
+ }
+ prepare_distance_fields(m_ref_scaled);
+ }
+
+}
+
+void C2DLabelFullCost::prepare_distance_fields( const C2DUBImage &image )
+{
+ assert(image.get_pixel_type() == it_ubyte);
+
+ static int step = 0;
+
+ for (size_t i = 0; i < m_ref_label_exists.size(); ++i) {
+ bool exist = false;
+
+ stringstream filter_descr;
+ filter_descr << "binarize:min=" << i << ",max=" << i;
+ auto bin = run_filter(image, filter_descr.str().c_str());
+
+ const C2DBitImage& bool_bin = static_cast<const C2DBitImage&>(*bin);
+ for (auto i = bool_bin.begin(); i != bool_bin.end() && !exist; ++i)
+ exist = *i;
+
+ m_ref_label_exists[i] = exist;
+ if (exist) {
+ C2DFImage prep(bool_bin.get_size());
+ distance_transform_prepare(bool_bin.begin(), bool_bin.end(),
+ prep.begin());
+
+ m_ref_distances[i] = distance_transform(prep);
+ transform(m_ref_distances[i].begin(), m_ref_distances[i].end(),
+ m_ref_distances[i].begin(), [](float& x){ return sqrt(x);});
+
+ }
+ }
+ if (m_debug) {
+ for (size_t i = 0; i < m_ref_label_exists.size(); ++i) {
+ if (m_ref_label_exists[i]) {
+ stringstream ofname;
+ ofname << "dt" << setw(3) << setfill('0') << step
+ << "_" << setw(3) << setfill('0') << i << ".v";
+ save_image(ofname.str(), m_ref_distances[i]);
+ }
+ }
+ }
+}
+
+double C2DLabelFullCost::value(int idx, int label) const
+{
+ // non existent labels will be ignored, since they never can be
+ // aligned
+ return m_ref_label_exists[label] ? m_ref_distances[label][idx] : 0.0;
+}
+
+double C2DLabelFullCost::value_and_gradient(int idx, int label, C2DFVector& gradient,
+ const C2DBounds& pos, int boundaries) const
+{
+ double result;
+
+ if (m_ref_label_exists[label]) {
+ const auto & dref = m_ref_distances[label];
+ result = dref[idx];
+ if (result > 0.0) {
+ if (boundaries == eb_none)
+ gradient = dref.get_gradient(idx);
+ else { // emulate repeat boundary conditions
+ switch (boundaries & eb_x) {
+ case eb_xlow:
+ gradient.x = 0.5 * (dref(pos.x + 1, pos.y) - dref(pos.x, pos.y));
+ break;
+ case eb_xhigh:
+ gradient.x = 0.5 * (dref(pos.x, pos.y) - dref(pos.x - 1, pos.y));
+ break;
+ default:
+ gradient.x = 0.5 * (dref(pos.x + 1, pos.y) - dref(pos.x - 1, pos.y));
+ }
+
+ switch (boundaries & eb_y) {
+ case eb_ylow:
+ gradient.y = 0.5 * (dref(pos.x, pos.y + 1) - dref(pos.x, pos.y));
+ break;
+ case eb_yhigh:
+ gradient.y = 0.5 * (dref(pos.x, pos.y) - dref(pos.x, pos.y - 1));
+ break;
+ default:
+ gradient.y = 0.5 * (dref(pos.x, pos.y + 1) - dref(pos.x, pos.y - 1));
+ }
+ }
+ }else{
+ gradient = C2DFVector::_0;
+ }
+ }else {
+ result = 0.0;
+ gradient = C2DFVector::_0;
+ }
+ return result;
+}
+
+
+void C2DLabelFullCost::do_reinit()
+{
+ TRACE_FUNCTION;
+ m_src = get_from_pool(m_src_key);
+ m_ref = get_from_pool(m_ref_key);
+ m_src_scaled = C2DUBImage();
+ m_ref_scaled = C2DUBImage();
+
+ // is this true? Actually the deformed image is used and it is always interpolated on the full
+ // space of the reference image
+ if (m_src->get_size() != m_ref->get_size())
+ throw runtime_error("C2DLabelFullCost only works with images of equal size");
+
+ if (m_src->get_pixel_size() != m_ref->get_pixel_size()) {
+ cvwarn() << "C2DLabelFullCost: src and reference image are of differnet pixel dimensions:"
+ << m_src->get_pixel_size() << " vs " << m_ref->get_pixel_size()
+ << " This code doesn't honour this.\n";
+ }
+ if (m_src->get_pixel_type() != it_ubyte)
+ throw create_exception<runtime_error>("C2DLabelFullCost only works with (label) "
+ "images of pixel type ubyte, but src has type ",
+ CPixelTypeDict.get_name(m_src->get_pixel_type()));
+
+ if (m_ref->get_pixel_type() != it_ubyte)
+ throw create_exception<runtime_error>("C2DLabelFullCost only works with (label) "
+ "images of pixel type ubyte, but ref has type ",
+ CPixelTypeDict.get_name(m_src->get_pixel_type()));
+}
+
+P2DImage C2DLabelFullCost::get_from_pool(const C2DImageDataKey& key)
+{
+ C2DImageIOPlugin::PData in_image_list = key.get();
+
+ if (!in_image_list || in_image_list->empty())
+ throw invalid_argument("C2DLabelFullCost: no image available in data pool");
+
+ return (*in_image_list)[0];
+}
+
+
+C2DLabelFullCostPlugin::C2DLabelFullCostPlugin():
+ C2DFullCostPlugin("labelimage"),
+ m_src_name("src.@"),
+ m_ref_name("ref.@"),
+ m_maxlabel(256),
+ m_debug(0)
+{
+ add_parameter("src", new CStringParameter(m_src_name, CCmdOptionFlags::input, "Study image",
+ &C2DImageIOPluginHandler::instance()));
+ add_parameter("ref", new CStringParameter(m_ref_name, CCmdOptionFlags::input, "Reference image",
+ &C2DImageIOPluginHandler::instance()));
+ add_parameter("maxlabel", new CIntParameter(m_maxlabel, 2, 32000, false,
+ "maximum number of labels to consider"));
+ add_parameter("debug", new CIntParameter(m_debug, 0, 1, false,
+ "write the distance transforms to a 3D image"));
+
+}
+
+C2DFullCost *C2DLabelFullCostPlugin::do_create(float weight) const
+{
+ cvdebug() << "create C2DLabelFullCostPlugin with weight= " << weight
+ << " src=" << m_src_name << " ref=" << m_ref_name
+ << " naxlabels=" << m_maxlabel << "\n";
+ return new C2DLabelFullCost(m_src_name, m_ref_name,
+ weight, m_maxlabel, m_debug);
+}
+
+const std::string C2DLabelFullCostPlugin::do_get_descr() const
+{
+ return "Similarity cost function that maps labels of two images and handles "
+ "label-preserving multi-resolution processing.";
+
+}
+
+extern "C" EXPORT CPluginBase *get_plugin_interface()
+{
+ return new C2DLabelFullCostPlugin();
+}
+
+NS_MIA_END
diff --git a/mia/2d/fullcost/label.hh b/mia/2d/fullcost/label.hh
new file mode 100644
index 0000000..dab3ca9
--- /dev/null
+++ b/mia/2d/fullcost/label.hh
@@ -0,0 +1,97 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef mia_2d_imagefullcost_hh
+#define mia_2d_imagefullcost_hh
+
+
+#include <mia/2d/fullcost.hh>
+#include <mia/2d/imageio.hh>
+#include <mia/2d/cost.hh>
+
+NS_MIA_BEGIN
+
+class EXPORT C2DLabelFullCost : public C2DFullCost {
+public:
+ C2DLabelFullCost(const std::string& src,
+ const std::string& ref,
+ double weight,
+ int maxlabels,
+ int debug);
+private:
+ double do_evaluate(const C2DTransformation& t, CDoubleVector& gradient) const;
+ void do_set_size();
+
+ static P2DImage get_from_pool(const C2DImageDataKey& key);
+
+ double do_value(const C2DTransformation& t) const;
+ bool do_get_full_size(C2DBounds& size) const;
+
+ double value(int idx, int label) const;
+ double value_and_gradient(int idx, int label, C2DFVector& gradient, const C2DBounds& pos, int boundaries) const;
+ void prepare_distance_fields(const C2DUBImage& image);
+
+ double do_value() const;
+ void do_reinit();
+
+ C2DImageDataKey m_src_key;
+ C2DImageDataKey m_ref_key;
+
+ P2DImage m_src;
+ P2DImage m_ref;
+
+ C2DUBImage m_src_scaled;
+ C2DUBImage m_ref_scaled;
+
+ std::vector<bool> m_ref_label_exists;
+ std::vector<C2DFImage> m_ref_distances;
+
+ enum EBoundaries {
+ eb_none = 0,
+ eb_xlow = 1, /**< at low x-boundary */
+ eb_xhigh = 2, /**< at high x-boundary */
+ eb_x = 3, /**< at high x-boundary */
+ eb_ylow = 4, /**< at low y-boundary */
+ eb_yhigh = 8, /**< at high y-boundary */
+ eb_y = 12, /**< any y-boundary */
+ };
+
+ int m_debug;
+};
+
+// plugin implementation
+class C2DLabelFullCostPlugin: public C2DFullCostPlugin {
+public:
+ C2DLabelFullCostPlugin();
+private:
+ C2DFullCost *do_create(float weight) const;
+ const std::string do_get_descr() const;
+
+
+ std::string m_src_name;
+ std::string m_ref_name;
+ int m_maxlabel;
+ int m_debug;
+};
+
+
+NS_MIA_END
+
+#endif
diff --git a/mia/2d/fullcost/test_label.cc b/mia/2d/fullcost/test_label.cc
new file mode 100644
index 0000000..1cc6738
--- /dev/null
+++ b/mia/2d/fullcost/test_label.cc
@@ -0,0 +1,127 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mia/internal/plugintester.hh>
+#include <mia/2d/fullcost/label.hh>
+#include <mia/2d/transformfactory.hh>
+
+NS_MIA_USE
+
+
+struct TransformInitFixture {
+ TransformInitFixture();
+
+ P2DTransformationFactory tff;
+};
+
+
+BOOST_FIXTURE_TEST_CASE ( test_labeldistance, TransformInitFixture )
+{
+ // create two images and do the thing
+
+ const unsigned char ref_data[25] = {
+ 1, 1, 1, 2, 2,
+ 1, 1, 1, 2, 2,
+ 1, 1, 1, 2, 2,
+ 5, 5, 5, 2, 2,
+ 5, 5, 2, 2, 2,
+ };
+
+ const unsigned char mov_data[25] = {
+ 1, 1, 2, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 5, 2, 2,
+ 5, 5, 5, 5, 2,
+ };
+
+ const float distances [25] = {
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, sqrtf(2.0f), 0,
+ };
+
+ const float gradx [25] = {
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, -0.5f * sqrtf(2.0f), -0.5f * (sqrtf(5.0f) - 1.0f), 0
+ };
+
+ const float grady [25] = {
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ -1, -1, 0, 0, 0,
+ 0, 0,-.5f, -.5f * (sqrtf(2.0f) - 1.0f), 0
+ };
+
+ const C2DBounds size(5,5);
+
+ C2DUBImage *mov_image = new C2DUBImage(size, mov_data );
+ C2DUBImage *ref_image = new C2DUBImage(size, ref_data );
+
+ P2DImage mov(mov_image);
+ P2DImage ref(ref_image);
+
+ auto cost = BOOST_TEST_create_from_plugin<C2DLabelFullCostPlugin>("labelimage:maxlabel=7");
+
+ auto t = tff->create(size);
+ auto params = t->get_parameters();
+ std::fill(params.begin(), params.end(), 0.0);
+ t->set_parameters(params);
+
+ save_image("src.@", mov);
+ save_image("ref.@", ref);
+
+ cost->reinit();
+ cost->set_size(size);
+
+ BOOST_CHECK_CLOSE(cost->cost_value(*t), 6 + sqrt(2.0), 0.01);
+ BOOST_CHECK_CLOSE(cost->cost_value(), 6 + sqrt(2.0), 0.01);
+
+ CDoubleVector gradient(t->degrees_of_freedom());
+ double cost_value = cost->evaluate(*t, gradient);
+
+ for(int i = 0; i < 25; ++i) {
+ cvdebug() << "[" << i << "]: (" << gradient[2*i] << ", " << gradient[2*i+1]
+ << ") expect ("<< gradx[i] << ", " << grady[i] << ")\n";
+
+ if (gradx[i] != 0.0)
+ BOOST_CHECK_CLOSE(gradient[2*i], gradx[i], 0.1);
+ else
+ BOOST_CHECK_SMALL(gradient[2*i], 1e-10);
+ if (grady[i] != 0.0)
+ BOOST_CHECK_CLOSE(gradient[2*i+1], grady[i], 0.1);
+ else
+ BOOST_CHECK_SMALL(gradient[2*i+1], 1e-10);
+ }
+}
+
+
+
+TransformInitFixture::TransformInitFixture():
+ tff(C2DTransformCreatorHandler::instance().produce("vf:imgkernel=[bspline:d=0],imgboundary=zero"))
+{
+
+}
diff --git a/mia/2d/imageiotest.cc b/mia/2d/imageiotest.cc
index ffb1f4e..9175694 100644
--- a/mia/2d/imageiotest.cc
+++ b/mia/2d/imageiotest.cc
@@ -30,7 +30,6 @@
using namespace std;
-using namespace boost;
using namespace boost::unit_test;
NS_MIA_BEGIN
diff --git a/mia/2d/imagetest.cc b/mia/2d/imagetest.cc
index 884291f..2e33cf1 100644
--- a/mia/2d/imagetest.cc
+++ b/mia/2d/imagetest.cc
@@ -23,7 +23,6 @@
#include <mia/2d/imagetest.hh>
NS_MIA_BEGIN
-using namespace boost;
template <typename T, typename R>
struct __compare {
diff --git a/mia/2d/interpolator.cc b/mia/2d/interpolator.cc
index 2a4f681..93387dc 100644
--- a/mia/2d/interpolator.cc
+++ b/mia/2d/interpolator.cc
@@ -34,10 +34,8 @@
NS_MIA_BEGIN
-using namespace boost;
using namespace std;
-
C2DInterpolatorFactory::C2DInterpolatorFactory(const std::string& kernel, const std::string& bc):
m_kernel(produce_spline_kernel(kernel)),
m_xbc(produce_spline_boundary_condition(bc)),
diff --git a/mia/2d/register.cc b/mia/2d/register.cc
index 8b2bf2d..cf4d28b 100644
--- a/mia/2d/register.cc
+++ b/mia/2d/register.cc
@@ -36,7 +36,6 @@
#include <boost/algorithm/minmax_element.hpp>
NS_MIA_USE
-using namespace boost;
using namespace std;
@@ -349,7 +348,7 @@ struct FMinMax: public TFilter <pair<float, float> > {
template <typename T>
pair<float, float> operator ()(const T2DImage<T>& image) const {
pair<typename T2DImage<T>::const_iterator, typename T2DImage<T>::const_iterator>
- minmax = ::boost::minmax_element(image.begin(), image.end());
+ minmax = minmax_element(image.begin(), image.end());
return pair<float, float>(*minmax.first, *minmax.second);
}
};
diff --git a/mia/2d/test_combiner.cc b/mia/2d/test_combiner.cc
index ebf7895..ee76058 100644
--- a/mia/2d/test_combiner.cc
+++ b/mia/2d/test_combiner.cc
@@ -27,7 +27,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
namespace bfs=boost::filesystem;
diff --git a/mia/2d/test_distance.cc b/mia/2d/test_distance.cc
index 875ece4..0756042 100644
--- a/mia/2d/test_distance.cc
+++ b/mia/2d/test_distance.cc
@@ -26,7 +26,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
struct PointLineDistanceFixture {
diff --git a/mia/2d/test_filter.cc b/mia/2d/test_filter.cc
index 2c769aa..acae766 100644
--- a/mia/2d/test_filter.cc
+++ b/mia/2d/test_filter.cc
@@ -39,7 +39,7 @@ BOOST_AUTO_TEST_CASE(test_available_filters)
set<string> test_data = {
"adaptmed", "admean", "aniso", "bandpass", "binarize", "close", "combiner", "convert", "crop",
"dilate", "distance", "downscale", "erode", "gauss", "gradnorm", "invert", "kmeans",
- "label", "labelmap", "load", "mask", "mean", "median", "mlv", "ngfnorm", "noise", "open",
+ "label", "labelmap", "labelscale", "load", "mask", "mean", "median", "mlv", "ngfnorm", "noise", "open",
"pruning", "regiongrow", "sandp", "scale", "selectbig", "sepconv", "shmean", "sort-label",
"sws", "tee", "thinning", "thresh", "transform", "ws"};
diff --git a/mia/2d/test_filter_cast.cc b/mia/2d/test_filter_cast.cc
index 6729522..a54e743 100644
--- a/mia/2d/test_filter_cast.cc
+++ b/mia/2d/test_filter_cast.cc
@@ -30,7 +30,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
namespace bmpl=boost::mpl;
diff --git a/mia/2d/test_fullcost.cc b/mia/2d/test_fullcost.cc
index a3e0846..b4f77bd 100644
--- a/mia/2d/test_fullcost.cc
+++ b/mia/2d/test_fullcost.cc
@@ -194,8 +194,8 @@ private:
BOOST_AUTO_TEST_CASE( test_load_plugins )
{
const C2DFullCostPluginHandler::Instance& handler = PrepareFullcostTests::instance().fullcost_handler();
- BOOST_CHECK_EQUAL(handler.size(), 2u);
- BOOST_CHECK_EQUAL(handler.get_plugin_names(), "image maskedimage ");
+ BOOST_CHECK_EQUAL(handler.size(), 3u);
+ BOOST_CHECK_EQUAL(handler.get_plugin_names(), "image labelimage maskedimage ");
}
#if 0
diff --git a/mia/2d/test_ica.cc b/mia/2d/test_ica.cc
index a648576..d03dcf8 100644
--- a/mia/2d/test_ica.cc
+++ b/mia/2d/test_ica.cc
@@ -25,7 +25,6 @@
using namespace mia;
using namespace std;
-using namespace ::boost;
using namespace boost::unit_test;
const size_t slices = 5;
diff --git a/mia/2d/test_image.cc b/mia/2d/test_image.cc
index 38be58e..13efa1b 100644
--- a/mia/2d/test_image.cc
+++ b/mia/2d/test_image.cc
@@ -32,8 +32,6 @@
NS_MIA_USE
-using namespace boost;
-
class CCopyFilter: public TFilter<P2DImage > {
public:
diff --git a/mia/2d/test_imageio.cc b/mia/2d/test_imageio.cc
index 44975c5..540daa9 100644
--- a/mia/2d/test_imageio.cc
+++ b/mia/2d/test_imageio.cc
@@ -27,7 +27,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
using namespace boost::unit_test;
namespace bfs = ::boost::filesystem;
diff --git a/mia/2d/test_interpol.cc b/mia/2d/test_interpol.cc
index 8f6e5d5..8314d30 100644
--- a/mia/2d/test_interpol.cc
+++ b/mia/2d/test_interpol.cc
@@ -36,7 +36,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bmpl=boost::mpl;
diff --git a/mia/2d/test_modelsolverreg.cc b/mia/2d/test_modelsolverreg.cc
index 0c6f76b..7cf402a 100644
--- a/mia/2d/test_modelsolverreg.cc
+++ b/mia/2d/test_modelsolverreg.cc
@@ -26,7 +26,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
diff --git a/mia/2d/test_nfg.cc b/mia/2d/test_nfg.cc
index 6cd2c5d..c49f139 100644
--- a/mia/2d/test_nfg.cc
+++ b/mia/2d/test_nfg.cc
@@ -27,7 +27,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
P2DImage create_test_image()
diff --git a/mia/2d/test_oldnewintegrate.cc b/mia/2d/test_oldnewintegrate.cc
index 6a4d366..1cfe490 100644
--- a/mia/2d/test_oldnewintegrate.cc
+++ b/mia/2d/test_oldnewintegrate.cc
@@ -29,7 +29,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bmpl=boost::mpl;
diff --git a/mia/2d/test_ppmatrix.cc b/mia/2d/test_ppmatrix.cc
index c7be3d6..8689acf 100644
--- a/mia/2d/test_ppmatrix.cc
+++ b/mia/2d/test_ppmatrix.cc
@@ -18,6 +18,7 @@
*
*/
+#include <cmath>
#include <mia/internal/autotest.hh>
#include <mia/2d/ppmatrix.hh>
@@ -272,7 +273,7 @@ BOOST_FIXTURE_TEST_CASE( test_divergence_expm2_bspline3_grad, TransformSplineFix
ic->x += 0.001;
double test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (x)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[0], test_grad, 2);
ic->y += 0.001;
@@ -283,7 +284,7 @@ BOOST_FIXTURE_TEST_CASE( test_divergence_expm2_bspline3_grad, TransformSplineFix
test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (y)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[1], test_grad, 2);
}
}
@@ -314,7 +315,7 @@ BOOST_FIXTURE_TEST_CASE( test_rotation_expm2_bspline3_grad, TransformSplineFixtu
ic->x += 0.001;
double test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (x)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[0], test_grad, 2);
ic->y += 0.001;
@@ -325,7 +326,7 @@ BOOST_FIXTURE_TEST_CASE( test_rotation_expm2_bspline3_grad, TransformSplineFixtu
test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (y)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[1], test_grad, 2);
}
}
@@ -356,7 +357,7 @@ BOOST_FIXTURE_TEST_CASE( test_divergence_expm2_bspline3_grad_noiso, TransformSpl
ic->x += 0.001;
double test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (x)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[0], test_grad, 1);
ic->y += 0.001;
@@ -367,7 +368,7 @@ BOOST_FIXTURE_TEST_CASE( test_divergence_expm2_bspline3_grad_noiso, TransformSpl
test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (y)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[1], test_grad, 1);
}
}
@@ -398,7 +399,7 @@ BOOST_FIXTURE_TEST_CASE( test_rotation_expm2_bspline3_grad_noiso, TransformSplin
ic->x += 0.001;
double test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (x)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[0], test_grad, 1);
ic->y += 0.001;
@@ -409,7 +410,7 @@ BOOST_FIXTURE_TEST_CASE( test_rotation_expm2_bspline3_grad_noiso, TransformSplin
test_grad = (graddivp - graddivm)/ 0.002;
cvdebug() << x << " " << y << " (y)\n";
- if (abs(test_grad) > 0.0001)
+ if (fabs(test_grad) > 0.0001)
BOOST_CHECK_CLOSE(ig[1], test_grad, 1);
}
}
diff --git a/mia/2d/test_regplugins.cc b/mia/2d/test_regplugins.cc
index e73d290..23604aa 100644
--- a/mia/2d/test_regplugins.cc
+++ b/mia/2d/test_regplugins.cc
@@ -30,7 +30,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
using namespace boost::unit_test;
namespace bfs=::boost::filesystem;
diff --git a/mia/2d/test_segframe.cc b/mia/2d/test_segframe.cc
index cf449ce..d8ee634 100644
--- a/mia/2d/test_segframe.cc
+++ b/mia/2d/test_segframe.cc
@@ -29,7 +29,6 @@
using namespace mia;
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace xmlpp;
namespace bfs=boost::filesystem;
diff --git a/mia/2d/test_segmentation.cc b/mia/2d/test_segmentation.cc
index d8a6e46..429712b 100644
--- a/mia/2d/test_segmentation.cc
+++ b/mia/2d/test_segmentation.cc
@@ -33,7 +33,6 @@ namespace bfs=boost::filesystem;
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace xmlpp;
diff --git a/mia/2d/test_shape.cc b/mia/2d/test_shape.cc
index 33cb374..08d2867 100644
--- a/mia/2d/test_shape.cc
+++ b/mia/2d/test_shape.cc
@@ -26,7 +26,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
BOOST_AUTO_TEST_CASE( test_2dshape_handler )
diff --git a/mia/2d/test_transformfactory.cc b/mia/2d/test_transformfactory.cc
index 63db398..7c3497e 100644
--- a/mia/2d/test_transformfactory.cc
+++ b/mia/2d/test_transformfactory.cc
@@ -26,7 +26,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace boost::unit_test;
namespace bfs=boost::filesystem;
diff --git a/mia/2d/test_vectorfield_interpolator.cc b/mia/2d/test_vectorfield_interpolator.cc
index ec92320..570be1f 100644
--- a/mia/2d/test_vectorfield_interpolator.cc
+++ b/mia/2d/test_vectorfield_interpolator.cc
@@ -28,7 +28,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace boost::unit_test;
namespace bfs=boost::filesystem;
diff --git a/mia/2d/test_vfio.cc b/mia/2d/test_vfio.cc
index 5b72380..a94c2bc 100644
--- a/mia/2d/test_vfio.cc
+++ b/mia/2d/test_vfio.cc
@@ -32,7 +32,6 @@
#include <mia/core/filter.hh>
NS_MIA_USE
-using namespace boost;
using namespace std;
using namespace boost::unit_test;
namespace bfs=::boost::filesystem;
diff --git a/mia/2d/vfiotest.cc b/mia/2d/vfiotest.cc
index 9e25437..77ea934 100644
--- a/mia/2d/vfiotest.cc
+++ b/mia/2d/vfiotest.cc
@@ -33,7 +33,6 @@
#include <mia/core/filter.hh>
NS_MIA_BEGIN
-using namespace boost;
using namespace std;
using namespace boost::unit_test;
namespace bfs=::boost::filesystem;
diff --git a/mia/3d/datafield.cxx b/mia/3d/datafield.cxx
index 7b6469d..b08714b 100644
--- a/mia/3d/datafield.cxx
+++ b/mia/3d/datafield.cxx
@@ -600,6 +600,42 @@ T3DDatafield<T>::end_range(const C3DBounds& begin, const C3DBounds& end)const
begin_at(end.x, end.y, end.z));
}
+template <typename T>
+typename T3DDatafield<T>::range_iterator_with_boundary_flag
+T3DDatafield<T>::begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)
+{
+ return range_iterator_with_boundary_flag(begin, get_size(), begin, end,
+ begin_at(begin.x, begin.y, begin.z));
+}
+
+
+
+template <typename T>
+typename T3DDatafield<T>::range_iterator_with_boundary_flag
+T3DDatafield<T>::end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)
+{
+ return range_iterator_with_boundary_flag(end, get_size(), begin, end,
+ begin_at(end.x, end.y, end.z));
+}
+
+
+
+template <typename T>
+typename T3DDatafield<T>::const_range_iterator_with_boundary_flag
+T3DDatafield<T>::begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const
+{
+ return const_range_iterator_with_boundary_flag(begin, get_size(), begin, end,
+ begin_at(begin.x, begin.y, begin.z));
+}
+
+template <typename T>
+typename T3DDatafield<T>::const_range_iterator_with_boundary_flag
+T3DDatafield<T>::end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const
+{
+ return const_range_iterator_with_boundary_flag(end, get_size(), begin, end,
+ begin_at(end.x, end.y, end.z));
+}
+
NS_MIA_END
diff --git a/mia/3d/datafield.hh b/mia/3d/datafield.hh
index d8aff60..1f36786 100644
--- a/mia/3d/datafield.hh
+++ b/mia/3d/datafield.hh
@@ -399,6 +399,20 @@ public:
const_range_iterator end_range(const C3DBounds& begin, const C3DBounds& end)const;
+ /** \returns an read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ range_iterator_with_boundary_flag begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end);
+
+ /** \returns the end of a read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ range_iterator_with_boundary_flag end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end);
+
+
+ /** \returns an read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ const_range_iterator_with_boundary_flag begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const;
+
+ /** \returns the end of a read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ const_range_iterator_with_boundary_flag end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const;
+
+
/**
Obtain an iterator at position (x,y,z)
The functions ensures, that the field uses a single referenced datafield
diff --git a/mia/3d/fifof/morphological.cc b/mia/3d/fifof/morphological.cc
index beb129c..f5441d6 100644
--- a/mia/3d/fifof/morphological.cc
+++ b/mia/3d/fifof/morphological.cc
@@ -33,7 +33,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace morphological_fifof {
diff --git a/mia/3d/fifof/regiongrow.cc b/mia/3d/fifof/regiongrow.cc
index 6eaef61..6288051 100644
--- a/mia/3d/fifof/regiongrow.cc
+++ b/mia/3d/fifof/regiongrow.cc
@@ -83,7 +83,7 @@ struct FTransform<T, true> {
template <typename T>
int C2DRegiongrowFifoFilter::operator ()( const T2DImage<T>& image)
{
- const bool is_float = is_floating_point<T>::value;
+ const bool is_float = std::is_floating_point<T>::value;
transform(image.begin(), image.end(), m_in_buffer.begin(),
FTransform<T, is_float>(m_probmap[m_class]));
diff --git a/mia/3d/filter.cc b/mia/3d/filter.cc
index 1d34f0e..61c9fe2 100644
--- a/mia/3d/filter.cc
+++ b/mia/3d/filter.cc
@@ -28,8 +28,6 @@
NS_MIA_BEGIN
-using namespace boost;
-
template<> const char * const
TPluginHandler<C3DFilterPlugin>::m_help =
"These plug-ins provide 3D image filters. Unless otherwise noted, "
diff --git a/mia/3d/filter/CMakeLists.txt b/mia/3d/filter/CMakeLists.txt
index 277da32..3bbada1 100644
--- a/mia/3d/filter/CMakeLists.txt
+++ b/mia/3d/filter/CMakeLists.txt
@@ -29,6 +29,7 @@ SET(filters3dNew
invert
kmeans
label
+ labelscale
load
lvdownscale
mask
diff --git a/mia/3d/filter/labelscale.cc b/mia/3d/filter/labelscale.cc
new file mode 100644
index 0000000..60a90b0
--- /dev/null
+++ b/mia/3d/filter/labelscale.cc
@@ -0,0 +1,177 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <mia/3d/filter/labelscale.hh>
+
+NS_BEGIN( labelscale_3dimage_filter)
+
+using namespace mia;
+using std::vector;
+using std::pair;
+using std::make_pair;
+using std::invalid_argument;
+
+C3DLabelscale::C3DLabelscale(const C3DBounds& out_size):
+ m_out_size(out_size)
+{
+}
+
+inline pair<unsigned, unsigned> clamp_coord(unsigned i, unsigned di, unsigned ni)
+{
+ unsigned first = i * di;
+ unsigned second = first + di;
+ return make_pair(first, second > ni? ni: second);
+};
+
+
+template <typename T>
+T get_max_represented(const vector<T>& buffer)
+{
+ T max_elm = T();
+ if (buffer.empty())
+ return max_elm;
+ unsigned int max_num = 1;
+ unsigned int cur_num = 1;
+
+ max_elm = buffer[0];
+
+ T cur_elm = max_elm;
+
+ for (auto ib = buffer.begin() + 1; ib != buffer.end() ; ++ib) {
+ if (cur_elm == *ib) {
+ ++cur_num;
+ }else{
+ if (cur_num > max_num) {
+ max_num = cur_num;
+ max_elm = cur_elm;
+ }
+ cur_num = 1;
+ cur_elm = *ib;
+ }
+ }
+ if (cur_num > max_num) {
+ max_elm = cur_elm;
+ }
+ return max_elm;
+};
+
+template <typename T>
+typename C3DLabelscale::result_type C3DLabelscale::operator () (const T3DImage<T>& data) const
+{
+ T3DImage<T> *result = new T3DImage<T>(m_out_size, data);
+
+ C3DBounds block_size = C3DBounds::_1;
+ C3DFVector coordinate_scale = C3DFVector::_1;
+
+ if (m_out_size.x < data.get_size().x ){
+ block_size.x = (data.get_size().x + m_out_size.x - 1) / m_out_size.x;
+ }else{
+ coordinate_scale.x = float(data.get_size().x) / float(m_out_size.x);
+ }
+
+ if (m_out_size.y < data.get_size().y ) {
+ block_size.y = (data.get_size().y + m_out_size.y - 1) / m_out_size.y;
+ }else{
+ coordinate_scale.y = float(data.get_size().y) / float(m_out_size.y);
+ }
+
+ if (m_out_size.z < data.get_size().z ) {
+ block_size.z = (data.get_size().z + m_out_size.z - 1) / m_out_size.z;
+ }else{
+ coordinate_scale.z = float(data.get_size().z) / float(m_out_size.z);
+ }
+
+ vector<T> buffer;
+ buffer.reserve(block_size.product());
+ auto ir = result->begin();
+
+ for (unsigned z = 0; z < m_out_size.z; ++z) {
+ unsigned iz = static_cast<unsigned>(floor(z * coordinate_scale.z));
+ auto rangez = clamp_coord(iz, block_size.z, data.get_size().z);
+
+ for (unsigned y = 0; y < m_out_size.y; ++y) {
+ unsigned iy = static_cast<unsigned>(floor(y * coordinate_scale.y));
+ auto rangey = clamp_coord(iy, block_size.y, data.get_size().y);
+ for (unsigned x = 0; x < m_out_size.x; ++x, ++ir) {
+ unsigned ix = static_cast<unsigned>(floor(x * coordinate_scale.x));
+ auto rangex = clamp_coord(ix, block_size.x, data.get_size().x);
+ C3DBounds ibegin(rangex.first, rangey.first, rangez.first);
+ C3DBounds iend(rangex.second, rangey.second, rangez.second);
+
+ buffer.clear();
+ for_each(data.begin_range(ibegin, iend), data.end_range(ibegin, iend),
+ [&buffer](T pixel) {
+ buffer.push_back(pixel);
+ });
+
+ sort(buffer.begin(), buffer.end());
+ *ir = get_max_represented(buffer);
+ }
+ }
+ }
+
+ C3DFVector voxel_size = data.get_voxel_size();
+ C3DFVector factor(float(data.get_size().x / float(m_out_size.x) ),
+ float(data.get_size().y / float(m_out_size.y) ),
+ float(data.get_size().z / float(m_out_size.z) ));
+
+ result->set_voxel_size(voxel_size * factor);
+
+ return P3DImage(result);
+
+
+}
+
+P3DImage C3DLabelscale::do_filter(const C3DImage& image) const
+{
+ return mia::filter(*this, image);
+}
+
+C3DLabelscaleFilterPluginFactory::C3DLabelscaleFilterPluginFactory():
+C3DFilterPlugin("labelscale")
+{
+ add_parameter("out-size", new C3DBoundsParameter(m_out_size, true, "target size given as two coma separated values"));
+}
+
+C3DFilter *C3DLabelscaleFilterPluginFactory::do_create()const
+{
+ if (m_out_size.x < 1 || m_out_size.y < 1 || m_out_size.z < 1) {
+ throw create_exception<invalid_argument>("labelscale: Output sizes must be positive (got",
+ m_out_size, ")");
+ }
+ return new C3DLabelscale(m_out_size);
+}
+
+const std::string C3DLabelscaleFilterPluginFactory::do_get_descr()const
+{
+ return "A filter that only creates output voxels that are already created in "
+ "the input image. Scaling is done by using a voting algorithms that "
+ "selects the target pixel value based on the highest pixel count of a "
+ "certain label in the corresponding source region. If the region "
+ "comprises two labels with the same count, the one with the lower number "
+ "wins.";
+}
+
+extern "C" EXPORT CPluginBase *get_plugin_interface()
+{
+ return new C3DLabelscaleFilterPluginFactory();
+}
+
+
+NS_END
diff --git a/mia/2d/test_combiner.cc b/mia/3d/filter/labelscale.hh
similarity index 54%
copy from mia/2d/test_combiner.cc
copy to mia/3d/filter/labelscale.hh
index ebf7895..c8d5905 100644
--- a/mia/2d/test_combiner.cc
+++ b/mia/3d/filter/labelscale.hh
@@ -18,26 +18,33 @@
*
*/
-#include <stdexcept>
-#include <climits>
+#include <mia/3d/filter.hh>
-#include <mia/internal/autotest.hh>
-#include <boost/filesystem/path.hpp>
-#include <mia/2d/filter.hh>
+NS_BEGIN( labelscale_3dimage_filter)
+class C3DLabelscale : public mia::C3DFilter {
+public:
+ C3DLabelscale(const mia::C3DBounds& out_size);
-NS_MIA_USE
-using namespace boost;
-using namespace std;
-namespace bfs=boost::filesystem;
+ template <class T>
+ typename C3DLabelscale::result_type operator () (const mia::T3DImage<T>& data) const ;
+private:
+ virtual mia::P3DImage do_filter(const mia::C3DImage& image) const;
-BOOST_AUTO_TEST_CASE( test_load_plugins )
-{
- CPathNameArray plugpath;
- plugpath.push_back(bfs::path("combiner"));
- C2DImageCombinerPluginHandler::set_search_path(plugpath);
+ mia::C3DBounds m_out_size;
- const C2DImageCombinerPluginHandler::Instance& handler = C2DImageCombinerPluginHandler::instance();
- BOOST_CHECK_EQUAL(handler.size(), 5u);
- BOOST_CHECK_EQUAL(handler.get_plugin_names(), "absdiff add div mul sub ");
-}
+};
+
+class C3DLabelscaleFilterPluginFactory: public mia::C3DFilterPlugin {
+public:
+ C3DLabelscaleFilterPluginFactory();
+private:
+ virtual mia::C3DFilter *do_create()const;
+ virtual const std::string do_get_descr()const;
+
+ mia::C3DBounds m_out_size;
+};
+
+
+
+NS_END
diff --git a/mia/3d/filter/test_bandpass.cc b/mia/3d/filter/test_bandpass.cc
index ce1a4ba..2f223c0 100644
--- a/mia/3d/filter/test_bandpass.cc
+++ b/mia/3d/filter/test_bandpass.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
BOOST_AUTO_TEST_CASE( test_bandpass )
diff --git a/mia/3d/filter/test_binarize.cc b/mia/3d/filter/test_binarize.cc
index 3f094e7..0a1add4 100644
--- a/mia/3d/filter/test_binarize.cc
+++ b/mia/3d/filter/test_binarize.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
diff --git a/mia/3d/filter/test_convert.cc b/mia/3d/filter/test_convert.cc
index c724579..4a6e64f 100644
--- a/mia/3d/filter/test_convert.cc
+++ b/mia/3d/filter/test_convert.cc
@@ -28,7 +28,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
namespace bmpl=boost::mpl;
diff --git a/mia/3d/filter/test_crop.cc b/mia/3d/filter/test_crop.cc
index bd2c226..b881288 100644
--- a/mia/3d/filter/test_crop.cc
+++ b/mia/3d/filter/test_crop.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace crop_3d_filter;
diff --git a/mia/3d/filter/test_downscale.cc b/mia/3d/filter/test_downscale.cc
index 06ea0fe..be69298 100644
--- a/mia/3d/filter/test_downscale.cc
+++ b/mia/3d/filter/test_downscale.cc
@@ -24,7 +24,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
namespace bfs=boost::filesystem;
using namespace downscale_3dimage_filter;
diff --git a/mia/3d/filter/test_gradnorm.cc b/mia/3d/filter/test_gradnorm.cc
index a57c101..f9b4b2d 100644
--- a/mia/3d/filter/test_gradnorm.cc
+++ b/mia/3d/filter/test_gradnorm.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace gradnorm_3dimage_filter;
diff --git a/mia/3d/filter/test_growmask.cc b/mia/3d/filter/test_growmask.cc
index d80daec..e6621a8 100644
--- a/mia/3d/filter/test_growmask.cc
+++ b/mia/3d/filter/test_growmask.cc
@@ -25,7 +25,6 @@ namespace bfs=boost::filesystem;
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace growmask_3dimage_filter;
diff --git a/mia/3d/filter/test_invert.cc b/mia/3d/filter/test_invert.cc
index 0274550..586ee03 100644
--- a/mia/3d/filter/test_invert.cc
+++ b/mia/3d/filter/test_invert.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
BOOST_AUTO_TEST_CASE( test_invert_float )
diff --git a/mia/3d/filter/test_kmeans.cc b/mia/3d/filter/test_kmeans.cc
index 0d30fe2..3052330 100644
--- a/mia/3d/filter/test_kmeans.cc
+++ b/mia/3d/filter/test_kmeans.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace kmeans_3dimage_filter;
diff --git a/mia/3d/filter/test_label.cc b/mia/3d/filter/test_label.cc
index fbc92af..a574a83 100644
--- a/mia/3d/filter/test_label.cc
+++ b/mia/3d/filter/test_label.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
namespace bfs=boost::filesystem;
using namespace label_3dimage_filter;
diff --git a/mia/3d/filter/test_labelscale.cc b/mia/3d/filter/test_labelscale.cc
new file mode 100644
index 0000000..66302a1
--- /dev/null
+++ b/mia/3d/filter/test_labelscale.cc
@@ -0,0 +1,169 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mia/internal/plugintester.hh>
+#include <mia/3d/filter/labelscale.hh>
+
+using namespace labelscale_3dimage_filter;
+using namespace mia;
+
+BOOST_AUTO_TEST_CASE ( test_labelscale_downscale )
+{
+ const C3DBounds in_size(10, 4, 6);
+
+ const unsigned char in_image[240] = {
+ 1, 1, 1, 2, 2, 2, 2, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 2, 3, 3, 3,
+ 1, 1, 1, 2, 2, 3, 3, 3, 4, 4,
+ 5, 5, 5, 2, 2, 2, 3, 3, 4, 4,
+
+ 1, 1, 1, 2, 2, 3, 3, 3, 3, 3,
+ 1, 1, 1, 2, 7, 2, 3, 3, 3, 3,
+ 5, 6, 5, 7, 7, 7, 7, 3, 4, 4,
+ 6, 6, 6, 7, 7, 7, 7, 3, 4, 4,
+
+ 1, 1, 1, 7, 7, 7, 7, 3, 3, 3,
+ 1, 1, 1, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ 1, 1, 1, 7, 6, 6, 6, 3, 3, 3,
+ 1, 1, 1, 8, 6, 6, 6, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+
+ 1, 1, 1, 7, 6, 6, 6, 3, 3, 3,
+ 1, 1, 1, 8, 7, 6, 6, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 6, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ 1, 1, 1, 7, 6, 6, 6, 3, 3, 3,
+ 1, 1, 1, 8, 6, 6, 6, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+
+ };
+
+ const C3DBounds out_size(5, 2, 3);
+ const unsigned char out_image[30] = {
+ 1, 2, 2, 3, 3,
+ 5, 2, 7, 3, 4,
+ 1, 1, 6, 7, 3,
+
+ 8, 8, 7, 7, 3,
+ 1, 1, 6, 6, 3,
+ 8, 8, 7, 7, 3
+
+ };
+
+ auto f = BOOST_TEST_create_from_plugin<C3DLabelscaleFilterPluginFactory>("labelscale:out-size=[5,2,3]");
+
+
+ C3DUBImage fimage(in_size, in_image );
+ fimage.set_voxel_size(C3DFVector(2.0, 3.0, 4.0));
+
+ P3DImage scaled = f->filter(fimage);
+
+ BOOST_CHECK_EQUAL(scaled->get_size(), out_size);
+
+ const C3DUBImage& fscaled = dynamic_cast<const C3DUBImage& >(*scaled);
+ BOOST_REQUIRE(scaled->get_size() == out_size);
+
+ BOOST_CHECK_EQUAL(fscaled.get_voxel_size(), C3DFVector(4.0f, 6.f, 8.0));
+
+ for (size_t i = 0; i < 30; ++i) {
+ cvdebug() << i << ":" << fscaled[i] << " - " << out_image[i] << '\n';
+ BOOST_CHECK_EQUAL(fscaled[i], out_image[i]);
+ }
+
+}
+
+
+
+BOOST_AUTO_TEST_CASE ( test_labelscale_upscale )
+{
+ const C3DBounds out_size(10, 6, 4);
+
+ const unsigned char out_image[240] = {
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 5, 5, 2, 2, 7, 7, 3, 3, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+ 8, 8, 8, 8, 7, 7, 7, 7, 3, 3,
+
+ 3, 3, 4, 4, 2, 2, 9, 9, 9, 9,
+ 3, 3, 4, 4, 2, 2, 9, 9, 9, 9,
+ 5, 5, 2, 2, 2, 2, 3, 3, 6, 6,
+ 5, 5, 2, 2, 2, 2, 3, 3, 6, 6,
+ 8, 8, 1, 1, 3, 3, 1, 1, 3, 3,
+ 8, 8, 1, 1, 3, 3, 1, 1, 3, 3,
+
+ 3, 3, 4, 4, 2, 2, 9, 9, 9, 9,
+ 3, 3, 4, 4, 2, 2, 9, 9, 9, 9,
+ 5, 5, 2, 2, 2, 2, 3, 3, 6, 6,
+ 5, 5, 2, 2, 2, 2, 3, 3, 6, 6,
+ 8, 8, 1, 1, 3, 3, 1, 1, 3, 3,
+ 8, 8, 1, 1, 3, 3, 1, 1, 3, 3,
+
+ };
+
+ const C3DBounds in_size(5, 3, 2);
+ const unsigned char in_image[30] = {
+ 1, 2, 2, 3, 3,
+ 5, 2, 7, 3, 3,
+ 8, 8, 7, 7, 3,
+ 3, 4, 2, 9, 9,
+ 5, 2, 2, 3, 6,
+ 8, 1, 3, 1, 3
+
+ };
+
+ auto f = BOOST_TEST_create_from_plugin<C3DLabelscaleFilterPluginFactory>("labelscale:out-size=[10,6,4]");
+
+
+ C3DUBImage fimage(in_size, in_image );
+ fimage.set_voxel_size(C3DFVector(2.0, 3.0, 4.0));
+
+ P3DImage scaled = f->filter(fimage);
+
+ BOOST_CHECK_EQUAL(scaled->get_size(), out_size);
+
+ const C3DUBImage& fscaled = dynamic_cast<const C3DUBImage& >(*scaled);
+ BOOST_REQUIRE(scaled->get_size() == out_size);
+
+ BOOST_CHECK_EQUAL(fscaled.get_voxel_size(), C3DFVector(1.0f, 1.5f, 2.0));
+
+ for (size_t i = 0; i < 240; ++i) {
+ cvdebug() << i << ":" << int(fscaled[i]) << " - " << int(out_image[i]) << '\n';
+ BOOST_CHECK_EQUAL(fscaled[i], out_image[i]);
+ }
+
+}
+
diff --git a/mia/3d/filter/test_load.cc b/mia/3d/filter/test_load.cc
index 4c353a0..cb84a5c 100644
--- a/mia/3d/filter/test_load.cc
+++ b/mia/3d/filter/test_load.cc
@@ -25,7 +25,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace load_3dimage_filter;
diff --git a/mia/3d/filter/test_mask.cc b/mia/3d/filter/test_mask.cc
index 8f88413..0cba453 100644
--- a/mia/3d/filter/test_mask.cc
+++ b/mia/3d/filter/test_mask.cc
@@ -24,7 +24,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace mask_3dimage_filter;
diff --git a/mia/3d/filter/test_median.cc b/mia/3d/filter/test_median.cc
index 60d551d..f6966f9 100644
--- a/mia/3d/filter/test_median.cc
+++ b/mia/3d/filter/test_median.cc
@@ -24,7 +24,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace median_3dimage_filter;
diff --git a/mia/3d/filter/test_mlv.cc b/mia/3d/filter/test_mlv.cc
index 9ac5ec6..fec1b52 100644
--- a/mia/3d/filter/test_mlv.cc
+++ b/mia/3d/filter/test_mlv.cc
@@ -24,7 +24,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace mlv_3dimage_filter;
diff --git a/mia/3d/filter/test_morphological.cc b/mia/3d/filter/test_morphological.cc
index c3699f3..0800c25 100644
--- a/mia/3d/filter/test_morphological.cc
+++ b/mia/3d/filter/test_morphological.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
namespace bfs=boost::filesystem;
using namespace morph_3dimage_filter;
diff --git a/mia/3d/filter/test_reorient.cc b/mia/3d/filter/test_reorient.cc
index 2e8de09..8e1f5a4 100644
--- a/mia/3d/filter/test_reorient.cc
+++ b/mia/3d/filter/test_reorient.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace reorient_3dimage_filter;
diff --git a/mia/3d/filter/test_scale.cc b/mia/3d/filter/test_scale.cc
index fe7399a..dd9108a 100644
--- a/mia/3d/filter/test_scale.cc
+++ b/mia/3d/filter/test_scale.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace scale_3dimage_filter;
diff --git a/mia/3d/filter/test_selectbig.cc b/mia/3d/filter/test_selectbig.cc
index 4ee03d1..2a2f06f 100644
--- a/mia/3d/filter/test_selectbig.cc
+++ b/mia/3d/filter/test_selectbig.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace selectbig_3dimage_filter;
diff --git a/mia/3d/filter/test_sepconv.cc b/mia/3d/filter/test_sepconv.cc
index be15403..1efee04 100644
--- a/mia/3d/filter/test_sepconv.cc
+++ b/mia/3d/filter/test_sepconv.cc
@@ -23,7 +23,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
namespace bfs=boost::filesystem;
using namespace sepconv_3dimage_filter;
diff --git a/mia/3d/filter/test_tee.cc b/mia/3d/filter/test_tee.cc
index 67a57a2..700922a 100644
--- a/mia/3d/filter/test_tee.cc
+++ b/mia/3d/filter/test_tee.cc
@@ -25,7 +25,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
using namespace ::boost::unit_test;
using namespace tee_3dimage_filter;
diff --git a/mia/3d/fullcost/CMakeLists.txt b/mia/3d/fullcost/CMakeLists.txt
index f7f2d59..c324b30 100644
--- a/mia/3d/fullcost/CMakeLists.txt
+++ b/mia/3d/fullcost/CMakeLists.txt
@@ -16,7 +16,7 @@
# along with this program; if not, see <http://www.gnu.org/licenses/>.
#
-SET(fullcost image maskedimage taggedssd)
+SET(fullcost image label maskedimage taggedssd)
PLUGINGROUP_WITH_TEST_AND_PREFIX2("3dimage" "fullcost" "${fullcost}" mia3d TESTLIBS
mia3dtest
)
diff --git a/mia/3d/fullcost/label.cc b/mia/3d/fullcost/label.cc
new file mode 100644
index 0000000..cd9f62b
--- /dev/null
+++ b/mia/3d/fullcost/label.cc
@@ -0,0 +1,321 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <cmath>
+
+#include <mia/3d/fullcost/label.hh>
+#include <mia/3d/filter.hh>
+#include <mia/core/distance.hh>
+#include <mia/3d/distance.hh>
+
+NS_MIA_BEGIN
+using namespace std;
+
+C3DLabelFullCost::C3DLabelFullCost(const std::string& src,
+ const std::string& ref,
+ double weight,
+ int maxlabels):
+ C3DFullCost(weight),
+ m_src_key(C3DImageIOPluginHandler::instance().load_to_pool(src)),
+ m_ref_key(C3DImageIOPluginHandler::instance().load_to_pool(ref)),
+ m_ref_label_exists(maxlabels),
+ m_ref_distances(maxlabels)
+{
+ add(::mia::property_gradient);
+}
+
+bool C3DLabelFullCost::do_get_full_size(C3DBounds& size) const
+{
+ TRACE_FUNCTION;
+ assert(m_src);
+ if (size == C3DBounds::_0) {
+ size = m_src->get_size();
+ return true;
+ }else
+ return size == m_src->get_size();
+}
+
+
+double C3DLabelFullCost::do_value(const C3DTransformation& t) const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+ P3DImage temp = t(m_src_scaled);
+ const C3DUBImage& temp_ubyte = static_cast<const C3DUBImage&>(*temp);
+
+ double result = 0.0;
+ for (size_t i = 0; i < temp_ubyte.size(); ++i) {
+ double v = value(i, temp_ubyte[i]);
+ result += v;
+ }
+ return result;
+}
+
+double C3DLabelFullCost::do_value() const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+ // one should apply an identity transform here, to ensure that the test image is
+ // of the same size like the reference image
+
+ double result = 0.0;
+ for (size_t i = 0; i < m_src_scaled.size(); ++i) {
+ result += value(i, m_src_scaled[i]);
+ }
+ return result;
+}
+
+
+double C3DLabelFullCost::do_evaluate(const C3DTransformation& t, CDoubleVector& gradient) const
+{
+ TRACE_FUNCTION;
+ assert(m_src_scaled.size());
+
+ assert("add Z loop");
+ P3DImage temp = t(m_src_scaled);
+ const C3DUBImage& temp_ubyte = static_cast<const C3DUBImage&>(*temp);
+
+ C3DFVectorfield force(get_current_size());
+
+ int idx = 0;
+ auto i = temp_ubyte.begin_range_with_boundary_flags(C3DBounds::_0, temp_ubyte.get_size());
+ auto e = temp_ubyte.end_range_with_boundary_flags(C3DBounds::_0, temp_ubyte.get_size());
+ auto ig = force.begin();
+
+
+ double result = 0.0;
+ while (i != e) {
+ result += value_and_gradient(idx, i, *ig);
+ ++i;
+ ++ig;
+ ++idx;
+ }
+
+
+
+ // at this point one could inject a hole-filling algorithm to
+ // add forces inside of the homogen overlapping label regions
+
+ t.translate(force, gradient);
+
+ cvdebug() << "Image cost =" << result << "\n";
+ return result;
+
+}
+
+void C3DLabelFullCost::do_set_size()
+{
+ TRACE_FUNCTION;
+ assert(m_src);
+ assert(m_ref);
+
+ if (m_src_scaled.size() || m_src_scaled.get_size() != get_current_size() ||
+ m_ref_scaled.size() || m_ref_scaled.get_size() != get_current_size() ) {
+ if (get_current_size() == m_src->get_size()) {
+ m_src_scaled = static_cast<const C3DUBImage&>(*m_src);
+ m_ref_scaled = static_cast<const C3DUBImage&>(*m_ref);
+ }else{
+ stringstream filter_descr;
+ filter_descr << "labelscale:s=[" << get_current_size()<<"]";
+ auto scaler = C3DFilterPluginHandler::instance().produce(filter_descr.str());
+ assert(scaler);
+ cvdebug() << "C3DLabelFullCost:scale images to " << get_current_size() <<
+ " using '" << filter_descr.str() << "'\n";
+ m_src_scaled = static_cast<const C3DUBImage&>(*scaler->filter(*m_src));
+ m_ref_scaled = static_cast<const C3DUBImage&>(*scaler->filter(*m_ref));
+ }
+ prepare_distance_fields(m_ref_scaled);
+ }
+
+}
+
+void C3DLabelFullCost::prepare_distance_fields( const C3DUBImage &image )
+{
+ assert(image.get_pixel_type() == it_ubyte);
+
+
+
+ for (size_t i = 0; i < m_ref_label_exists.size(); ++i) {
+ bool exist = false;
+
+ stringstream filter_descr;
+ filter_descr << "binarize:min=" << i << ",max=" << i;
+ auto bin = run_filter(image, filter_descr.str().c_str());
+
+ const C3DBitImage& bool_bin = static_cast<const C3DBitImage&>(*bin);
+ for (auto i = bool_bin.begin(); i != bool_bin.end() && !exist; ++i)
+ exist = *i;
+
+ m_ref_label_exists[i] = exist;
+ if (exist) {
+ C3DFImage prep(bool_bin.get_size());
+ distance_transform_prepare(bool_bin.begin(), bool_bin.end(),
+ prep.begin());
+
+ m_ref_distances[i] = distance_transform(prep);
+ transform(m_ref_distances[i].begin(), m_ref_distances[i].end(),
+ m_ref_distances[i].begin(), [](float& x){ return sqrt(x);});
+
+ }
+ }
+}
+
+double C3DLabelFullCost::value(int idx, int label) const
+{
+ // non existent labels will be ignored, since they never can be
+ // aligned
+ return m_ref_label_exists[label] ? m_ref_distances[label][idx] : 0.0;
+}
+
+double C3DLabelFullCost::value_and_gradient(int idx, const C3DUBImage::const_range_iterator_with_boundary_flag& i, C3DFVector& gradient) const
+{
+ double result = 0.0;
+
+ if (m_ref_label_exists[*i]) {
+ const auto & dref = m_ref_distances[*i];
+ result = dref[idx];
+ if (result > 0.0) {
+ auto boundaries = i.get_boundary_flags();
+ if (boundaries == eb_none)
+ gradient = dref.get_gradient(idx);
+ else { // emulate repeat boundary conditions
+ const auto& pos = i.pos();
+ switch (boundaries & eb_x) {
+ case eb_xlow:
+ gradient.x = 0.5 * (dref(pos.x + 1, pos.y, pos.z) - dref(pos.x, pos.y, pos.z));
+ break;
+ case eb_xhigh:
+ gradient.x = 0.5 * (dref(pos.x, pos.y, pos.z) - dref(pos.x - 1, pos.y, pos.z));
+ break;
+ default:
+ gradient.x = 0.5 * (dref(pos.x + 1, pos.y, pos.z) - dref(pos.x - 1, pos.y, pos.z));
+ }
+
+ switch (boundaries & eb_y) {
+ case eb_ylow:
+ gradient.y = 0.5 * (dref(pos.x, pos.y + 1, pos.z) - dref(pos.x, pos.y, pos.z));
+ break;
+ case eb_yhigh:
+ gradient.y = 0.5 * (dref(pos.x, pos.y, pos.z) - dref(pos.x, pos.y - 1, pos.z));
+ break;
+ default:
+ gradient.y = 0.5 * (dref(pos.x, pos.y + 1, pos.z) - dref(pos.x, pos.y - 1, pos.z));
+ }
+
+ switch (boundaries & eb_z) {
+ case eb_zlow:
+ gradient.z = 0.5 * (dref(pos.x, pos.y, pos.z + 1) - dref(pos.x, pos.y, pos.z));
+ break;
+ case eb_zhigh:
+ gradient.z = 0.5 * (dref(pos.x, pos.y, pos.z) - dref(pos.x, pos.y, pos.z - 1));
+ break;
+ default:
+ gradient.z = 0.5 * (dref(pos.x, pos.y, pos.z + 1) - dref(pos.x, pos.y, pos.z - 1));
+ }
+
+ }
+ }else{
+ gradient = C3DFVector::_0;
+ }
+ }else {
+ gradient = C3DFVector::_0;
+ }
+ return result;
+}
+
+
+void C3DLabelFullCost::do_reinit()
+{
+ TRACE_FUNCTION;
+ m_src = get_from_pool(m_src_key);
+ m_ref = get_from_pool(m_ref_key);
+ m_src_scaled = C3DUBImage();
+ m_ref_scaled = C3DUBImage();
+
+ // is this true? Actually the deformed image is used and it is always interpolated on the full
+ // space of the reference image
+ if (m_src->get_size() != m_ref->get_size())
+ throw runtime_error("C3DLabelFullCost only works with images of equal size");
+
+ if (m_src->get_voxel_size() != m_ref->get_voxel_size()) {
+ cvwarn() << "C3DLabelFullCost: src and reference image are of differnet voxel dimensions:"
+ << m_src->get_voxel_size() << " vs " << m_ref->get_voxel_size()
+ << " This code doesn't honour this.\n";
+ }
+ if (m_src->get_pixel_type() != it_ubyte)
+ throw create_exception<runtime_error>("C3DLabelFullCost only works with (label) "
+ "images of voxel type ubyte, but src has type ",
+ CPixelTypeDict.get_name(m_src->get_pixel_type()));
+
+ if (m_ref->get_pixel_type() != it_ubyte)
+ throw create_exception<runtime_error>("C3DLabelFullCost only works with (label) "
+ "images of voxel type ubyte, but ref has type ",
+ CPixelTypeDict.get_name(m_src->get_pixel_type()));
+}
+
+P3DImage C3DLabelFullCost::get_from_pool(const C3DImageDataKey& key)
+{
+ C3DImageIOPlugin::PData in_image_list = key.get();
+
+ if (!in_image_list || in_image_list->empty())
+ throw invalid_argument("C3DLabelFullCost: no image available in data pool");
+
+ return (*in_image_list)[0];
+}
+
+
+C3DLabelFullCostPlugin::C3DLabelFullCostPlugin():
+ C3DFullCostPlugin("labelimage"),
+ m_src_name("src.@"),
+ m_ref_name("ref.@"),
+ m_maxlabel(256)
+{
+ add_parameter("src", new CStringParameter(m_src_name, CCmdOptionFlags::input, "Study image",
+ &C3DImageIOPluginHandler::instance()));
+ add_parameter("ref", new CStringParameter(m_ref_name, CCmdOptionFlags::input, "Reference image",
+ &C3DImageIOPluginHandler::instance()));
+ add_parameter("maxlabel", new CIntParameter(m_maxlabel, 2, 32000, false,
+ "maximum number of labels to consider"));
+}
+
+C3DFullCost *C3DLabelFullCostPlugin::do_create(float weight) const
+{
+ cvdebug() << "create C3DLabelFullCostPlugin with weight= " << weight
+ << " src=" << m_src_name << " ref=" << m_ref_name
+ << " naxlabels=" << m_maxlabel << "\n";
+ return new C3DLabelFullCost(m_src_name, m_ref_name,
+ weight, m_maxlabel);
+}
+
+const std::string C3DLabelFullCostPlugin::do_get_descr() const
+{
+ return "Similarity cost function that maps labels of two images and handles "
+ "label-preserving multi-resolution processing.";
+
+}
+
+extern "C" EXPORT CPluginBase *get_plugin_interface()
+{
+ return new C3DLabelFullCostPlugin();
+}
+
+NS_MIA_END
diff --git a/mia/3d/fullcost/label.hh b/mia/3d/fullcost/label.hh
new file mode 100644
index 0000000..8a0299d
--- /dev/null
+++ b/mia/3d/fullcost/label.hh
@@ -0,0 +1,100 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef mia_3d_imagefullcost_hh
+#define mia_3d_imagefullcost_hh
+
+
+#include <mia/3d/fullcost.hh>
+#include <mia/3d/imageio.hh>
+#include <mia/3d/cost.hh>
+
+NS_MIA_BEGIN
+
+class EXPORT C3DLabelFullCost : public C3DFullCost {
+public:
+ C3DLabelFullCost(const std::string& src,
+ const std::string& ref,
+ double weight,
+ int maxlabels);
+private:
+ double do_evaluate(const C3DTransformation& t, CDoubleVector& gradient) const;
+ void do_set_size();
+
+ static P3DImage get_from_pool(const C3DImageDataKey& key);
+
+ double do_value(const C3DTransformation& t) const;
+ bool do_get_full_size(C3DBounds& size) const;
+
+ double value(int idx, int label) const;
+ double value_and_gradient(int idx, const C3DUBImage::const_range_iterator_with_boundary_flag& i,
+ C3DFVector& gradient) const;
+ void prepare_distance_fields(const C3DUBImage& image);
+
+ double do_value() const;
+ void do_reinit();
+
+ C3DImageDataKey m_src_key;
+ C3DImageDataKey m_ref_key;
+
+ P3DImage m_src;
+ P3DImage m_ref;
+
+ C3DUBImage m_src_scaled;
+ C3DUBImage m_ref_scaled;
+
+ std::vector<bool> m_ref_label_exists;
+ std::vector<C3DFImage> m_ref_distances;
+
+ enum EBoundaries {
+ eb_none = 0,
+ eb_xlow = 1, /**< at low x-boundary */
+ eb_xhigh = 2, /**< at high x-boundary */
+ eb_x = 3, /**< at high x-boundary */
+ eb_ylow = 4, /**< at low y-boundary */
+ eb_yhigh = 8, /**< at high y-boundary */
+ eb_y = 12, /**< any y-boundary */
+ eb_zlow = 0x10, /**< at low y-boundary */
+ eb_zhigh = 0x20, /**< at high y-boundary */
+ eb_z = 0x30, /**< any y-boundary */
+
+ };
+
+
+};
+
+// plugin implementation
+class C3DLabelFullCostPlugin: public C3DFullCostPlugin {
+public:
+ C3DLabelFullCostPlugin();
+private:
+ C3DFullCost *do_create(float weight) const;
+ const std::string do_get_descr() const;
+
+
+ std::string m_src_name;
+ std::string m_ref_name;
+ int m_maxlabel;
+};
+
+
+NS_MIA_END
+
+#endif
diff --git a/mia/3d/fullcost/test_label.cc b/mia/3d/fullcost/test_label.cc
new file mode 100644
index 0000000..23454c8
--- /dev/null
+++ b/mia/3d/fullcost/test_label.cc
@@ -0,0 +1,203 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <mia/internal/plugintester.hh>
+#include <mia/3d/fullcost/label.hh>
+#include <mia/3d/transformfactory.hh>
+
+NS_MIA_USE
+
+
+struct TransformInitFixture {
+ TransformInitFixture();
+
+ P3DTransformationFactory tff;
+};
+
+
+BOOST_FIXTURE_TEST_CASE ( test_labeldistance, TransformInitFixture )
+{
+ // create two images and do the thing
+
+
+ const unsigned char mov_data[75] = {
+ 1, 1, 2, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 1, 2, 2,
+ 1, 1, 5, 2, 2,
+ 5, 5, 5, 5, 2,
+
+ 1, 1, 3, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 1, 2, 2,
+ 1, 5, 5, 2, 2,
+ 5, 5, 5, 5, 2,
+
+ 1, 1, 2, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 2, 2, 2,
+ 1, 1, 1, 2, 2,
+ 5, 5, 5, 5, 2,
+
+ };
+
+ const unsigned char ref_data[75] = {
+ 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 5, 5, 5, 2, 2, 5, 5, 2, 2, 2,
+ 1, 1, 3, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 5, 5, 5, 2, 2, 5, 5, 2, 2, 2,
+ 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 5, 5, 2, 2, 2, 5, 5, 2, 2, 2,
+ };
+
+#if 0
+ const float distances [75] = {
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 1, 0, 0, 0,
+ 0, 0, 1, sqrtf(2.0f), 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0,
+ 0, 0, 1, sqrtf(2.0f), 0,
+
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 1, 1, 1, 0, 0,
+ 0, 0, 1, sqrtf(3.0f), 0
+
+ };
+
+#endif
+ const float gradz [75] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5f * (sqrtf(2.0f) - sqrtf(3.0f)) , 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.5f * (sqrtf(2.0f) - sqrtf(3.0f)), 0
+
+ };
+
+ const float grady [75] = {
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ -1, -1, 0, 0, 0,
+ 0, 0,-.5f, -.5f * (sqrtf(2.0f) - 1.0f), 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ -1,0, 0, 0, 0,
+ 0, 0,-.5f, -.5f * (sqrtf(2.0f) - 1.0f), 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0.5f, 0, 0,
+ -1, -1, -1, 0, 0,
+ 0, 0, 0, -.5f * (sqrtf(3.0f) - sqrtf(2.0f)), 0
+
+ };
+
+ const float gradx [75] = {
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, -0.5f * sqrtf(2.0f), -0.5f * (sqrtf(5.0f) - 1.0f), 0,
+
+ 0, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, -0.5f * sqrtf(2.0f), -0.5f * (sqrtf(5.0f) - 1.0f), 0,
+
+ 0, 0, 1, 0, 0,
+ 0, 0, 1, 0, 0,
+ 0, 0, 0.5f * sqrtf(2.0f), 0, 0,
+ 0, 0, -.5f * (sqrtf(2.0f) - 1.0f) , 0, 0,
+ 0, 0, -0.5f * sqrtf(3.0f), -0.5f * (sqrtf(6.0f) - 1.0f), 0
+
+ };
+
+
+
+
+ const C3DBounds size(5,5,3);
+
+
+ C3DUBImage *mov_image = new C3DUBImage(size, mov_data );
+ C3DUBImage *ref_image = new C3DUBImage(size, ref_data );
+
+ P3DImage mov(mov_image);
+ P3DImage ref(ref_image);
+
+ auto cost = BOOST_TEST_create_from_plugin<C3DLabelFullCostPlugin>("labelimage:maxlabel=7");
+
+ auto t = tff->create(size);
+ auto params = t->get_parameters();
+ std::fill(params.begin(), params.end(), 0.0);
+ t->set_parameters(params);
+
+ save_image("src.@", mov);
+ save_image("ref.@", ref);
+
+ cost->reinit();
+ cost->set_size(size);
+
+ BOOST_CHECK_CLOSE(cost->cost_value(*t), 15 + 2 * sqrt(2.0) + sqrt(3.0), 0.01);
+ BOOST_CHECK_CLOSE(cost->cost_value(), 15 + 2 * sqrt(2.0) + sqrt(3.0), 0.01);
+
+
+ CDoubleVector gradient(t->degrees_of_freedom());
+ double cost_value = cost->evaluate(*t, gradient);
+ BOOST_CHECK_CLOSE(cost_value, 15 + 2 * sqrt(2.0) + sqrt(3.0), 0.01);
+
+ for(int i = 0; i < 75; ++i) {
+ cvdebug() << "[" << i << "]: (" << gradient[3*i] << ", " << gradient[3*i+1] << ", " << gradient[3*i+2]
+ << ") expect ("<< gradx[i] << ", " << grady[i] << ", " << gradz[i] << ")\n";
+
+ if (gradx[i] != 0.0)
+ BOOST_CHECK_CLOSE(gradient[3*i], gradx[i], 0.1);
+ else
+ BOOST_CHECK_SMALL(gradient[3*i], 1e-10);
+
+ if (grady[i] != 0.0)
+ BOOST_CHECK_CLOSE(gradient[3*i+1], grady[i], 0.1);
+ else
+ BOOST_CHECK_SMALL(gradient[3*i+1], 1e-10);
+
+ if (gradz[i] != 0.0)
+ BOOST_CHECK_CLOSE(gradient[3*i+2], gradz[i], 0.1);
+ else
+ BOOST_CHECK_SMALL(gradient[3*i+2], 1e-10);
+
+
+ }
+
+}
+
+
+
+
+TransformInitFixture::TransformInitFixture():
+ tff(C3DTransformCreatorHandler::instance().produce("vf:imgkernel=[bspline:d=0],imgboundary=zero"))
+{
+
+}
diff --git a/mia/3d/image.hh b/mia/3d/image.hh
index fb308ac..554fd7d 100644
--- a/mia/3d/image.hh
+++ b/mia/3d/image.hh
@@ -289,6 +289,27 @@ public:
}
+ /** \returns an read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ range_iterator_with_boundary_flag begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end){
+ return m_image.begin_range_with_boundary_flags(begin, end);
+ }
+
+ /** \returns the end of a read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ range_iterator_with_boundary_flag end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end){
+ return m_image.end_range_with_boundary_flags(begin, end);
+ }
+
+
+ /** \returns an read/write forward iterator over a subset of the data with indicator for the boundaries.
+ The functions ensures, that the field uses a single referenced datafield */
+ const_range_iterator_with_boundary_flag begin_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const{
+ return m_image.begin_range_with_boundary_flags(begin, end);
+ }
+
+ /** \returns the end of a read/write forward iterator over a subset of the data with indicator for the boundaries. */
+ const_range_iterator_with_boundary_flag end_range_with_boundary_flags(const C3DBounds& begin, const C3DBounds& end)const{
+ return m_image.end_range_with_boundary_flags(begin, end);
+ }
/// \returns the all over number of pixels/voxels
size_t size() const;
diff --git a/mia/3d/imageiotest.cc b/mia/3d/imageiotest.cc
index 74bf83c..52f6852 100644
--- a/mia/3d/imageiotest.cc
+++ b/mia/3d/imageiotest.cc
@@ -34,9 +34,7 @@
#include <mia/core/filter.hh>
NS_MIA_BEGIN
-using namespace boost;
using namespace std;
-using namespace boost::unit_test;
namespace bfs=::boost::filesystem;
#ifdef WIN32
diff --git a/mia/3d/imagetest.cc b/mia/3d/imagetest.cc
index b0a8731..cf5993a 100644
--- a/mia/3d/imagetest.cc
+++ b/mia/3d/imagetest.cc
@@ -23,7 +23,6 @@
#include <mia/3d/imagetest.hh>
NS_MIA_BEGIN
-using namespace boost;
template <typename T, typename R>
struct __compare {
diff --git a/mia/3d/interpolator.cc b/mia/3d/interpolator.cc
index 4ccc080..41d62b5 100644
--- a/mia/3d/interpolator.cc
+++ b/mia/3d/interpolator.cc
@@ -38,7 +38,6 @@
NS_MIA_BEGIN
-//using namespace boost;
using namespace std;
CWeightCache::CWeightCache(int kernel_size,
diff --git a/mia/3d/multireg.cc b/mia/3d/multireg.cc
index c5c6f67..f1f9d6e 100644
--- a/mia/3d/multireg.cc
+++ b/mia/3d/multireg.cc
@@ -36,7 +36,6 @@
#include <boost/algorithm/minmax_element.hpp>
NS_MIA_BEGIN
-using namespace boost;
using namespace std;
diff --git a/mia/3d/test_combiner.cc b/mia/3d/test_combiner.cc
index f08f305..f31b1fb 100644
--- a/mia/3d/test_combiner.cc
+++ b/mia/3d/test_combiner.cc
@@ -27,7 +27,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bfs=::boost::filesystem;
static void setup_filter_search_path()
diff --git a/mia/3d/test_cost.cc b/mia/3d/test_cost.cc
index c328655..6ff3c01 100644
--- a/mia/3d/test_cost.cc
+++ b/mia/3d/test_cost.cc
@@ -28,11 +28,8 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bfs=::boost::filesystem;
-using namespace boost::unit_test;
-
static void prepare_plugin_path()
{
list< bfs::path> searchpath;
diff --git a/mia/3d/test_deform.cc b/mia/3d/test_deform.cc
index 8cb1979..ee38a61 100644
--- a/mia/3d/test_deform.cc
+++ b/mia/3d/test_deform.cc
@@ -27,8 +27,6 @@
NS_MIA_USE
using namespace std;
-using namespace ::boost;
-using namespace boost::unit_test;
struct DeformFixture {
DeformFixture();
diff --git a/mia/3d/test_ica.cc b/mia/3d/test_ica.cc
index 2665b56..74f46e4 100644
--- a/mia/3d/test_ica.cc
+++ b/mia/3d/test_ica.cc
@@ -24,7 +24,6 @@
using namespace mia;
using namespace std;
-using namespace ::boost;
using namespace boost::unit_test;
const size_t slices = 5;
diff --git a/mia/3d/test_image.cc b/mia/3d/test_image.cc
index 08c6300..8b2b209 100644
--- a/mia/3d/test_image.cc
+++ b/mia/3d/test_image.cc
@@ -31,7 +31,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
class CCopyFilter: public TFilter<std::shared_ptr<C3DImage> > {
diff --git a/mia/3d/test_interpol.cc b/mia/3d/test_interpol.cc
index 860031d..ce0836f 100644
--- a/mia/3d/test_interpol.cc
+++ b/mia/3d/test_interpol.cc
@@ -31,7 +31,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bmpl=boost::mpl;
template <typename T, typename I, bool is_int>
diff --git a/mia/3d/test_nfg.cc b/mia/3d/test_nfg.cc
index 4f14942..be8f446 100644
--- a/mia/3d/test_nfg.cc
+++ b/mia/3d/test_nfg.cc
@@ -25,7 +25,6 @@
NS_MIA_USE
-using namespace boost;
using namespace std;
const float check_noise_level = sqrt((499.0 - 131.0 * 131.0 / 54.0) / 53.0 );
diff --git a/mia/3d/test_orientation.cc b/mia/3d/test_orientation.cc
index 4cfa842..c0330e1 100644
--- a/mia/3d/test_orientation.cc
+++ b/mia/3d/test_orientation.cc
@@ -27,9 +27,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
-
-using namespace boost::unit_test;
static void run_test_read(const string& id, E3DImageOrientation test_orient,
const string& expect)
diff --git a/mia/3d/test_regplugins.cc b/mia/3d/test_regplugins.cc
index 3de2d65..346981d 100644
--- a/mia/3d/test_regplugins.cc
+++ b/mia/3d/test_regplugins.cc
@@ -35,7 +35,6 @@ namespace bfs=::boost::filesystem;
NS_MIA_USE
using namespace std;
-using namespace boost;
template <typename P>
void test_plugin(const P& i)
diff --git a/mia/3d/test_shape.cc b/mia/3d/test_shape.cc
index 7e83651..71a9e80 100644
--- a/mia/3d/test_shape.cc
+++ b/mia/3d/test_shape.cc
@@ -26,7 +26,6 @@
NS_MIA_USE
using namespace std;
-using namespace boost;
namespace bfs=::boost::filesystem;
static void setup_filter_search_path()
diff --git a/mia/3d/test_transformfactory.cc b/mia/3d/test_transformfactory.cc
index 9e57d23..435d775 100644
--- a/mia/3d/test_transformfactory.cc
+++ b/mia/3d/test_transformfactory.cc
@@ -27,8 +27,6 @@ NS_MIA_USE
using namespace std;
-using namespace ::boost;
-using namespace boost::unit_test;
namespace bfs=boost::filesystem;
struct HandlerTestFixture {
diff --git a/mia/3d/test_vfio.cc b/mia/3d/test_vfio.cc
index 09d0cce..7671dbb 100644
--- a/mia/3d/test_vfio.cc
+++ b/mia/3d/test_vfio.cc
@@ -31,9 +31,7 @@
#include <mia/3d/vfiotest.hh>
NS_MIA_USE
-using namespace boost;
using namespace std;
-using namespace boost::unit_test;
namespace bfs=::boost::filesystem;
static void prepare_handler()
diff --git a/mia/3d/transform/rotbend.cc b/mia/3d/transform/rotbend.cc
index 2ee935c..aad4644 100644
--- a/mia/3d/transform/rotbend.cc
+++ b/mia/3d/transform/rotbend.cc
@@ -39,27 +39,29 @@ C3DFVector C3DRotBendTransformation::apply(const C3DFVector& x) const
C3DFVector C3DRotBendTransformation::transform(const C3DFVector& x)const
{
+ int offset = m_norot ? 0 : 2;
auto y = m_pre_matrix * x;
- if (y.x > 0) {
- const float max_distance = get_size().x - m_rotation_center.x;
- y.z += y.x * y.x * m_params[2] / (max_distance * max_distance + 1);
+ if (y.y > 0) {
+ const float max_distance = get_size().y - m_rotation_center.y;
+ y.z += y.y * y.y * m_params[offset] / (max_distance * max_distance + 1);
}
- else if (y.x < 0) {
- const float max_distance = m_rotation_center.x;
- y.z += y.x * y.x * m_params[3] / (max_distance * max_distance + 1);
+ else if (y.y < 0) {
+ const float max_distance = m_rotation_center.y;
+ y.z += y.y * y.y * m_params[offset + 1] / (max_distance * max_distance + 1);
}
return m_post_matrix * y;
}
-C3DRotBendTransformation::C3DRotBendTransformation(const C3DBounds& size, const C3DFVector& orig,
+C3DRotBendTransformation::C3DRotBendTransformation(const C3DBounds& size, const C3DFVector& orig, bool norot,
const C3DInterpolatorFactory& ipf):
C3DTransformation(ipf),
- m_params(4),
+ m_params(norot ? 2 : 4),
m_relative_origin(orig),
m_rotation_center(C3DFVector(size) * m_relative_origin),
- m_size(size)
+ m_size(size),
+ m_norot(norot)
{
m_pre_matrix.identity();
m_post_matrix.identity();
@@ -105,9 +107,11 @@ void C3DRotBendTransformation::set_parameters(const CDoubleVector& params)
m_pre_matrix.identity();
m_post_matrix.identity();
m_pre_matrix.translate( -1.0f * m_rotation_center);
-
- m_pre_matrix.rotate_x(m_params[0]);
- m_pre_matrix.rotate_y(m_params[1]);
+
+ if (!m_norot) {
+ m_pre_matrix.rotate_x(m_params[0]);
+ m_pre_matrix.rotate_y(m_params[1]);
+ }
m_post_matrix.translate(m_rotation_center);
}
@@ -119,7 +123,7 @@ const C3DBounds& C3DRotBendTransformation::get_size() const
P3DTransformation C3DRotBendTransformation::do_upscale(const C3DBounds& size) const
{
- auto result = new C3DRotBendTransformation(size, m_relative_origin, get_interpolator_factory());
+ auto result = new C3DRotBendTransformation(size, m_relative_origin, m_norot, get_interpolator_factory());
result->set_parameters(m_params);
return P3DTransformation(result);
}
@@ -180,35 +184,6 @@ void C3DRotBendTransformation::translate(const C3DFVectorfield& gradient, CDoubl
{
assert(0 && !"not yet implemented");
- assert(gradient.get_size() == m_size);
- assert(params.size() == degrees_of_freedom());
-
- vector<double> r(params.size(), 0.0);
-
- auto g = gradient.begin();
- for (size_t z = 0; z < m_size.z; ++z) {
- double fy = - m_rotation_center.y;
- for (size_t y = 0; y < m_size.y; ++y, fy += 1.0) {
- double fx = - m_rotation_center.x;
- for (size_t x = 0; x < m_size.x; ++x, ++g, fx += 1.0) {
- r[0] += -fy * g->x + fx * g->y;
-
- // scaling
- r[1] += 0;
- r[2] += 0;
-
-
-
- // shear
- r[3] += 0;
- r[4] += 0;
- r[5] += 0;
-
-
- }
- }
- }
- std::copy(r.begin(), r.end(), params.begin());
}
@@ -287,32 +262,35 @@ float C3DRotBendTransformation::pertuberate(C3DFVectorfield& /*v*/) const
DEBUG_ASSERT_RELEASE_THROW(false, "C3DRotBendTransformation doesn't implement pertuberate.");
}
-C3DRotBendTransformCreator::C3DRotBendTransformCreator(const C3DFVector& origin,
+C3DRotBendTransformCreator::C3DRotBendTransformCreator(const C3DFVector& origin, int norot,
const C3DInterpolatorFactory& ipf):
C3DTransformCreator(ipf),
- m_origin(origin)
+ m_origin(origin),
+ m_norot(norot)
{
}
P3DTransformation C3DRotBendTransformCreator::do_create(const C3DBounds& size,
const C3DInterpolatorFactory& ipf) const
{
- return P3DTransformation(new C3DRotBendTransformation(size, m_origin, ipf));
+ return P3DTransformation(new C3DRotBendTransformation(size, m_origin, m_norot, ipf));
}
C3DRotBendTransformCreatorPlugin::C3DRotBendTransformCreatorPlugin():
- C3DTransformCreatorPlugin("rotbend")
+C3DTransformCreatorPlugin("rotbend"),
+ m_norot(0)
{
add_parameter("origin", new C3DFVectorParameter(m_origin, true, "center of the transformation"));
+ add_parameter("norot", new CIntParameter(m_norot, 0, 1, false, "Don't optimize the rotation"));
}
C3DTransformCreator *C3DRotBendTransformCreatorPlugin::do_create(const C3DInterpolatorFactory& ipf) const
{
- return new C3DRotBendTransformCreator(m_origin, ipf);
+ return new C3DRotBendTransformCreator(m_origin, m_norot, ipf);
}
const std::string C3DRotBendTransformCreatorPlugin::do_get_descr() const
diff --git a/mia/3d/transform/rotbend.hh b/mia/3d/transform/rotbend.hh
index 40ec14a..1ac3c72 100644
--- a/mia/3d/transform/rotbend.hh
+++ b/mia/3d/transform/rotbend.hh
@@ -33,7 +33,7 @@ namespace mia_3dtransform_rotbend {
class EXPORT_3D C3DRotBendTransformation : public mia::C3DTransformation {
public:
- C3DRotBendTransformation(const mia::C3DBounds& size, const mia::C3DFVector& orig,
+ C3DRotBendTransformation(const mia::C3DBounds& size, const mia::C3DFVector& orig, bool norot,
const mia::C3DInterpolatorFactory& ipf);
mia::C3DFVector apply(const mia::C3DFVector& x) const;
@@ -92,17 +92,20 @@ private:
mia::C3DFVector m_relative_origin;
mia::C3DFVector m_rotation_center;
mia::C3DBounds m_size;
+ bool m_norot;
};
class C3DRotBendTransformCreator: public mia::C3DTransformCreator {
public:
C3DRotBendTransformCreator(const mia::C3DFVector& origin,
+ int norot,
const mia::C3DInterpolatorFactory& ipf);
private:
virtual mia::P3DTransformation do_create(const mia::C3DBounds& size,
const mia::C3DInterpolatorFactory& ipf) const;
mia::C3DFVector m_origin;
+ int m_norot;
};
class C3DRotBendTransformCreatorPlugin: public mia::C3DTransformCreatorPlugin {
@@ -112,6 +115,7 @@ public:
const std::string do_get_descr() const;
private:
mia::C3DFVector m_origin;
+ int m_norot;
};
diff --git a/mia/3d/transform/test_rotbend.cc b/mia/3d/transform/test_rotbend.cc
index 4ee2b05..45e1c6d 100644
--- a/mia/3d/transform/test_rotbend.cc
+++ b/mia/3d/transform/test_rotbend.cc
@@ -104,20 +104,20 @@ BOOST_FIXTURE_TEST_CASE( test_rotbend3d_rotation_x, Axis1Fixture )
BOOST_FIXTURE_TEST_CASE( test_rotbend3d_bend_left, Axis1Fixture )
{
check_transformed_is_expected(2, 2.0, m_origin + C3DFVector(1, 2, -0.2),
- m_origin + C3DFVector(1, 2, -0.2 + 2.0/(13*13+1) ));
+ m_origin + C3DFVector(1, 2, -0.2 + 8.0/(24*24+1) ));
}
BOOST_FIXTURE_TEST_CASE( test_rotbend3d__bend_right, Axis1Fixture )
{
- check_transformed_is_expected(3, 3.0, m_origin + C3DFVector(-3, 2, -0.2),
- m_origin + C3DFVector(-3, 2, -0.2 + 27.0 / (12*12+1)));
+ check_transformed_is_expected(3, 4.0, m_origin + C3DFVector(-3, -2, -0.2),
+ m_origin + C3DFVector(-3, -2, -0.2 + 16.0 / (23*23+1) ));
}
BOOST_FIXTURE_TEST_CASE( test_affine3d_iterator, ipfFixture )
{
C3DBounds size(10,20,15);
- C3DRotBendTransformation t1(size, C3DFVector(5,9.0f,7.5f), ipf);
+ C3DRotBendTransformation t1(size, C3DFVector(5,9.0f, 7.5f), false, ipf);
C3DRotBendTransformation::const_iterator ti = t1.begin();
for (size_t z = 0; z < size.z; ++z)
@@ -134,7 +134,7 @@ BOOST_FIXTURE_TEST_CASE( test_affine3d_ranged_iterator, ipfFixture)
C3DBounds size(10,20,30);
C3DBounds delta(1,2,3);
- C3DRotBendTransformation t1(size, C3DFVector(5,9.0f,15.5f), ipf);
+ C3DRotBendTransformation t1(size, C3DFVector(5,9.0f,15.5f), false, ipf);
auto ti = t1.begin_range(delta, size - delta);
for (size_t z = delta.z; z < size.z - delta.z; ++z)
@@ -149,7 +149,7 @@ BOOST_FIXTURE_TEST_CASE( test_affine3d_ranged_iterator, ipfFixture)
Axis1Fixture::Axis1Fixture():
m_origin(12,23,32),
m_size(25, 47, 70),
- m_transform(m_size, m_origin / C3DFVector(m_size), ipf)
+ m_transform(m_size, m_origin / C3DFVector(m_size), false, ipf)
{
}
diff --git a/mia/3d/vfiotest.cc b/mia/3d/vfiotest.cc
index ba18e62..9f3c648 100644
--- a/mia/3d/vfiotest.cc
+++ b/mia/3d/vfiotest.cc
@@ -30,9 +30,8 @@
#include <mia/3d/vfiotest.hh>
NS_MIA_BEGIN
-using namespace boost;
using namespace std;
-using namespace boost::unit_test;
+using boost::unit_test::test_suite;
const C3DFVector voxel(1.0, 2.0, 3.0);
diff --git a/mia/core/CMakeLists.txt b/mia/core/CMakeLists.txt
index 3c42ab2..0f947b4 100644
--- a/mia/core/CMakeLists.txt
+++ b/mia/core/CMakeLists.txt
@@ -69,6 +69,7 @@ SET(MIACORE_SRC_BASE
revision.cc
scaler1d.cc
seriesstats.cc
+ selftestcmdoption.cc
shape.cc
slopestatistics.cc
slopeclassifier.cc
@@ -155,6 +156,7 @@ SET(MIACORE_HEADER_BASE
scaler1d.hh
shape.hh shape.cxx
seriesstats.hh
+ selftestcmdoption.hh
singular_refobj.hh
slopestatistics.hh
slopeclassifier.hh
diff --git a/mia/core/attributes.hh b/mia/core/attributes.hh
index 22cb46e..99480d1 100644
--- a/mia/core/attributes.hh
+++ b/mia/core/attributes.hh
@@ -33,6 +33,7 @@
#include <stdexcept>
#include <boost/any.hpp>
#include <boost/ref.hpp>
+#include <boost/lexical_cast.hpp>
#include <mia/core/attributetype.hh>
NS_MIA_BEGIN
@@ -560,11 +561,12 @@ int TAttribute<T>::type_id() const
\remark this should replace the parameter translation methods
*/
+
template <typename T>
struct dispatch_attr_string {
static std::string val2string(const typename ::boost::reference_wrapper<T>::type value) {
std::stringstream sval;
- sval << value;
+ sval << boost::lexical_cast<std::string>(value);
return sval.str();
}
static T string2val(const std::string& str) {
@@ -582,7 +584,7 @@ struct dispatch_attr_string<std::vector<T> > {
std::stringstream sval;
sval << value.size();
for (size_t i = 0; i < value.size(); ++i)
- sval << " " << value[i];
+ sval << " " << boost::lexical_cast<std::string>(value[i]);
return sval.str();
}
static std::vector<T> string2val(const std::string& str) {
diff --git a/mia/core/cmdbooloption.cc b/mia/core/cmdbooloption.cc
index 3117072..2b511ed 100644
--- a/mia/core/cmdbooloption.cc
+++ b/mia/core/cmdbooloption.cc
@@ -18,17 +18,21 @@
*
*/
+#include <cassert>
#include <mia/core/typedescr.hh>
#include <mia/core/cmdbooloption.hh>
NS_MIA_BEGIN
-CCmdBoolOption::CCmdBoolOption(bool& value, char short_opt, const char *long_opt, const char *long_help):
- CCmdOption(short_opt, long_opt, long_help, long_opt, false),
+CCmdBoolOption::CCmdBoolOption(bool& value, char short_opt, const char *long_opt, const char *long_help,
+ CCmdOptionFlags flags):
+ CCmdOption(short_opt, long_opt, long_help, long_opt, flags),
m_value(value)
{
m_value = false;
+
+ assert(!has_flag(CCmdOptionFlags::required) && "A boolean flag option must not have the flag CCmdOptionFlags::required");
}
bool CCmdBoolOption::do_set_value(const char */*str_value*/)
diff --git a/mia/core/cmdbooloption.hh b/mia/core/cmdbooloption.hh
index ebc2d36..dc8f89a 100644
--- a/mia/core/cmdbooloption.hh
+++ b/mia/core/cmdbooloption.hh
@@ -43,8 +43,9 @@ class EXPORT_CORE CCmdBoolOption : public CCmdOption {
\param short_opt the one letter command line option
\param long_opt the long command line option
\param long_help the full help bool that describes the option completely
+ \param flags specific flags for the option. Note that passing CCmdOptionFlags::required doesn't make sense.
*/
- CCmdBoolOption(bool& value, char short_opt, const char *long_opt, const char *long_help);
+ CCmdBoolOption(bool& value, char short_opt, const char *long_opt, const char *long_help, CCmdOptionFlags flags);
private:
bool do_set_value(const char *str_value);
void do_write_value(std::ostream& os) const;
diff --git a/mia/core/cmdlineparser.cc b/mia/core/cmdlineparser.cc
index 138bd1f..452084c 100644
--- a/mia/core/cmdlineparser.cc
+++ b/mia/core/cmdlineparser.cc
@@ -89,6 +89,8 @@ struct CCmdOptionListData {
bool copyright;
vstream::Level verbose;
int max_threads;
+ bool m_selftest_run;
+ bool m_stdout_is_result;
CCmdOptionListData(const SProgramDescription& description);
@@ -125,6 +127,44 @@ struct CCmdOptionListData {
ostream *m_log;
};
+
+/**
+ This option is used to run a selftest.
+
+ A program can only have one selftest option and all other options that are not
+ in the Help & Info section are ignored when the selftest option is set.
+ The selftest is done within a class derived from the CSelftestOption::Callback
+ class that overrides the Callback::do_run() method.
+*/
+class EXPORT_CORE CSelftestOption: public CCmdOption {
+public:
+ /**
+ Test callback base class.
+
+ The tests to be run must be implemented in the "int do_run() const" method, and
+ it must return 0 if the test run successfull.
+ */
+
+
+
+private:
+ friend class CCmdOptionList;
+ /**
+ Constructor of the selftest function
+ */
+ CSelftestOption(bool& run, int& test_result, CSelftestCallback *callback);
+
+
+ virtual bool do_set_value(const char *str_value);
+ virtual void do_write_value(std::ostream& os) const;
+ virtual size_t do_get_needed_args() const;
+
+ std::unique_ptr<CSelftestCallback> m_callback;
+ int& m_test_result;
+ bool& m_run;
+
+};
+
void CCmdOptionListData::set_logstream(ostream& os)
{
m_log = &os;
@@ -169,6 +209,8 @@ CCmdOptionListData::CCmdOptionListData(const SProgramDescription& description):
#else
max_threads(tbb::task_scheduler_init::automatic),
#endif
+ m_selftest_run(false),
+ m_stdout_is_result(false),
m_log(&std::cout)
{
@@ -185,11 +227,11 @@ CCmdOptionListData::CCmdOptionListData(const SProgramDescription& description):
add(make_opt(verbose, g_verbose_dict, "verbose", 'V',
"verbosity of output, print messages of given level and higher priorities."
" Supported priorities starting at lowest level are:"));
- add(make_opt(copyright, "copyright", 0, "print copyright information"));
- add(make_opt(help, "help", 'h', "print this help"));
- add(make_opt(help_xml, "help-xml", 0, "print help formatted as XML"));
- add(make_opt(usage, "usage", '?', "print a short help"));
- add(make_opt(version, "version", 0, "print the version number and exit"));
+ add(make_opt(copyright, "copyright", 0, "print copyright information", CCmdOptionFlags::nonipype));
+ add(make_opt(help, "help", 'h', "print this help", CCmdOptionFlags::nonipype));
+ add(make_opt(help_xml, "help-xml", 0, "print help formatted as XML", CCmdOptionFlags::nonipype));
+ add(make_opt(usage, "usage", '?', "print a short help", CCmdOptionFlags::nonipype));
+ add(make_opt(version, "version", 0, "print the version number and exit", CCmdOptionFlags::nonipype));
set_current_group("Processing");
add(make_opt(max_threads, "threads", 0, "Maxiumum number of threads to use for processing,"
@@ -236,6 +278,7 @@ void CCmdOptionListData::add(const string& group, PCmdOption opt)
if (options.find(group) == options.end())
options[group] = vector<PCmdOption>();
options[group].push_back(opt);
+ opt->add_option(short_map, long_map);
}
CHistoryRecord CCmdOptionListData::get_values() const
@@ -277,7 +320,8 @@ void CCmdOptionListData::print_help_xml(const char *name_help, const CPluginHand
Element* nodeRoot = doc->create_root_node("program");
Element* program_name = nodeRoot->add_child("name");
program_name->set_child_text(name_help);
-
+ Element* version_string = nodeRoot->add_child("version");
+ version_string->set_child_text(get_revision());
Element* program_group = nodeRoot->add_child("section");
program_group->set_child_text(m_program_group);
Element* description = nodeRoot->add_child("description");
@@ -286,6 +330,7 @@ void CCmdOptionListData::print_help_xml(const char *name_help, const CPluginHand
Element* short_descr = nodeRoot->add_child("whatis");
short_descr->set_child_text(m_short_descr);
+
ostringstream usage_text;
usage_text << " " << name_help << " ";
@@ -319,6 +364,10 @@ void CCmdOptionListData::print_help_xml(const char *name_help, const CPluginHand
free_parameters->set_attribute("name", additional_help->get_descriptor());
free_parameters->set_attribute("type", "factory");
}
+
+ if (m_stdout_is_result) {
+ nodeRoot->add_child("stdout-is-result");
+ }
usage_text << "[options]";
if (additional_help)
@@ -506,7 +555,7 @@ void CCmdOptionListData::print_usage(const char *name) const
void CCmdOptionListData::print_version(const char *name_help) const
{
- *m_log << name_help << " revision:" << get_revision() << "\n\n";
+ *m_log << name_help << " version: " << get_revision() << "\n\n";
*m_log << g_basic_copyright1;
*m_log << get_author();
*m_log << g_basic_copyright2 << "\n";
@@ -527,6 +576,11 @@ void CCmdOptionList::add(const std::string& table, PCmdOption opt)
m_impl->add(table, opt);
}
+void CCmdOptionList::add_selftest(int& test_result, CSelftestCallback *callback)
+{
+ m_impl->add("Test", PCmdOption(new CSelftestOption(m_impl->m_selftest_run, test_result, callback)));
+}
+
void CCmdOptionList::set_group(const std::string& group)
{
m_impl->set_current_group(group);
@@ -624,6 +678,11 @@ CCmdOptionList::parse(size_t argc, char *args[], const string& additional_type,
return do_parse(argc, (const char **)args, true, additional_help);
}
+void CCmdOptionList::set_stdout_is_result()
+{
+ m_impl->m_stdout_is_result = true;
+}
+
struct TBBTaskScheduler {
static const tbb::task_scheduler_init& initialize(int max_threads);
};
@@ -720,6 +779,8 @@ CCmdOptionList::do_parse(size_t argc, const char *args[], bool has_additional,
} else if (m_impl->copyright) {
::print_full_copyright(name_help, m_impl->get_author());
return hr_copyright;
+ } else if (m_impl->m_selftest_run) {
+ return hr_selftest;
}
cverb.set_verbosity(m_impl->verbose);
@@ -776,42 +837,6 @@ CHistoryRecord CCmdOptionList::get_values() const
return m_impl->get_values();
}
-CHelpOption::CHelpOption(Callback *cb, char short_opt, const char *long_opt, const char *long_help):
- CCmdOption(short_opt, long_opt, long_help, NULL, CCmdOptionFlags::none),
- m_callback(cb)
-{
-}
-
-void CHelpOption::do_get_long_help_xml(std::ostream& os, xmlpp::Element& parent,
- HandlerHelpMap& /*handler_map*/) const
-{
- do_get_long_help(os);
- parent.set_attribute("type", "bool");
-}
-
-
-void CHelpOption::print(std::ostream& os) const
-{
- m_callback->print(os);
-}
-
-bool CHelpOption::do_set_value(const char */*str_value*/)
-{
- exit(0);
-}
-size_t CHelpOption::do_get_needed_args() const
-{
- return 0;
-}
-
-void CHelpOption::do_get_long_help(std::ostream& /*os*/) const
-{
-}
-
-void CHelpOption::do_write_value(std::ostream& /*os*/) const
-{
-}
-
CCmdFlagOption::CCmdFlagOption(int& val, const CFlagString& map, char short_opt,
const char *long_opt, const char *long_help,
const char *short_help,
@@ -849,72 +874,57 @@ size_t CCmdFlagOption::do_get_needed_args() const
return 1;
}
-PCmdOption EXPORT_CORE make_opt(int& value, const CFlagString& map, const char *long_opt,
- char short_opt,const char *long_help,
- const char *short_help, CCmdOptionFlags flags)
-{
- return PCmdOption(new CCmdFlagOption(value, map, short_opt, long_opt,
- long_help, short_help, flags ));
-}
-
-PCmdOption EXPORT_CORE make_help_opt(const char *long_opt, char short_opt,
- const char *long_help, CHelpOption::Callback *cb)
+CSelftestOption::CSelftestOption(bool& run, int& test_result, CSelftestCallback *callback):
+ CCmdOption(0, "selftest", "run a self test of the program", 0,
+ CCmdOptionFlags::nonipype),
+ m_callback(callback),
+ m_test_result(test_result),
+ m_run(run)
{
- return PCmdOption(new CHelpOption(cb, short_opt, long_opt, long_help));
+
}
-PCmdOption EXPORT_CORE make_opt(std::string& value, const char *long_opt, char short_opt, const char *long_help,
- CCmdOptionFlags flags, const CPluginHandlerBase *plugin_hint)
-{
- return PCmdOption(new CCmdStringOption(value, short_opt, long_opt, long_help,
- flags, plugin_hint));
-}
-PCmdOption EXPORT_CORE make_opt(bool& value, const char *long_opt, char short_opt, const char *help)
+bool CSelftestOption::do_set_value(const char * /* str_value */)
{
- return PCmdOption(new CCmdBoolOption(value, short_opt, long_opt, help ));
+ assert(m_callback);
+ m_test_result = m_callback->run();
+ m_run = true;
+ return true;
}
-
-//
-// Implementation of the standard option that holds a value
-//
-#if 0
-CBooleanCmdOption::CBooleanCmdOption(T& val, char short_opt, const char *long_opt, const char *long_help):
- CCmdOption(short_opt, long_opt, long_help, short_help, flags),
- m_value(val)
+void CSelftestOption::do_write_value(std::ostream& /* os */) const
{
- m_value = false;
}
-
-bool CBooleanCmdOption::do_set_value(const char *svalue)
+size_t CSelftestOption::do_get_needed_args() const
{
- m_value = true;
- return true;
+ return 0;
}
-
-size_t CBooleanCmdOption::do_get_needed_args() const
+PCmdOption EXPORT_CORE make_opt(int& value, const CFlagString& map, const char *long_opt,
+ char short_opt,const char *long_help,
+ const char *short_help, CCmdOptionFlags flags)
{
- return 0;
+ return PCmdOption(new CCmdFlagOption(value, map, short_opt, long_opt,
+ long_help, short_help, flags ));
}
-void CBooleanCmdOption::do_get_long_help(std::ostream& /*os*/) const
+PCmdOption EXPORT_CORE make_opt(std::string& value, const char *long_opt, char short_opt, const char *long_help,
+ CCmdOptionFlags flags, const CPluginHandlerBase *plugin_hint)
{
+ return PCmdOption(new CCmdStringOption(value, short_opt, long_opt, long_help,
+ flags, plugin_hint));
}
-
-void CBooleanCmdOption::do_write_value(std::ostream& /*os*/) const
+PCmdOption EXPORT_CORE make_opt(bool& value, const char *long_opt, char short_opt, const char *help,
+ CCmdOptionFlags flags)
{
+ return PCmdOption(new CCmdBoolOption(value, short_opt, long_opt, help, flags ));
}
-const std::string CBooleanCmdOption::do_get_value_as_string() const
-{
- return m_value ? "true" : "false";
-}
-#endif
+
NS_MIA_END
diff --git a/mia/core/cmdlineparser.hh b/mia/core/cmdlineparser.hh
index 773d5ef..acce537 100644
--- a/mia/core/cmdlineparser.hh
+++ b/mia/core/cmdlineparser.hh
@@ -30,12 +30,12 @@
#include <string>
#include <iterator>
#include <mia/core/cmdoption.hh>
-#include <mia/core/cmdoption.hh>
#include <mia/core/typedescr.hh>
#include <mia/core/paramoption.hh>
#include <mia/core/dictmap.hh>
#include <mia/core/flagstring.hh>
#include <mia/core/handlerbase.hh>
+#include <mia/core/selftestcmdoption.hh>
NS_MIA_BEGIN
@@ -159,68 +159,6 @@ private:
/**
\ingroup cmdline
- \brief A command line option that will appear in the help group
- and exits the program after printing the help.
-
- Option that will appear in the help group and setting it will
- always terminate the program after printing out the requested
- help.
- */
-class EXPORT_CORE CHelpOption: public CCmdOption {
-public:
-
- /**
- \ingroup cmdline
- \brief Interface for the callback to print the help assositated with the given option.
- */
- class Callback {
- public:
- /**
- Interface to print the help
- \param os output stream to print to
- */
- virtual void print(std::ostream& os) const = 0;
- };
-
- /** Constructor of the command option
- \param cb callback to call when help option is requested
- \param short_opt short option name (or 0)
- \param long_opt long option name (must not be NULL)
- \param long_help long help string (must not be NULL)
- */
- CHelpOption(Callback *cb, char short_opt, const char*long_opt, const char *long_help);
-
- /** Print the option to a stream
- @param os
- */
- void print(std::ostream& os) const;
-
-private:
- std::unique_ptr<Callback> m_callback;
- virtual bool do_set_value(const char *str_value);
- virtual size_t do_get_needed_args() const;
- virtual void do_write_value(std::ostream& os) const;
- virtual void do_get_long_help(std::ostream& os) const;
- virtual void do_get_long_help_xml(std::ostream& os, xmlpp::Element& parent,
- HandlerHelpMap& /*handler_map*/) const;
-
-};
-
-/**
- \ingroup cmdline
- \brief Help callback to print the help for the given plug-in
-
-*/
-template <typename PluginHandler>
-class TPluginHandlerHelpCallback: public CHelpOption::Callback {
- void print(std::ostream& os) const{
- PluginHandler::instance().print_help(os);
- }
-};
-
-
-/**
- \ingroup cmdline
\brief The class to hold the list of options
This class holds all the user defined and default command line option,
@@ -239,7 +177,8 @@ public:
hr_help_xml, /**< XML-formatted help has been requested */
hr_usage, /**< a short usage description has been requested */
hr_version, /**< The version information has been requested */
- hr_copyright /**< The long copyright information has been requested */
+ hr_copyright, /**< The long copyright information has been requested */
+ hr_selftest /**< The selftest was run */
};
/**
@@ -264,6 +203,17 @@ public:
*/
void add(const std::string& group, PCmdOption opt);
+ /**
+ Add a selftest option.
+
+ The selftest option runs the given self test and then exists. Additional parameters
+ given on the command line are ignored.
+ The option is set within the group \a Test and provides the long optionb name \a --selftest.
+ \param [out] test_result stores the result returned by running by running the test suite
+ \param callback the test functor that must have CSelftestCallback as a base class
+ */
+ void add_selftest(int& test_result, CSelftestCallback *callback);
+
/** the work routine, can take the arguemnts straight from \a main
This version parses the command line and allows for additional arguments that can be
read by get_remaining().
@@ -326,6 +276,11 @@ public:
\param os new output stream
*/
void set_logstream(std::ostream& os);
+
+
+ /** This function sets a flag that indicates that data written
+ to stdout is an actual result */
+ void set_stdout_is_result();
private:
EHelpRequested do_parse(size_t argc, const char *args[], bool has_additional,
const CPluginHandlerBase *additional_help)
@@ -659,11 +614,13 @@ PCmdOption make_opt(std::vector<T>& value, const char *long_opt, char short_opt,
\param long_opt long option name (must not be NULL)
\param short_opt short option name (or 0)
\param help help string (must not be NULL)
+ \param flags option flags
\returns the option warped into a \a boost::shared_ptr
*/
-PCmdOption make_opt(bool& value, const char *long_opt, char short_opt, const char *help);
+PCmdOption make_opt(bool& value, const char *long_opt, char short_opt, const char *help,
+ CCmdOptionFlags flags = CCmdOptionFlags::none);
/**
\ingroup cmdline
@@ -817,19 +774,6 @@ PCmdOption make_opt(typename std::unique_ptr<T>& value, const char *default_valu
}
-/**
- \ingroup cmdline
- \brief Create a command line help option
-
- Create a command line hoption that is used to print out some help.
- \param long_opt long option name
- \param short_opt short option char, set to 0 of none givn
- \param long_help the help string for thie option
- \param cb a call back that us used to write the help
-*/
-PCmdOption make_help_opt(const char *long_opt, char short_opt,
- const char *long_help, CHelpOption::Callback* cb);
-
NS_MIA_END
#endif
diff --git a/mia/core/cmdoption.cc b/mia/core/cmdoption.cc
index 005b727..5ae9bcf 100644
--- a/mia/core/cmdoption.cc
+++ b/mia/core/cmdoption.cc
@@ -32,21 +32,6 @@ using std::invalid_argument;
NS_MIA_BEGIN
CCmdOption::CCmdOption(char short_opt, const char *long_opt,
- const char *long_help, const char *short_help, bool required):
- m_short_opt(short_opt),
- m_long_opt(long_opt),
- m_long_help(long_help),
- m_short_help(short_help),
- m_flags(required ? CCmdOptionFlags::required : CCmdOptionFlags::none)
-{
- TRACE_FUNCTION;
- cvdebug() << "Create option '" << long_opt << "'\n";
- assert(long_opt);
- assert(long_help);
-
-}
-
-CCmdOption::CCmdOption(char short_opt, const char *long_opt,
const char *long_help, const char *short_help, CCmdOptionFlags flags):
m_short_opt(short_opt),
m_long_opt(long_opt),
@@ -238,7 +223,6 @@ void CCmdOption::add_option_xml(xmlpp::Element& parent, HandlerHelpMap& handler_
auto option = parent.add_child("option");
option->set_attribute("short", to_string<char>(get_short_option()));
option->set_attribute("long", get_long_option());
- option->set_attribute("required", to_string<bool>(is_required()));
option->set_attribute("default", get_value_as_string());
auto flagstring = get_flag_string();
@@ -258,6 +242,9 @@ string CCmdOption::get_flag_string()const
ss << "output ";
if (mia::has_flag(m_flags, CCmdOptionFlags::required))
ss << "required ";
+ if (mia::has_flag(m_flags, CCmdOptionFlags::nonipype))
+ ss << "nonipype ";
+
return ss.str();
}
diff --git a/mia/core/cmdoption.hh b/mia/core/cmdoption.hh
index b9adedd..93ad177 100644
--- a/mia/core/cmdoption.hh
+++ b/mia/core/cmdoption.hh
@@ -56,12 +56,9 @@ public:
\param long_opt the long option name
\param long_help a long help string
\param short_help help to print out when only usage information is requested
- \param required set to true if the option must be set by the user
+ \param flags add certain \a CCmdOptionFlags to the option
*/
CCmdOption(char short_opt, const char *long_opt, const char *long_help,
- const char *short_help, bool required)__attribute__((deprecated));
-
- CCmdOption(char short_opt, const char *long_opt, const char *long_help,
const char *short_help, CCmdOptionFlags flags);
diff --git a/mia/core/cmdoptionflags.hh b/mia/core/cmdoptionflags.hh
index 3c615c2..327a5c9 100644
--- a/mia/core/cmdoptionflags.hh
+++ b/mia/core/cmdoptionflags.hh
@@ -27,12 +27,13 @@ NS_MIA_BEGIN
enum class CCmdOptionFlags : int {
none = 0,
- required = 1,
- input = 2,
+ required = 1,
+ input = 2,
output = 4,
required_input = 3,
required_output = 5,
- validate = 8
+ validate = 8,
+ nonipype = 16
};
inline CCmdOptionFlags operator | (CCmdOptionFlags lhs, CCmdOptionFlags rhs)
@@ -66,7 +67,7 @@ inline std::ostream& operator << (std::ostream& os, CCmdOptionFlags flags)
case CCmdOptionFlags::required_input: os << "CCmdOptionFlags::required_input"; break;
case CCmdOptionFlags::required_output: os << "CCmdOptionFlags::required_output"; break;
case CCmdOptionFlags::validate: os << "CCmdOptionFlags::validate"; break;
-
+ case CCmdOptionFlags::nonipype: os << "CCmdOptionFlags::nonipype"; break;
default: os << "CCmdOptionFlags::<undefined>";
};
return os;
diff --git a/mia/core/handler.hh b/mia/core/handler.hh
index 8468c97..273bab2 100644
--- a/mia/core/handler.hh
+++ b/mia/core/handler.hh
@@ -86,6 +86,12 @@ public:
/// \returns the behind-end iterator to the plug-ins
const_iterator end()const;
+ /**
+ Add a given plug-in to the handler. The pointer must not be freed in client code.
+ @param plugin
+ */
+ void add_plugin(Interface *plugin);
+
protected:
//! \name Constructors
//@{
@@ -105,12 +111,6 @@ protected:
typename TPluginHandler<I>::Interface *plugin(const char *plugin) const;
- /**
- Add a given plug-in to the handler
- @param plugin
- */
- void add_plugin(Interface *plugin);
-
void initialise(CPathNameArray searchpath);
private:
diff --git a/mia/core/minimizer/gdas.cc b/mia/core/minimizer/gdas.cc
index e53814c..e0ab822 100644
--- a/mia/core/minimizer/gdas.cc
+++ b/mia/core/minimizer/gdas.cc
@@ -95,7 +95,7 @@ int CGDSAMinimizer::do_run(CDoubleVector& x)
tries = 0;
copy(xwork.begin(), xwork.end(), x.begin());
- if ( (f < 0.5 * f_old) && (step > m_max_step)) {
+ if ( (f < 0.5 * f_old) && (step < m_max_step)) {
step *= 1.5;
if (step > m_max_step)
step = m_max_step;
@@ -114,8 +114,11 @@ int CGDSAMinimizer::do_run(CDoubleVector& x)
<< ", gmax = " << gmax << ", step=" << step << "\n";
if (step > m_min_step) {
- // restore last solution
- copy(x.begin(), x.end(), xwork.begin());
+
+ // restore last solution if current value larger
+ if (f > f_old)
+ copy(x.begin(), x.end(), xwork.begin());
+
step /= 2.0;
if (step < m_min_step)
step = m_min_step;
diff --git a/mia/core/parameter.cc b/mia/core/parameter.cc
index 0df6019..a02794f 100644
--- a/mia/core/parameter.cc
+++ b/mia/core/parameter.cc
@@ -55,12 +55,14 @@ void CParameter::get_help_xml(xmlpp::Element& param) const
{
TRACE_FUNCTION;
param.set_attribute("type", m_type);
- param.set_attribute("required", to_string<bool>(m_is_required));
param.set_attribute("default", get_default_value());
ostringstream d;
-// descr(d);
param.set_child_text(m_descr);
do_get_help_xml(param);
+ if (m_is_required) {
+ auto flags = param.add_child("flags");
+ flags->set_child_text("required");
+ }
}
void CParameter::do_get_help_xml(xmlpp::Element& /*param*/) const
diff --git a/mia/2d/test_combiner.cc b/mia/core/selftestcmdoption.cc
similarity index 55%
copy from mia/2d/test_combiner.cc
copy to mia/core/selftestcmdoption.cc
index ebf7895..890c199 100644
--- a/mia/2d/test_combiner.cc
+++ b/mia/core/selftestcmdoption.cc
@@ -18,26 +18,23 @@
*
*/
-#include <stdexcept>
-#include <climits>
+#include <cassert>
+#include <mia/core/selftestcmdoption.hh>
+#include <mia/core/plugin_base.hh>
-#include <mia/internal/autotest.hh>
-#include <boost/filesystem/path.hpp>
-#include <mia/2d/filter.hh>
+NS_MIA_BEGIN
+CSelftestCallback::CSelftestCallback(int argc, char **argv):
+ m_argc(argc), m_argv(argv)
+{
+}
+
+int CSelftestCallback::run () const
+{
+ PrepareTestPluginPath prepare_plugin_path;
+ return do_run(m_argc, m_argv);
+}
-NS_MIA_USE
-using namespace boost;
-using namespace std;
-namespace bfs=boost::filesystem;
-BOOST_AUTO_TEST_CASE( test_load_plugins )
-{
- CPathNameArray plugpath;
- plugpath.push_back(bfs::path("combiner"));
- C2DImageCombinerPluginHandler::set_search_path(plugpath);
- const C2DImageCombinerPluginHandler::Instance& handler = C2DImageCombinerPluginHandler::instance();
- BOOST_CHECK_EQUAL(handler.size(), 5u);
- BOOST_CHECK_EQUAL(handler.get_plugin_names(), "absdiff add div mul sub ");
-}
+NS_MIA_END
diff --git a/mia/core/selftestcmdoption.hh b/mia/core/selftestcmdoption.hh
new file mode 100644
index 0000000..c9ddaec
--- /dev/null
+++ b/mia/core/selftestcmdoption.hh
@@ -0,0 +1,89 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef mia_core_selftestcmdoption_hh
+#define mia_core_selftestcmdoption_hh
+
+#include <mia/core/cmdoption.hh>
+#include <memory>
+
+NS_MIA_BEGIN
+
+/**
+ The base class for the selftest callback.
+
+ The self test class provides the interface to add a selftest option
+ that invokes the tests for normal programs.
+
+ For a working implementation the abstract method
+
+ int do_run(int argc, char **argv) const;
+
+ must be overridden. It must return zero if the tests pass and non-zero if they don't.
+*/
+struct EXPORT_CORE CSelftestCallback {
+ /**
+ Constructor of the callback function. Usually you can just inherit it
+ by the C++11 "using Callback::Callback" directive.
+
+ \param argc number of following arguments
+ \param argv an array of string arguments
+ */
+ CSelftestCallback(int argc, char **argv);
+
+ private:
+ friend class CSelftestOption;
+
+ /** runs the test suite
+ \returns 0 if all tests were successfull and non-zero otherwise
+ */
+ int run() const;
+
+ /**
+ Interface for the callback function to be overridden.
+ */
+ virtual int do_run(int argc, char **argv) const = 0;
+
+ int m_argc;
+ char **m_argv;
+};
+
+/**
+ This define creates an derived selftest class that runs a BOOST test suite.
+ As usual, the boost tests have to be defined by using BOOST_*_TEST_CASE.
+
+ In order to use this test case an instance of this class created with \a new
+ must be passed to the command line parser by using the add_selftest method.
+ \param NAME name of the selftest class.
+
+ */
+#define SELFTEST_CALLBACK(NAME) class NAME: public CSelftestCallback { \
+ public: \
+ using CSelftestCallback::CSelftestCallback; \
+ \
+ private: \
+ int do_run(int argc, char **argv)const { \
+ return ::boost::unit_test::unit_test_main( &init_unit_test, argc, argv); \
+ } \
+}
+
+NS_MIA_END
+
+#endif
diff --git a/mia/core/statistics.hh b/mia/core/statistics.hh
index 96ac893..89987f7 100644
--- a/mia/core/statistics.hh
+++ b/mia/core/statistics.hh
@@ -110,7 +110,7 @@ FMedianMAD::result_type FMedianMAD::operator()( const T& data) const
result.first = median(buffer);
transform(buffer.begin(), buffer.end(), buffer.begin(),
- [&result](double x) {return abs(x - result.first);});
+ [&result](double x) {return fabs(x - result.first);});
result.second = median(buffer);
return result;
}
diff --git a/mia/core/test_attributes.cc b/mia/core/test_attributes.cc
index 905496e..006bc68 100644
--- a/mia/core/test_attributes.cc
+++ b/mia/core/test_attributes.cc
@@ -120,8 +120,8 @@ BOOST_AUTO_TEST_CASE( test_translator )
check_translate_type("bit", true, "1");
- check_translate_type("double", 1.9, "1.9");
- check_translate_type("float", 1.7f, "1.7");
+ check_translate_type("double", 1.8, "1.8");
+ check_translate_type("float", 1.75f, "1.75");
check_translate_type("ubyte", (unsigned char)129, "129");
check_translate_type("sbyte", (signed char)-120, "-120");
check_translate_type("sshort", (signed short)-1231, "-1231");
diff --git a/miacore.pc.cmake b/miacore.pc.cmake
index d2c9fda..050befb 100644
--- a/miacore.pc.cmake
+++ b/miacore.pc.cmake
@@ -8,10 +8,13 @@ includedir=${prefix}/@INCLUDE_INSTALL_PATH@
pluginroot=@PLUGIN_SEARCH_PATH@
TestLibs=
+doctools=@MIA_DOCTOOLS_INSTALL_ROOT@
+
Name: miacore
Description: A library for 2D/3D grayscale image processing
Version: @PACKAGE_VERSION@
Conflicts:
+Requires: libxml++-2.6
Requires.private: @PKG_CONFIG_DEPS@
Libs: -lmiacore- at VERSION@ -L${prefix}/@LIBRARY_INSTALL_PATH@ -lboost_system
Cflags: -I${prefix}/@INCLUDE_INSTALL_PATH@ -I at LIB_INCLUDE_INSTALL_PATH@
diff --git a/src/2davgmasked.cc b/src/2davgmasked.cc
index 3c3bcad..c91aa1e 100644
--- a/src/2davgmasked.cc
+++ b/src/2davgmasked.cc
@@ -104,7 +104,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &image2dio));
options.add(make_opt( mask_filename, "mask-file", 'm', "mask image, must be of type byte",
CCmdOptionFlags::required_input, &image2dio));
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv, "image") != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dcost.cc b/src/2dcost.cc
index fa92a10..e00830b 100644
--- a/src/2dcost.cc
+++ b/src/2dcost.cc
@@ -45,11 +45,13 @@ int do_main(int argc, char **argv)
{
CCmdOptionList options(g_description);
-
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv, "cost", &C2DFullCostPluginHandler::instance()) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
+
auto cost_chain = options.get_remaining();
if (cost_chain.empty()) {
diff --git a/src/2ddistance.cc b/src/2ddistance.cc
index e81f755..db67d4a 100644
--- a/src/2ddistance.cc
+++ b/src/2ddistance.cc
@@ -52,6 +52,7 @@ const SProgramDescription g_general_help = {
enum EOps {dist_avg,
dist_max,
+ dist_raw,
dist_unknown
};
@@ -59,6 +60,7 @@ enum EOps {dist_avg,
const TDictMap<EOps>::Table combine_option_table[] = {
{"avg", dist_avg, "use average"},
{"max", dist_max, "use maximum" },
+ {"raw", dist_raw, "collect raw values as vector" },
{NULL, dist_unknown, ""},
};
@@ -71,14 +73,14 @@ class Convert2DoubleAndScale: public TFilter<C2DDImage>{
C2DDImage operator ()(const T2DImage<T>& image) const {
C2DDImage result(image.get_size());
transform(image.begin(), image.end(), result.begin(),
- [this](T x){return x/_M_scale;});
+ [this](T x){return x * _M_scale;});
return result;
}
private:
double _M_scale;
};
-class CGetDistance: public TFilter<double> {
+class CGetDistance: public TFilter<vector<double>> {
public:
CGetDistance(const C2DDImage& dist_field, EOps method):
_M_distance(dist_field),
@@ -93,6 +95,7 @@ public:
auto d = _M_distance.begin();
auto i = image.begin();
auto e = image.end();
+ vector<double> vresult;
switch (_M_method) {
case dist_avg: {
@@ -106,7 +109,8 @@ public:
++d;
++i;
}
- return n == 0 ? 0 : result / n;
+ vresult.push_back(n == 0 ? 0 : result / n);
+ return vresult;
}
case dist_max: {
double result = 0.0;
@@ -117,7 +121,17 @@ public:
++d;
++i;
}
- return result;
+ vresult.push_back(result);
+ return vresult;
+ }
+ case dist_raw: {
+ while (i != e) {
+ if (*i)
+ vresult.push_back(*d);
+ ++d;
+ ++i;
+ }
+ return vresult;
}
default:
throw runtime_error("unknown distance measure requested\n");
@@ -133,6 +147,7 @@ int do_main( int argc, char *argv[] )
string in_filename;
string dist_filename;
+ string out_filename("-");
float scale = 1.0;
EOps method = dist_avg;
@@ -144,7 +159,9 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_filename, "in-file", 'i', "input image",
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( dist_filename, "distance-file", 'd', "distance field image (floating point)",
- CCmdOptionFlags::required_output, &imageio));
+ CCmdOptionFlags::required_input, &imageio));
+ options.add(make_opt(out_filename, "out-file", 'o', "output file, '-': write to stdout", CCmdOptionFlags::required_output));
+
options.add(make_opt( scale, "scale", 's', "distance scaling factor"));
options.add(make_opt( method, combine_option, "method", 'm', "distance measuring method"));
@@ -160,7 +177,15 @@ int do_main( int argc, char *argv[] )
C2DDImage dist = mia::filter(create_dist, *dist_image);
CGetDistance get_distance(dist, method);
- cout << filter(get_distance, *in_image) <<"\n";
+ auto result = filter(get_distance, *in_image);
+ if (out_filename == "-")
+ cout << result <<"\n";
+ else {
+ ofstream out(out_filename.c_str());
+ out << result;
+ if (!out.good())
+ create_exception<runtime_error>("Error writing result to '", out_filename, "'");
+ }
return EXIT_SUCCESS;
}
diff --git a/src/2dgrayimage-combine-to-rgb.cc b/src/2dgrayimage-combine-to-rgb.cc
index 3498ca9..ca75501 100644
--- a/src/2dgrayimage-combine-to-rgb.cc
+++ b/src/2dgrayimage-combine-to-rgb.cc
@@ -94,7 +94,7 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( red_filename, "red", 'r', "input image for red channel",
CCmdOptionFlags::input, &imageio));
- options.add(make_opt( out_filename, "out-file", 'o', "combined output image", CCmdOptionFlags::required_input, &imageio));
+ options.add(make_opt( out_filename, "out-file", 'o', "combined output image", CCmdOptionFlags::required_output, &imageio));
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dimagecombine-dice.cc b/src/2dimagecombine-dice.cc
index fd36e58..d077581 100644
--- a/src/2dimagecombine-dice.cc
+++ b/src/2dimagecombine-dice.cc
@@ -92,7 +92,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( in_filename2, "in-file-2", '2', "input image 2",
CCmdOptionFlags::required_input, &imageio));
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dimagefilter.cc b/src/2dimagefilter.cc
index 847e884..e8d75ef 100644
--- a/src/2dimagefilter.cc
+++ b/src/2dimagefilter.cc
@@ -54,10 +54,6 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( out_filename, "out-file", 'o', "output image(s) that have been filtered",
CCmdOptionFlags::required_output, &imageio));
- options.set_group(g_help_optiongroup);
- options.add(make_help_opt( "help-filters", 0,
- "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<C2DFilterPluginHandler>));
if (options.parse(argc, argv, "filter", &filter_plugins) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dimagefilterstack.cc b/src/2dimagefilterstack.cc
index 4d0ea07..5a4eb56 100644
--- a/src/2dimagefilterstack.cc
+++ b/src/2dimagefilterstack.cc
@@ -83,12 +83,6 @@ int do_main( int argc, char *argv[] )
options.add(make_opt(startid, "start", 's', "first possible number of file number range to be filtered"));
options.add(make_opt(endid, "end", 'e', "last possible number of file number range to be filtered"));
-
- options.set_group(g_help_optiongroup);
- options.add(make_help_opt( "help-filters", 0,
- "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<C2DFilterPluginHandler>));
-
if (options.parse(argc, argv, "filter", &filter_plugins) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dimagefullstats.cc b/src/2dimagefullstats.cc
index 35aceb3..f5c703f 100644
--- a/src/2dimagefullstats.cc
+++ b/src/2dimagefullstats.cc
@@ -52,6 +52,7 @@ int do_main( int argc, char *argv[] )
string in_filename;
CCmdOptionList options(g_general_help);
+ options.set_stdout_is_result();
options.add(make_opt( in_filename, "in-file", 'i', "input image",
CCmdOptionFlags::required_input, &C2DImageIOPluginHandler::instance()));
diff --git a/src/2dimageregistration.cc b/src/2dimageregistration.cc
index a4eb449..e81d13d 100644
--- a/src/2dimageregistration.cc
+++ b/src/2dimageregistration.cc
@@ -56,10 +56,10 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_general_help);
options.set_group("File-IO");
- options.add(make_opt( src_filename, "in", 'i', "test image", CCmdOptionFlags::required_input, &imageio));
- options.add(make_opt( ref_filename, "ref", 'r', "reference image", CCmdOptionFlags::required_input, &imageio));
- options.add(make_opt( out_filename, "out", 'o', "registered output image", CCmdOptionFlags::output, &imageio));
- options.add(make_opt( trans_filename, "trans", 't', "output transformation",
+ options.add(make_opt( src_filename, "in-image", 'i', "test image to be registered", CCmdOptionFlags::required_input, &imageio));
+ options.add(make_opt( ref_filename, "ref-image", 'r', "reference image to be registered to", CCmdOptionFlags::required_input, &imageio));
+ options.add(make_opt( out_filename, "out-image", 'o', "registered output image", CCmdOptionFlags::output, &imageio));
+ options.add(make_opt( trans_filename, "transformation", 't', "output transformation comprising the registration",
CCmdOptionFlags::required_output, &C2DTransformationIOPluginHandler::instance()));
options.set_group("Parameters");
diff --git a/src/2dimagestats.cc b/src/2dimagestats.cc
index fad4618..1decee1 100644
--- a/src/2dimagestats.cc
+++ b/src/2dimagestats.cc
@@ -104,6 +104,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( thresh, "thresh", 't', "intensity thresh to ignore"));
options.add(make_opt( high_thresh, "high-thresh", 'g', "upper histogram percentage to ignore"));
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dlerp.cc b/src/2dlerp.cc
index e16cf62..8df5d50 100644
--- a/src/2dlerp.cc
+++ b/src/2dlerp.cc
@@ -19,6 +19,10 @@
*/
#include <climits>
+
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_NO_MAIN
+
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
@@ -39,7 +43,9 @@ const SProgramDescription g_description = {
{pdi_short, "Linearly combine two 2D images."},
{pdi_description, "Merge two images by pixel-wise linearly combining their intensities."},
{pdi_example_descr, "Combine image inputA.v and inputB.v by using position coordinates "
- "4, 7, and 9 and write the result to output.v"},
+ "4, 7, and 9. This means the output pixel values will be evaluated according to\n\n"
+ " (9-7)/(9-4) * A + (7-4)/(9-4) * B \n\n"
+ "The result image will be written to output.v"},
{pdi_example_code, "-1 inputA.v -2 inputB.v -p 4,7,9 -o output.v"}
};
@@ -79,8 +85,9 @@ private:
float m_w;
};
-static void run_self_test()
+BOOST_AUTO_TEST_CASE ( run_self_test )
{
+
const C2DBounds size(1,2);
C2DFImage *A = new C2DFImage(size);
@@ -105,12 +112,8 @@ static void run_self_test()
}
-static bool init_unit_test_suite( )
-{
- ::boost::unit_test::framework::master_test_suite().add( BOOST_TEST_CASE( &run_self_test));
- return true;
-}
+
template <typename F>
struct FFilter {
FFilter(const F& f):
@@ -125,6 +128,8 @@ private:
const F& m_f;
};
+SELFTEST_CALLBACK(CSelftest);
+
int do_main(int argc, char **argv)
{
@@ -132,7 +137,7 @@ int do_main(int argc, char **argv)
string src1_filename;
string src2_filename;
string out_filename;
- bool self_test = false;
+ int self_test_result = 0;
vector<float> positions;
@@ -147,15 +152,17 @@ int do_main(int argc, char **argv)
options.add(make_opt( positions, "positions", 'p',
"image series positions (first, target, second)",
CCmdOptionFlags::required));
- options.add(make_opt( self_test, "self-test", 0, "run a self test of the tool"));
+ options.add_selftest(self_test_result, new CSelftest(argc, argv));
- if (options.parse(argc, argv) != CCmdOptionList::hr_no)
+ switch (options.parse(argc, argv, "boost-test-options")) {
+ case CCmdOptionList::hr_no:
+ break;
+ case CCmdOptionList::hr_selftest:
+ return self_test_result;
+ default:
return EXIT_SUCCESS;
-
- if (self_test) {
- return ::boost::unit_test::unit_test_main( &init_unit_test_suite, argc, (char **)argv );
}
-
+
if (positions.size() != 3) {
stringstream msg;
msg << "positions must be 3 values: first, target, second, got " << positions.size() << "images";
diff --git a/src/2dmany2one-nonrigid.cc b/src/2dmany2one-nonrigid.cc
index 45dc3db..52e0465 100644
--- a/src/2dmany2one-nonrigid.cc
+++ b/src/2dmany2one-nonrigid.cc
@@ -142,7 +142,7 @@ int do_main( int argc, char *argv[] )
"input perfusion data set", CCmdOptionFlags::required_input));
options.add(make_opt( registered_filebase, "out-file", 'o',
"file name for registered images, numbering and pattern are deducted from the input data",
- CCmdOptionFlags::required));
+ CCmdOptionFlags::required_output));
options.set_group("\nRegistration");
options.add(make_opt( minimizer, "optimizer", 'O', "Optimizer used for minimization"));
diff --git a/src/2dmulti-force.cc b/src/2dmulti-force.cc
index a3f6c4b..bf82ac8 100644
--- a/src/2dmulti-force.cc
+++ b/src/2dmulti-force.cc
@@ -24,6 +24,7 @@
#include <sstream>
#include <iomanip>
#include <boost/algorithm/minmax_element.hpp>
+#include <mia/2d/transformfactory.hh>
NS_MIA_USE
using namespace boost;
@@ -37,10 +38,11 @@ const SProgramDescription g_description = {
"The input images must be of the same dimensions and gray scale (whatever bit-depth)."},
{pdi_example_descr, "Evaluate the force normimage weighted sum of costs SSD and NGF of "
"image1.v and image2.v. and store the result to force.v."},
- {pdi_example_code, "-o force.v ssd:src=image1.v,ref=image2.v,weight=0.1 "
- "ngf:src=image1.v,ref=image2.v,weight=2.0"}
+ {pdi_example_code, "-o force.v image:cost=ssd,src=image1.v,ref=image2.v,weight=0.1 "
+ "image:cost=ngf,src=image1.v,ref=image2.v,weight=2.0"}
};
+
struct FGetNorm {
float operator ()(const C2DFVector& x) const {
return x.norm();
@@ -58,7 +60,7 @@ int do_main(int argc, char **argv)
const auto& imageio = C2DImageIOPluginHandler::instance();
const auto& costcreator = C2DFullCostPluginHandler::instance();
- options.add(make_opt( out_filename, "out-file", 'o', "output norm image", CCmdOptionFlags::required_input, &imageio));
+ options.add(make_opt( out_filename, "out-file", 'o', "output norm image", CCmdOptionFlags::required_output, &imageio));
if (options.parse(argc, argv, "cost", &costcreator) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
@@ -71,23 +73,40 @@ int do_main(int argc, char **argv)
return EXIT_FAILURE;
}
- C2DImageFatCostList cost_list;
+
+ C2DFullCostList cost_list;
for(auto i = cost_chain.begin(); i != cost_chain.end(); ++i) {
- P2DImageFatCost c = costcreator.produce(*i);
+ auto c = costcreator.produce(*i);
assert(c);
- cost_list.push_back(c);
+ cost_list.push(c);
}
- C2DFVectorfield force(cost_list.get_size());
-
+ cost_list.reinit();
+ C2DBounds size;
+ if (!cost_list.get_full_size(size)) {
+ throw invalid_argument("Input images given for the cost functions are no of the same size");
+ }
+ cost_list.set_size(size);
+
if ( out_filename.empty()) {
- cout << cost_list.value() << endl;
+ cout << cost_list.cost_value() << endl;
return EXIT_SUCCESS;
}
-
- C2DFImage *result = new C2DFImage(force.get_size());
-
- transform(force.begin(), force.end(), result->begin(), FGetNorm());
+
+ auto tff = C2DTransformCreatorHandler::instance().produce("vf:imgkernel=[bspline:d=0],imgboundary=zero");
+ auto t = tff->create(size);
+ auto params = t->get_parameters();
+ std::fill(params.begin(), params.end(), 0.0);
+ t->set_parameters(params);
+
+ double cost_value = cost_list.evaluate(*t, params);
+
+ C2DFImage *result = new C2DFImage(size);
+ int i = 0;
+
+ for (auto ir = result->begin(); ir != result->end(); ++ir, i+=2){
+ *ir = sqrt(params[i] * params[i] + params[i+1] * params[i+1]);
+ }
P2DImage norm_img(result);
@@ -97,11 +116,7 @@ int do_main(int argc, char **argv)
if (pts.find(it_float) == pts.end())
norm_img = C2DFilterPluginHandler::instance().produce("convert")->filter(*norm_img);
- C2DImageIOPluginHandler::Instance::Data images;
- images.push_back(norm_img);
-
-
- if ( !imageio.save(out_filename, images) )
+ if ( !save_image(out_filename, norm_img) )
throw runtime_error(string("unable to save to: ") + out_filename);
return EXIT_SUCCESS;
diff --git a/src/2dmultiimageregistration.cc b/src/2dmultiimageregistration.cc
new file mode 100644
index 0000000..ac1258a
--- /dev/null
+++ b/src/2dmultiimageregistration.cc
@@ -0,0 +1,92 @@
+/* -*- mia-c++ -*-
+ *
+ * This file is part of MIA - a toolbox for medical image analysis
+ * Copyright (c) Leipzig, Madrid 1999-2014 Gert Wollny
+ *
+ * MIA is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with MIA; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <sstream>
+#include <mia/core.hh>
+#include <mia/2d.hh>
+#include <mia/2d/nonrigidregister.hh>
+#include <mia/core/minimizer.hh>
+#include <mia/2d/transformfactory.hh>
+#include <mia/2d/transformio.hh>
+
+NS_MIA_USE;
+using namespace std;
+
+const SProgramDescription g_description = {
+ {pdi_group, "Registration, Comparison, and Transformation of 2D images"},
+
+ {pdi_short, "Non-linear registration of 2D images."},
+
+ {pdi_description, "This program runs a non-rigid registration based on the given cost criteria "
+ "and a given transformation model. Other than mia-2dnonrigidreg it doesn't support "
+ "specific command line parameters to provide the images. Instead the images are specified "
+ "dirctly when defining the cost function. Hence, image registrations can be executed that "
+ "optimize the aligmnet of more than one image pair at the same time. Note, however, that "
+ "all input images must be of the same dimension (in pixels)"},
+
+ {pdi_example_descr,
+ "Register image test.v to image ref.v by using a spline transformation with a "
+ "coefficient rate of 5 and write the registered image to reg.v. "
+ "Use two multiresolution levels, ssd as image cost function and divcurl weighted by 10.0 "
+ "as transformation smoothness penalty. The resulting transformation is saved in reg.vf."},
+
+ {pdi_example_code, "-o reg.vf -l 2 -f spline:rate=3,penalty=divcurl image:cost=ssd,src=test.v,ref=ref.v"}
+};
+
+
+int do_main( int argc, char *argv[] )
+{
+ string trans_filename;
+ size_t mg_levels = 3;
+ PMinimizer minimizer;
+ P2DTransformationFactory transform_creator;
+
+ const auto& transform2dio = C2DTransformationIOPluginHandler::instance();
+
+ CCmdOptionList options(g_description);
+ options.add(make_opt( trans_filename, "out-transform", 'o', "output transformation",
+ CCmdOptionFlags::required_output, &transform2dio));
+ options.add(make_opt( mg_levels, "levels", 'l', "multi-resolution levels"));
+ options.add(make_opt( minimizer, "gsl:opt=gd,step=0.1", "optimizer", 'O', "Optimizer used for minimization"));
+ options.add(make_opt( transform_creator, "spline:rate=10,penalty=divcurl", "transForm", 'f', "transformation type"));
+
+ if (options.parse(argc, argv, "cost", &C2DFullCostPluginHandler::instance()) != CCmdOptionList::hr_no)
+ return EXIT_SUCCESS;
+
+
+ auto cost_descrs = options.get_remaining();
+
+ C2DFullCostList costs;
+ for (auto i = cost_descrs.begin(); i != cost_descrs.end(); ++i)
+ costs.push(C2DFullCostPluginHandler::instance().produce(*i));
+
+
+ C2DNonrigidRegister nrr(costs, minimizer, transform_creator, mg_levels);
+ P2DTransformation transform = nrr.run();
+
+ if (! transform2dio.save(trans_filename, *transform) )
+ throw create_exception<runtime_error>("Unable to save obtained transformation to '", trans_filename, "'");
+ return EXIT_SUCCESS;
+}
+
+
+
+#include <mia/internal/main.hh>
+MIA_MAIN(do_main)
diff --git a/src/2dmyocard-ica.cc b/src/2dmyocard-ica.cc
index 94243fe..ab11e91 100644
--- a/src/2dmyocard-ica.cc
+++ b/src/2dmyocard-ica.cc
@@ -366,7 +366,8 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( src_name, "in-base", 'i', "input file name ofolloing pattern nameXXXX.ext X=numbers" ,
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( coefs_name, "coefs", 0, "output mixing coefficients to this file"));
- options.add(make_opt( out_name, "out-base", 'o', "output file name base"));
+ options.add(make_opt( out_name, "out-base", 'o', "output file name base",
+ CCmdOptionFlags::output));
options.add(make_opt( out_type, imageio.get_supported_suffix_set(), "type", 't',
"output file type"));
diff --git a/src/2dmyocard-icaseries.cc b/src/2dmyocard-icaseries.cc
index 4d5e349..d5aa747 100644
--- a/src/2dmyocard-icaseries.cc
+++ b/src/2dmyocard-icaseries.cc
@@ -89,12 +89,12 @@ int do_main( int argc, char *argv[] )
options.set_group("File-IO");
options.add(make_opt( in_filename, "in-file", 'i', "input perfusion data set", CCmdOptionFlags::required_input));
options.add(make_opt( reference_filename, "references", 'r', "File name base for the reference images. "
- "Image type and numbering scheme are taken from the input images."));
+ "Image type and numbering scheme are taken from the input images.", CCmdOptionFlags::output));
options.add(make_opt( cropped_filename, "save-cropped", 'c', "save cropped set of the original set to this file, "
- "the image files will use the stem of the name as file name base"));
+ "the image files will use the stem of the name as file name base", CCmdOptionFlags::output));
options.add(make_opt( save_crop_feature, "save-feature", 0, "save the features images resulting from the ICA and "
"some intermediate images used for the RV-LV segmentation with the given file name base to PNG files. "
- "Also save the coefficients of the initial best and the final IC mixing matrix."));
+ "Also save the coefficients of the initial best and the final IC mixing matrix.", CCmdOptionFlags::output));
options.set_group("ICA");
options.add(make_opt( components, "components", 'C', "ICA components 0 = automatic estimation"));
diff --git a/src/2dmyoseries-compdice.cc b/src/2dmyoseries-compdice.cc
index 056d494..7afa835 100644
--- a/src/2dmyoseries-compdice.cc
+++ b/src/2dmyoseries-compdice.cc
@@ -75,6 +75,7 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( org_filename, "first", '1', "first segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( ref_filename, "second", '2', "second segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( skip, "skip", 'k', "images to skip atthe begin of the series"));
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dmyoseries-dice.cc b/src/2dmyoseries-dice.cc
index 1078847..cda9eb0 100644
--- a/src/2dmyoseries-dice.cc
+++ b/src/2dmyoseries-dice.cc
@@ -76,7 +76,7 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( org_filename, "input", 'i', "original segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( skip, "skip", 'k', "images to skip atthe bgin of the series"));
options.add(make_opt( reference, "reference", 'r', "reference image"));
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dsegcompare.cc b/src/2dsegcompare.cc
index 7a67f5f..c8adaf7 100644
--- a/src/2dsegcompare.cc
+++ b/src/2dsegcompare.cc
@@ -67,6 +67,8 @@ int do_main(int argc, char *argv[])
CCmdOptionList options(g_description);
options.add(make_opt( src_filename, "in-file", 'i', "input segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( ref_filename, "ref-file", 'r', "reference segmentation set", CCmdOptionFlags::required_input));
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dseghausdorff.cc b/src/2dseghausdorff.cc
index bb1de98..c400dfd 100644
--- a/src/2dseghausdorff.cc
+++ b/src/2dseghausdorff.cc
@@ -62,6 +62,7 @@ int do_main(int argc, char *argv[])
options.add(make_opt( src_filename, "in-file", 'i', "input segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( reference, "ref-frame", 'r', "reference frame", CCmdOptionFlags::required_input));
options.add(make_opt( skip, "skip", 'k', "skip frames at the beginning"));
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dsegseriesstats.cc b/src/2dsegseriesstats.cc
index 9630055..965ff09 100644
--- a/src/2dsegseriesstats.cc
+++ b/src/2dsegseriesstats.cc
@@ -125,8 +125,10 @@ int do_main( int argc, char *argv[] )
"using the original segmentation of the reference on all images of the original series, "
"the second column contains the values obtained by the registered segmentation of the "
"reference on all images of the registered series, and the third column contains the "
- "values obtained by using the segmentations of each slice on the original images."));
- options.add(make_opt( varcurves_filename, "varcurves", 'v', "region variation values, same formt as described above. "));
+ "values obtained by using the segmentations of each slice on the original images.",
+ CCmdOptionFlags::output));
+ options.add(make_opt( varcurves_filename, "varcurves", 'v', "region variation values, same formt as described above. ",
+ CCmdOptionFlags::output));
options.add(make_opt( n_sections, "nsections", 'n',
"number of sections to use, 0=use as segmented, otherwise Otherwise, the LV myocardium is "
"divided into n sections that enclose equal angles starting at the "
diff --git a/src/2dseries-mincorr.cc b/src/2dseries-mincorr.cc
index 1a42b56..b4a87b8 100644
--- a/src/2dseries-mincorr.cc
+++ b/src/2dseries-mincorr.cc
@@ -89,8 +89,8 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
- options.add(make_opt( src_name, "in", 'i', "input segmentation set", CCmdOptionFlags::required_input));
- options.add(make_opt( out_name, "out", 'o', "output image of minimal correlation",
+ options.add(make_opt( src_name, "in-set", 'i', "input segmentation set", CCmdOptionFlags::required_input));
+ options.add(make_opt( out_name, "out-set", 'o', "output image of minimal correlation",
CCmdOptionFlags::required_output, &C2DImageIOPluginHandler::instance()));
options.add(make_opt( skip, "skip", 'k', "skip images at beginning of series"));
diff --git a/src/2dseries-segdistance.cc b/src/2dseries-segdistance.cc
index 5aff518..4824378 100644
--- a/src/2dseries-segdistance.cc
+++ b/src/2dseries-segdistance.cc
@@ -103,6 +103,9 @@ int do_main(int argc, char *argv[])
options.add(make_opt( src_filename, "in-file", 'i', "input segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( reference, "reference", 'r', "reference frame"));
options.add(make_opt( skip, "skip", 'k', "skip images at the beginning"));
+
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dseries2sets.cc b/src/2dseries2sets.cc
index 8421aff..266938c 100644
--- a/src/2dseries2sets.cc
+++ b/src/2dseries2sets.cc
@@ -171,7 +171,7 @@ int do_main( int argc, char *argv[] )
bool no_copy_images = false;
CCmdOptionList options(g_description);
- options.add(make_opt( out_directory, "out", 'o', "output directory (needs to exist and be writable)",
+ options.add(make_opt( out_directory, "out-directory", 'o', "output directory (needs to exist and be writable)",
CCmdOptionFlags::required_output));
options.add(make_opt( no_copy_images, "no-copy", 0, "don't copy image files to output directory"));
diff --git a/src/2dserieshausdorff.cc b/src/2dserieshausdorff.cc
index 623263d..a6bb371 100644
--- a/src/2dserieshausdorff.cc
+++ b/src/2dserieshausdorff.cc
@@ -60,6 +60,7 @@ int do_main(int argc, char *argv[])
options.add(make_opt( src_filename, "in-file", 'i', "input segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( ref_filename, "ref-file", 'r', "reference segmentation set", CCmdOptionFlags::required_input));
options.add(make_opt( skip, "skip", 'k', "skip images at the beginning"));
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/2dstackfilter.cc b/src/2dstackfilter.cc
index 64b3e95..60c6c31 100644
--- a/src/2dstackfilter.cc
+++ b/src/2dstackfilter.cc
@@ -123,12 +123,9 @@ int do_main(int argc, char *argv[])
options.add(make_opt( in_filename, "in-file", 'i', "input image(s) to be filtered", CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( out_filename, "out-file", 'o', "output file name base, the actual names is created "
"by adding the file number based on output order and the extension bysed on the 'type' parameter"
- , CCmdOptionFlags::required, &imageio));
+ , CCmdOptionFlags::required_output, &imageio));
options.add(make_opt( out_type, imageio.get_supported_suffix_set(), "type", 't',
"output file type", CCmdOptionFlags::required));
- options.add(make_help_opt( "help-plugins", 0,
- "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<C2DFifoFilterPluginHandler>));
if (options.parse(argc, argv, "filter", &sfh) != CCmdOptionList::hr_no)
diff --git a/src/3dcost.cc b/src/3dcost.cc
index af4f0fe..02a9c39 100644
--- a/src/3dcost.cc
+++ b/src/3dcost.cc
@@ -42,7 +42,7 @@ int do_main(int argc, char **argv)
{
CCmdOptionList options(g_description);
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv, "cost", &C3DFullCostPluginHandler::instance()) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3ddistance-stats.cc b/src/3ddistance-stats.cc
index c864203..62f123a 100644
--- a/src/3ddistance-stats.cc
+++ b/src/3ddistance-stats.cc
@@ -185,10 +185,11 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( label_translate_filename, "label-map", 'l', "optional mapping of label numbers",
- CCmdOptionFlags::input));
+ CCmdOptionFlags::input));
options.add(make_opt( out_filename, "out-file", 'o', "output file name to write the distances to. "
- "The output file is a csv file, containing distances listed for each label."));
+ "The output file is a csv file, containing distances listed for each label.",
+ CCmdOptionFlags::required_output));
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
diff --git a/src/3dfield2norm.cc b/src/3dfield2norm.cc
index 489802b..918e867 100644
--- a/src/3dfield2norm.cc
+++ b/src/3dfield2norm.cc
@@ -46,8 +46,10 @@ int do_main(int argc, char *argv[])
CCmdOptionList options(g_description);
- options.add(make_opt( src_filename, "in", 'i', "input vector field", CCmdOptionFlags::required_input, &C3DVFIOPluginHandler::instance()));
- options.add(make_opt( out_filename, "out", 'o', "output image", CCmdOptionFlags::required_output, &C3DImageIOPluginHandler::instance()));
+ options.add(make_opt( src_filename, "in-vectorfield", 'i', "input vector field",
+ CCmdOptionFlags::required_input, &C3DVFIOPluginHandler::instance()));
+ options.add(make_opt( out_filename, "out-image", 'o', "output image comprising the per voxel norm of each image",
+ CCmdOptionFlags::required_output, &C3DImageIOPluginHandler::instance()));
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dgetsize.cc b/src/3dgetsize.cc
index 218541c..c7e0c74 100644
--- a/src/3dgetsize.cc
+++ b/src/3dgetsize.cc
@@ -49,7 +49,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
options.add(make_opt( in_filename, "in-file", 'i', "input image(s) to be filtered",
CCmdOptionFlags::required_input, &imageio3d));
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dgetslice.cc b/src/3dgetslice.cc
index 638ea04..5289c60 100644
--- a/src/3dgetslice.cc
+++ b/src/3dgetslice.cc
@@ -115,9 +115,13 @@ public:
bool retval = true;
for(size_t i = m_start; i < end; ++i) {
P2DImage pimage(new T2DImage<T>(__dispatch<T, s_dir>::get_slice(i, image)));
- stringstream out_name;
- out_name << m_fname << setw(m_digits) << setfill('0') << i << "." << m_type;
- retval &= save_image(out_name.str(), pimage);
+ if (m_n != 1) {
+ stringstream out_name;
+ out_name << m_fname << setw(m_digits) << setfill('0') << i << "." << m_type;
+ retval &= save_image(out_name.str(), pimage);
+ }else{
+ retval &= save_image(m_fname, pimage);
+ }
}
return retval;
}
@@ -136,7 +140,7 @@ int do_main( int argc, char *argv[] )
string out_filename;
string out_type("png");
size_t start_slice = 0;
- size_t slice_number = 0;
+ size_t slice_number = 1;
EDirection direction = dir_xy;
int digits = 4;
@@ -146,13 +150,14 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_filename, "in-file", 'i',
"input image(s) to be filtered",
CCmdOptionFlags::required_input, &C3DImageIOPluginHandler::instance()));
- options.add(make_opt( out_filename, "out-file", 'o', "output image(s) base name, give without "
- "extension since this will be based on the '--type' option",
+ options.add(make_opt( out_filename, "out-file", 'o', "output image(s). If number != 1 than this is used as a base name "
+ "and should be given without extension since this will be based on the '--type' option. "
+ "If number=1 then this exact file name will be used.",
CCmdOptionFlags::required_output, &imageio2d));
- options.add(make_opt( out_type, imageio2d.get_set(), "type", 't', "output file type"));
+ options.add(make_opt( out_type, imageio2d.get_set(), "type", 't', "output file type for number != 1"));
options.add(make_opt( start_slice, "start", 's',"start slice number"));
options.add(make_opt( slice_number, "number", 'n', "number of slices (all=0)"));
- options.add(make_opt( digits, "ndigits", 0, "minimum number of digits of the file name numbers"));
+ options.add(make_opt( digits, "ndigits", 0, "minimum number of digits of the file name numbers (if n != 1)"));
options.add(make_opt( direction, GDirectionmap, "dir", 'd',
"slice direction (xy=axial, xz=coronal, yz=saggital)"));
diff --git a/src/3dimagecombine.cc b/src/3dimagecombine.cc
index e6c4cad..5c35f19 100644
--- a/src/3dimagecombine.cc
+++ b/src/3dimagecombine.cc
@@ -56,7 +56,7 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_image2, "image2", '2', "input image 2 to be combined",
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( combiner, "add", "combiner", 'c', "combiner operation", CCmdOptionFlags::required));
- options.add(make_opt( out_filename, "out", 'o', "output file", CCmdOptionFlags::required_output, &imageio));
+ options.add(make_opt( out_filename, "out-image", 'o', "output file", CCmdOptionFlags::required_output, &imageio));
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dimagefilter.cc b/src/3dimagefilter.cc
index cf0a827..5ae446f 100644
--- a/src/3dimagefilter.cc
+++ b/src/3dimagefilter.cc
@@ -57,8 +57,6 @@ int do_main( int argc, char *argv[] )
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( out_filename, "out-file", 'o', "output image(s) that have been filtered",
CCmdOptionFlags::required_output, &imageio));
- options.add(make_help_opt( "help-plugins", 0, "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<C3DFilterPluginHandler>));
if (options.parse(argc, argv, "filter", &filter_plugins) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dimagefilterstack.cc b/src/3dimagefilterstack.cc
index 79959a5..e8aa3d8 100644
--- a/src/3dimagefilterstack.cc
+++ b/src/3dimagefilterstack.cc
@@ -72,13 +72,9 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_filename, "in-file", 'i', "input image(s) to be filtered", CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( out_filename, "out-file", 'o', "output file name base, numbers are added accorfing to the input "
"file pattern, and the file extension is added according to the 'type' option.",
- CCmdOptionFlags::required, &imageio));
+ CCmdOptionFlags::required_output, &imageio));
options.add(make_opt( out_type, imageio.get_set(), "type", 't',"output file type", CCmdOptionFlags::required));
- options.add(make_help_opt( "help-plugins", 0,
- "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<C3DFilterPluginHandler>));
-
if (options.parse(argc, argv, "filter", &filter_plugins) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dimagestats.cc b/src/3dimagestats.cc
index 868a09b..e509580 100644
--- a/src/3dimagestats.cc
+++ b/src/3dimagestats.cc
@@ -87,7 +87,8 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_filename, "in-file", 'i', "input image(s) to be filtered",
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( thresh, "thresh", 't', "intensity thresh to ignore"));
-
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dlandmarks-distances.cc b/src/3dlandmarks-distances.cc
index bba662c..ec192ee 100644
--- a/src/3dlandmarks-distances.cc
+++ b/src/3dlandmarks-distances.cc
@@ -57,7 +57,7 @@ int do_main(int argc, char **argv)
options.add(make_opt( src1_filename, "in-file-1", 'i', "input landmark set 1", CCmdOptionFlags::required_input, &lmxio));
options.add(make_opt( src2_filename, "in-file-2", 'o', "input landmark set 2", CCmdOptionFlags::required_input, &lmxio));
-
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/3dlerp.cc b/src/3dlerp.cc
index 96bb6ee..7c5e128 100644
--- a/src/3dlerp.cc
+++ b/src/3dlerp.cc
@@ -19,6 +19,9 @@
*/
#include <climits>
+
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_NO_MAIN
#include <boost/test/unit_test_suite.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
@@ -38,8 +41,10 @@ const SProgramDescription g_description = {
{pdi_group, "Analysis, filtering, combining, and segmentation of 3D images"},
{pdi_short, "Linearly combine two 3D images."},
{pdi_description, "merge two images by linear combination."},
- {pdi_example_descr, "Combine image inputA.v and inputB.v by using position "
- "coordinates 4, 7, and 9 and write the result to output.v"},
+ {pdi_example_descr, "Combine image inputA.v and inputB.v by using position coordinates "
+ "4, 7, and 9. This means the output pixel values will be evaluated according to\n\n"
+ " (9-7)/(9-4) * A + (7-4)/(9-4) * B \n\n"
+ "The result image will be written to output.v"},
{pdi_example_code, "-1 inputA.v -2 inputB.v -p 4,7,9 -o output.v"}
};
@@ -87,7 +92,7 @@ private:
float m_w;
};
-static void run_self_test()
+BOOST_AUTO_TEST_CASE( run_self_test )
{
const C3DBounds size(1,2,1);
@@ -113,11 +118,7 @@ static void run_self_test()
}
-static bool init_unit_test_suite( )
-{
- ::boost::unit_test::framework::master_test_suite().add( BOOST_TEST_CASE( &run_self_test));
- return true;
-}
+SELFTEST_CALLBACK(CSelftest);
template <typename F>
struct FFilter {
@@ -141,7 +142,7 @@ int do_main(int argc, char **argv)
string src1_filename;
string src2_filename;
string out_filename;
- bool self_test = false;
+ int self_test_result = 0;
vector<float> positions;
@@ -153,13 +154,17 @@ int do_main(int argc, char **argv)
CCmdOptionFlags::required_output, &imageio));
options.add(make_opt( positions, "positions", 'p',
"image series positions (first, target, second)", CCmdOptionFlags::required));
- options.add(make_opt( self_test, "self-test", 0, "run a self test of the tool"));
+
+ options.add_selftest(self_test_result, new CSelftest(argc, argv));
- if (options.parse(argc, (const char **)argv) != CCmdOptionList::hr_no)
- return EXIT_SUCCESS;
- if (self_test) {
- return ::boost::unit_test::unit_test_main( &init_unit_test_suite, argc, argv );
+ switch (options.parse(argc, argv, "boost-test-options")) {
+ case CCmdOptionList::hr_no:
+ break;
+ case CCmdOptionList::hr_selftest:
+ return self_test_result;
+ default:
+ return EXIT_SUCCESS;
}
if (positions.size() != 3) {
diff --git a/src/3dnonrigidreg.cc b/src/3dnonrigidreg.cc
index c4d2df5..dd43467 100644
--- a/src/3dnonrigidreg.cc
+++ b/src/3dnonrigidreg.cc
@@ -59,13 +59,13 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
options.set_group("IO");
- options.add(make_opt( src_filename, "in", 'i', "test image",
+ options.add(make_opt( src_filename, "in-image", 'i', "test image",
CCmdOptionFlags::required_input, &image3dio));
- options.add(make_opt( ref_filename, "ref", 'r', "reference image",
+ options.add(make_opt( ref_filename, "ref-image", 'r', "reference image",
CCmdOptionFlags::required_input, &image3dio));
- options.add(make_opt( out_filename, "out", 'o', "registered output image",
+ options.add(make_opt( out_filename, "out-image", 'o', "registered output image",
CCmdOptionFlags::required_output, &image3dio));
- options.add(make_opt( trans_filename, "trans", 't', "output transformation",
+ options.add(make_opt( trans_filename, "transformation", 't', "output transformation",
CCmdOptionFlags::output, &transform3dio));
options.set_group("Registration");
diff --git a/src/3drigidreg.cc b/src/3drigidreg.cc
index ef8e272..8a9ca13 100644
--- a/src/3drigidreg.cc
+++ b/src/3drigidreg.cc
@@ -63,13 +63,13 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
options.set_group("File I/O");
- options.add(make_opt( src_filename, "in", 'i', "test image",
+ options.add(make_opt( src_filename, "in-image", 'i', "test image",
CCmdOptionFlags::required_input, &C3DImageIOPluginHandler::instance()));
- options.add(make_opt( ref_filename, "ref", 'r', "reference image",
+ options.add(make_opt( ref_filename, "ref-image", 'r', "reference image",
CCmdOptionFlags::required_input, &C3DImageIOPluginHandler::instance()));
- options.add(make_opt( out_filename, "out", 'o', "registered output image",
+ options.add(make_opt( out_filename, "out-image", 'o', "registered output image",
CCmdOptionFlags::required_output, &C3DImageIOPluginHandler::instance()));
- options.add(make_opt( trans_filename, "trans", 't', "transformation output file name",
+ options.add(make_opt( trans_filename, "transformation", 't', "transformation output file name",
CCmdOptionFlags::output, &C3DTransformationIOPluginHandler::instance() ));
diff --git a/src/3dseries-track-intensity.cc b/src/3dseries-track-intensity.cc
index 4776bed..481fa44 100644
--- a/src/3dseries-track-intensity.cc
+++ b/src/3dseries-track-intensity.cc
@@ -106,7 +106,7 @@ int do_main( int argc, char *argv[] )
options.add(make_opt( in_filename, "in-file", 'i',
"input perfusion data set", CCmdOptionFlags::required_input, &C3DImageIOPluginHandler::instance()));
options.add(make_opt( out_filename, "out-file", 'o',
- "file name for output intensity slopes"));
+ "file name for output intensity slopes", CCmdOptionFlags::required_output));
if (options.parse(argc, argv, "points") != CCmdOptionList::hr_no)
diff --git a/src/3dvfcompare.cc b/src/3dvfcompare.cc
index 4ce93a0..2ac9a05 100644
--- a/src/3dvfcompare.cc
+++ b/src/3dvfcompare.cc
@@ -22,7 +22,7 @@
#include <mia/core/cmdlineparser.hh>
#include <mia/3d/vfio.hh>
#include <mia/internal/main.hh>
-
+#include <iostream>
NS_MIA_USE
using namespace std;
@@ -48,7 +48,8 @@ int do_main(int argc, char **argv)
options.add(make_opt( vf1_filename, "in-file-1", '1', "input vector field 1", CCmdOptionFlags::required_input, &vfio));
options.add(make_opt( vf2_filename, "in-file-2", '2', "input vector field 2", CCmdOptionFlags::required_input, &vfio));
options.add(make_opt( delta, "delta", 'd', "Maximum difference between vector to be ignored"));
-
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
@@ -79,6 +80,7 @@ int do_main(int argc, char **argv)
++ivf1;
++ivf2;
}
+ std::cout << (diff ? "0" : "1") << "\n";
return diff ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 056743e..b36b275 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -17,9 +17,12 @@
#
#
-ADD_CUSTOM_TARGET(manpages)
+ADD_CUSTOM_TARGET(xmldoc)
-ADD_CUSTOM_TARGET(XMLDOC)
+INCLUDE (${CMAKE_SOURCE_DIR}/doc/MiaDoctools.cmake)
+
+SET(NIPYPE_INTERFACE_INIT_FILE ${CMAKE_CURRENT_BINARY_DIR}/__init__.py)
+MIA_PREPARE_AUTODOC(mia)
ADD_CUSTOM_TARGET(mandir COMMAND mkdir -p ${CMAKE_BINARY_DIR}/doc/man)
@@ -55,7 +58,8 @@ DEFEXE(2dfuzzysegment mia2d )
DEFEXE(2dsegment-ahmed mia2d )
DEFEXE(2dsegment-fuzzyw mia2d )
DEFEXE(2dmultiimagevar mia2d )
-#DEFEXE(2dmulti-force mia2d )
+DEFEXE(2dmultiimageregistration mia2d )
+DEFEXE(2dmulti-force mia2d )
DEFEXE(2dimagefullstats mia2d )
DEFEXE(2dbinarycombine mia2d )
DEFEXE(2dtransformation-to-strain mia2d)
@@ -66,7 +70,7 @@ DEFCHKEXE(2dlerp mia2d )
#Programs related to 2D myocardic perfusion
-DEFCHKEXE(2dsegshift mia2dmyocardperf )
+DEFEXE(2dsegshift mia2dmyocardperf )
DEFEXE(2dsegshiftperslice mia2dmyocardperf )
DEFEXE(2dsegseriesstats mia2dmyocardperf )
DEFEXE(2dseries2dordermedian mia2dmyocardperf )
@@ -92,6 +96,7 @@ DEFEXE(2dmyocard-segment mia2dmyocardperf )
DEFEXE(2dmyopgt-nonrigid mia2dmyocardperf )
DEFEXE(2dmany2one-nonrigid mia2dmyocardperf )
DEFEXE(2dmyoset-all2one-nonrigid mia2dmyocardperf )
+
IF(ITPP_FOUND)
DEFEXE(2dmyoica-full mia2dmyocardperf )
DEFEXE(2dmyoicapgt mia2dmyocardperf )
@@ -177,10 +182,3 @@ ADD_SUBDIRECTORY(fluid2d )
ADD_SUBDIRECTORY(fluid3d )
ADD_SUBDIRECTORY(isosurface )
-ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_BINARY_DIR}/doc/program.xml
- COMMAND ${PYTHON_EXECUTABLE} ARGS ${CMAKE_SOURCE_DIR}/doc/miaxml2sgml.py ${CMAKE_SOURCE_DIR}/doc ${CMAKE_BINARY_DIR}/doc
- DEPENDS XMLDOC
- )
-
-ADD_CUSTOM_TARGET(process_xml DEPENDS ${CMAKE_BINARY_DIR}/doc/program.xml)
-
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000..88da350
--- /dev/null
+++ b/src/__init__.py
@@ -0,0 +1 @@
+# init file for the nipype module
diff --git a/src/filenumberpattern.cc b/src/filenumberpattern.cc
index 8bd5501..3f41e00 100644
--- a/src/filenumberpattern.cc
+++ b/src/filenumberpattern.cc
@@ -49,6 +49,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
options.add(make_opt( in_filename, "in-file", 'i', "input image example name",
CCmdOptionFlags::required_input));
+ options.set_stdout_is_result();
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/fluid2d/CMakeLists.txt b/src/fluid2d/CMakeLists.txt
index 25d2213..e482e4f 100644
--- a/src/fluid2d/CMakeLists.txt
+++ b/src/fluid2d/CMakeLists.txt
@@ -20,6 +20,7 @@ SET(fluid2d_SOURCES main.cc vfluid.cc elast.cc helpers.cc)
ADD_EXECUTABLE(mia-2dfluid ${fluid2d_SOURCES})
TARGET_LINK_LIBRARIES(mia-2dfluid mia2d)
-CREATE_EXE_DOCU(2dfluid)
+MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia 2dfluid)
+
INSTALL(TARGETS mia-2dfluid RUNTIME DESTINATION "bin")
diff --git a/src/fluid2d/main.cc b/src/fluid2d/main.cc
index 98f9c63..05d0001 100644
--- a/src/fluid2d/main.cc
+++ b/src/fluid2d/main.cc
@@ -110,13 +110,13 @@ int do_main(int argc, char *argv[])
CCmdOptionList options(g_description);
options.set_group("File-IO");
- options.add(make_opt( src_filename, "in-image", 'i', "input (model) image to be registered",
+ options.add(make_opt( src_filename, "in-image", 'i', "input (test) image to be registered",
CCmdOptionFlags::required_input, &imageio));
options.add(make_opt( ref_filename, "ref-image", 'r', "reference image",
CCmdOptionFlags::required_input, &imageio));
- options.add(make_opt( out_filename, "out", 'o', "output vector field",
+ options.add(make_opt( out_filename, "out-transformation", 'o', "output transformation comprising the registration",
CCmdOptionFlags::output, &C2DVFIOPluginHandler::instance()));
- options.add(make_opt( def_filename, "deformed-image", 'd', "deformed registered image",
+ options.add(make_opt( def_filename, "out-image", 'd', "output image deformed according to the transformation",
CCmdOptionFlags::output, &imageio));
options.set_group("Registration parameters");
diff --git a/src/fluid3d/CMakeLists.txt b/src/fluid3d/CMakeLists.txt
index 05858b7..4a1eb46 100644
--- a/src/fluid3d/CMakeLists.txt
+++ b/src/fluid3d/CMakeLists.txt
@@ -26,9 +26,10 @@ ADD_DEFINITIONS(-DVSTREAM_DOMAIN=\"fluid3d\")
ADD_EXECUTABLE(mia-3dfluid ${fluid3d_SOURCES})
TARGET_LINK_LIBRARIES(mia-3dfluid mia3d)
-CREATE_EXE_DOCU(3dfluid)
INSTALL(TARGETS mia-3dfluid RUNTIME DESTINATION "bin")
+MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia 3dfluid)
+
diff --git a/src/fluid3d/main.cc b/src/fluid3d/main.cc
index fcd587e..bb853d2 100644
--- a/src/fluid3d/main.cc
+++ b/src/fluid3d/main.cc
@@ -122,12 +122,11 @@ int do_main(int argc, char *argv[])
options.set_group("File-IO");
options.add(make_opt( in_filename, "in-image", 'i', "input image", CCmdOptionFlags::required_input, &imageio ));
options.add(make_opt( ref_filename, "ref-image", 'r', "reference image ", CCmdOptionFlags::required_input, &imageio ));
- options.add(make_opt( out_filename, "out-deformation", 'o', "output vector field",
+ options.add(make_opt( out_filename, "out-transformation", 'o', "output transformation comprising the registering transformation field",
CCmdOptionFlags::required_output, &C3DTransformationIOPluginHandler::instance()));
- options.add(make_opt(deformed_filename, "deformed-image", 'd', "save deformed image",
- CCmdOptionFlags::output, &imageio));
-
+ options.add(make_opt( deformed_filename, "out-image", 'd', "save deformed image",
+ CCmdOptionFlags::output, &imageio));
options.set_group("Registration parameters");
options.add(make_opt( disable_multigrid, "disable-multigrid", 0, "disable multi-grid processing"));
@@ -166,7 +165,6 @@ int do_main(int argc, char *argv[])
P3DFVectorfield result = fluid_transform(params,solver,!disable_multigrid,
!disable_fullres,&g_MeasureList, ipf);
-
auto vftranscreator = produce_3dtransform_factory("vf:imgkernel=[bspline:d=1],imgboundary=zero");
auto transform = vftranscreator->create(result->get_size());
diff --git a/src/isosurface/CMakeLists.txt b/src/isosurface/CMakeLists.txt
index 0b93b38..6818aa2 100644
--- a/src/isosurface/CMakeLists.txt
+++ b/src/isosurface/CMakeLists.txt
@@ -38,12 +38,12 @@ IF(GTS_FOUND)
# add the ISO-surface programs
ADD_EXECUTABLE(mia-3disosurface-from-volume iso.cc)
- CREATE_EXE_DOCU(3disosurface-from-volume)
+ MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia 3disosurface-from-volume)
TARGET_LINK_LIBRARIES(mia-3disosurface-from-volume miagts)
INSTALL(TARGETS mia-3disosurface-from-volume RUNTIME DESTINATION "bin")
ADD_EXECUTABLE(mia-3disosurface-from-stack iso_from_slices.cc)
- CREATE_EXE_DOCU(3disosurface-from-stack)
+ MIA_EXE_CREATE_DOCU_AND_INTERFACE(mia 3disosurface-from-stack)
TARGET_LINK_LIBRARIES(mia-3disosurface-from-stack miagts)
INSTALL(TARGETS mia-3disosurface-from-stack RUNTIME DESTINATION "bin")
diff --git a/src/meshfilter.cc b/src/meshfilter.cc
index 0dfb532..4aaa6fa 100644
--- a/src/meshfilter.cc
+++ b/src/meshfilter.cc
@@ -51,10 +51,6 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_general_help);
options.add(make_opt( in_filename, "in-file", 'i', "input mesh to be filtered", CCmdOptionFlags::required_input, &meshio));
options.add(make_opt( out_filename, "out-file", 'o', "output mesh that have been filtered", CCmdOptionFlags::required_output, &meshio));
- options.set_group(g_help_optiongroup);
- options.add(make_help_opt( "help-filters", 0,
- "give some help about the filter plugins",
- new TPluginHandlerHelpCallback<CMeshFilterPluginHandler>));
if (options.parse(argc, argv, "filter", &filter_plugins) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/multihist.cc b/src/multihist.cc
index 32b406c..3c5f34a 100644
--- a/src/multihist.cc
+++ b/src/multihist.cc
@@ -115,7 +115,7 @@ int do_main( int argc, char *argv[] )
CCmdOptionList options(g_description);
options.add(make_opt( in_filename, "in-file", 'i', "input image(s) to be filtered",
CCmdOptionFlags::required_input, &imageio));
- options.add(make_opt( out_filename, "out", 'o', "output file name",
+ options.add(make_opt( out_filename, "out-histogram", 'o', "output file name",
CCmdOptionFlags::required_output));
options.add(make_opt( hmin, "min", 0, "minimum of histogram range"));
options.add(make_opt( hmax, "max", 0, "maximum of histogram range"));
diff --git a/src/myowavelettest.cc b/src/myowavelettest.cc
index d31dbce..5cb8a1d 100644
--- a/src/myowavelettest.cc
+++ b/src/myowavelettest.cc
@@ -67,7 +67,8 @@ int do_main( int argc, char *argv[] )
options.set_group("File-IO");
options.add(make_opt( in_filename, "in-file", 'i', "input data set",
CCmdOptionFlags::required_input));
-
+ options.set_stdout_is_result();
+
if (options.parse(argc, argv) != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
diff --git a/src/plugin-help.cc b/src/plugin-help.cc
index 70d28da..9cc3a07 100644
--- a/src/plugin-help.cc
+++ b/src/plugin-help.cc
@@ -99,8 +99,10 @@ map<string, const CPluginHandlerBase*> collect_handlers()
int do_main( int argc, char *argv[] )
{
CCmdOptionList options(description);
+ options.set_stdout_is_result();
if (options.parse(argc, argv, "plugin-descriptor") != CCmdOptionList::hr_no)
return EXIT_SUCCESS;
+
auto handlers = collect_handlers();
diff --git a/src/test_plugins_as_installed.cc b/src/test_plugins_as_installed.cc
index af1275e..c022c0b 100644
--- a/src/test_plugins_as_installed.cc
+++ b/src/test_plugins_as_installed.cc
@@ -74,6 +74,7 @@ BOOST_FIXTURE_TEST_CASE(test_C3DImageIOPluginHandler,PluginTestFixture)
"inria",
"hdf5",
"mhd",
+ "nifti",
"vff",
"vti",
"vtk",
@@ -103,7 +104,8 @@ BOOST_FIXTURE_TEST_CASE(test_C3DImageCreatorPluginHandler,PluginTestFixture)
BOOST_FIXTURE_TEST_CASE(test_C3DTransformCreatorHandler,PluginTestFixture)
{
set<string> test_data = {
- "affine", "axisrot", "raffine", "rigid", "spline", "translate", "rotation", "vf"
+ "affine", "axisrot", "raffine", "rigid", "spline",
+ "translate", "rotation", "rotbend", "vf"
};
test(C3DTransformCreatorHandler::instance().get_set(), test_data);
}
@@ -217,7 +219,7 @@ BOOST_FIXTURE_TEST_CASE(test_C2DVFIOPluginHandler,PluginTestFixture)
BOOST_FIXTURE_TEST_CASE(test_C2DFullCostPluginHandler,PluginTestFixture)
{
set<string> test_data = {
- "image", "maskedimage"
+ "image", "labelimage", "maskedimage"
};
test(C2DFullCostPluginHandler::instance().get_set(), test_data);
@@ -260,7 +262,7 @@ BOOST_FIXTURE_TEST_CASE(test_C2DFilterPluginHandler,PluginTestFixture)
"adaptmed", "admean", "aniso", "bandpass", "binarize", "combiner",
"convert", "close", "crop", "dilate", "distance",
"downscale", "erode", "gauss", "gradnorm", "invert", "kmeans",
- "label", "labelmap", "load", "mask", "mean", "median", "mlv",
+ "label", "labelmap", "labelscale", "load", "mask", "mean", "median", "mlv",
"ngfnorm", "noise", "open", "pruning", "regiongrow", "sandp",
"scale", "selectbig", "sepconv", "shmean", "sort-label", "sws",
"tee", "thinning", "thresh", "transform", "ws"
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/mia.git
More information about the debian-med-commit
mailing list