Commit efd71a61 authored by David Frank's avatar David Frank
Browse files

Add read and write free functions

The read and write free functions decide based on the extension given,
what format to read and write, making it a little more convenient to
quickly switch output and input formats. So it's only necessary to
change the string, rather than the string and the namespace prefix.
parent 4a162a93
Pipeline #834649 passed with stages
in 35 minutes and 49 seconds
......@@ -4,6 +4,12 @@ elsa io
.. contents:: Table of Contents
General
=======
.. doxygenfunction:: elsa::io::write
.. doxygenfunction:: elsa::io::read
EDF
===
......
# list all the headers of the module
set(MODULE_HEADERS EDFHandler.h MHDHandler.h PGMHandler.h ioUtils.h)
set(MODULE_HEADERS EDFHandler.h MHDHandler.h PGMHandler.h IO.h ioUtils.h)
# list all the code files of the module
set(MODULE_SOURCES EDFHandler.cpp MHDHandler.cpp PGMHandler.cpp ioUtils.cpp)
set(MODULE_SOURCES EDFHandler.cpp MHDHandler.cpp PGMHandler.cpp IO.cpp ioUtils.cpp)
list(APPEND MODULE_PUBLIC_DEPS elsa_core elsa_logging)
list(APPEND MODULE_PRIVATE_DEPS)
......
......@@ -10,6 +10,7 @@
#include <map>
#include <ostream>
#include <string>
#include <string_view>
namespace elsa
{
......
#include "IO.h"
#include "EDFHandler.h"
#include "Error.h"
#include "MHDHandler.h"
#include "PGMHandler.h"
#include <iostream>
namespace elsa::io
{
[[nodiscard]] std::optional<std::string_view> get_extension(std::string_view str)
{
const auto delimiter = '.';
const auto last_part = str.find_last_of(delimiter);
// String doesn't contain delimiter
if (last_part == std::string_view::npos) {
return std::nullopt;
}
return str.substr(last_part);
}
template <typename data_t>
[[nodiscard]] DataContainer<data_t> read(std::string_view filename)
{
const auto opt = get_extension(filename);
// No dot present in filename, so throw right away
if (!opt.has_value()) {
throw Error("No extension found in filename (\"{}\")", filename);
}
const auto extension = *opt;
if (extension == ".edf") {
return EDF::read<data_t>(std::string{filename});
}
throw Error("Can not read with unsupported file extension \"{}\"", extension);
}
template <typename data_t>
void write(DataContainer<data_t> x, std::string_view filename)
{
const auto opt = get_extension(filename);
// No dot present in filename, so throw right away
if (!opt.has_value()) {
throw Error("No extension found in filename (\"{}\")", filename);
}
const auto extension = *opt;
if (extension == ".edf") {
return EDF::write<data_t>(x, std::string{filename});
} else if (extension == ".pgm") {
return PGM::write<data_t>(x, std::string{filename});
}
throw Error("Can not write with unsupported file extension \"{}\"", extension);
}
template DataContainer<float> read<float>(std::string_view);
template DataContainer<double> read<double>(std::string_view);
template void write<float>(DataContainer<float>, std::string_view);
template void write<double>(DataContainer<double>, std::string_view);
} // namespace elsa::io
#pragma once
#include "DataContainer.h"
#include <optional>
#include <string_view>
namespace elsa::io
{
/**
* @brief Read from filename and create a DataContainer. Filename is expected to have a valid
* (i.e. supported) extension, else this function will throw.
*
* @param filename filename to read data from
*/
template <typename data_t>
DataContainer<data_t> read(std::string_view filename);
/**
* @brief Write DataContainer to a file with given filename. Filename is expected to have a
* valid (i.e. supported) extension, else this function will throw.
*
* @param x DataContainer to write to file
* @param filename filename to write data to
*/
template <typename data_t>
void write(DataContainer<data_t> x, std::string_view filename);
} // namespace elsa::io
......@@ -15,6 +15,7 @@ add_custom_target(
# the actual tests
ELSA_DOCTEST(ioUtils)
ELSA_DOCTEST(IO)
ELSA_DOCTEST(EDFHandler)
ELSA_DOCTEST(MHDHandler)
ELSA_DOCTEST(PGMHandler)
#include "doctest/doctest.h"
#include "IO.h"
#include "VolumeDescriptor.h"
using namespace elsa;
using namespace doctest;
TEST_SUITE_BEGIN("io");
TEST_CASE_TEMPLATE("IO: Testing exception behaviour of read", data_t, float, double)
{
WHEN("Trying to read from a string, without an extension")
{
CHECK_THROWS_WITH_AS(io::read<data_t>("hello"),
"No extension found in filename (\"hello\")", Error);
}
WHEN("Trying to read from a string, with an unsupported extension")
{
CHECK_THROWS_WITH_AS(io::read<data_t>("hello.something"),
"Can not read with unsupported file extension \".something\"", Error);
}
WHEN("Trying to read from a string, with a valid extension")
{
// Only throws as file is not present
CHECK_THROWS_WITH_AS(io::read<data_t>("hello.edf"),
"EDF::read: cannot read from 'hello.edf'", Error);
}
WHEN("Trying to read from a string, with an multiple dots")
{
// Only throws as file is not present
CHECK_THROWS_WITH_AS(io::read<data_t>("hello.something.edf"),
"EDF::read: cannot read from 'hello.something.edf'", Error);
}
}
TEST_CASE_TEMPLATE("IO: Testing exception behaviour of write", data_t, float, double)
{
DataContainer<data_t> x(VolumeDescriptor({32, 32}));
x = 1;
WHEN("Writing an edf file")
{
THEN("it works") { CHECK_NOTHROW(io::write(x, "hellosomething.edf")); }
}
WHEN("Writing an pgm file")
{
THEN("it works") { CHECK_NOTHROW(io::write(x, "hellosomething.pgm")); }
}
WHEN("Writing an with an unsupported extension")
{
CHECK_THROWS_WITH_AS(io::write(x, "hellosomethingelse.png"),
"Can not write with unsupported file extension \".png\"", Error);
}
WHEN("Writing without an extension given")
{
CHECK_THROWS_WITH_AS(io::write(x, "hello"), "No extension found in filename (\"hello\")",
Error);
}
}
TEST_SUITE_END();
/// Elsa example program: basic 2d X-ray CT simulation and reconstruction
#include "elsa.h"
#include "IO.h"
#include <iostream>
......@@ -15,7 +16,7 @@ void example2d()
auto& volumeDescriptor = phantom.getDataDescriptor();
// write the phantom out
EDF::write(phantom, "2dphantom.edf");
io::write(phantom, "2dphantom.edf");
// generate circular trajectory
index_t numAngles{180}, arc{360};
......@@ -35,7 +36,7 @@ void example2d()
auto sinogram = projector.apply(phantom);
// write the sinogram out
EDF::write(sinogram, "2dsinogram.edf");
io::write(sinogram, "2dsinogram.edf");
// setup reconstruction problem
WLSProblem wlsProblem(projector, sinogram);
......@@ -49,7 +50,7 @@ void example2d()
auto cgReconstruction = cgSolver.solve(noIterations);
// write the reconstruction out
EDF::write(cgReconstruction, "2dreconstruction_cg.edf");
io::write(cgReconstruction, "2dreconstruction_cg.edf");
LASSOProblem lassoProb(projector, sinogram);
......@@ -60,7 +61,7 @@ void example2d()
auto istaReconstruction = istaSolver.solve(noIterations);
// write the reconstruction out
EDF::write(istaReconstruction, "2dreconstruction_ista.edf");
io::write(istaReconstruction, "2dreconstruction_ista.edf");
// solve the reconstruction problem with FISTA
FISTA fistaSolver(lassoProb);
......@@ -69,7 +70,7 @@ void example2d()
auto fistaReconstruction = fistaSolver.solve(noIterations);
// write the reconstruction out
EDF::write(fistaReconstruction, "2dreconstruction_fista.edf");
io::write(fistaReconstruction, "2dreconstruction_fista.edf");
}
int main()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment