Line data Source code
1 : #include "PGMHandler.h" 2 : 3 : #include <ostream> 4 : #include <iostream> 5 : #include <exception> 6 : 7 : #include "Error.h" 8 : #include "spdlog/fmt/bundled/core.h" 9 : #include "spdlog/fmt/bundled/ostream.h" 10 : 11 : namespace elsa 12 : { 13 : template <typename data_t> 14 : void PGM::write(const DataContainer<data_t>& data, const std::string& filename) 15 4 : { 16 4 : std::ofstream ofs(filename, std::ios_base::out); 17 : 18 4 : PGM::write(data, ofs); 19 4 : } 20 : 21 : template <typename data_t> 22 : void PGM::write(const DataContainer<data_t>& data, std::ostream& stream) 23 6 : { 24 : // If `data_t` is float or double use that to cast values to, if it's 25 : // `index_t` then use real_t for multiplications 26 6 : using CastType = std::conditional_t<std::is_floating_point_v<data_t>, data_t, real_t>; 27 : 28 6 : const auto dim = data.getDataDescriptor().getNumberOfDimensions(); 29 6 : const auto shape = data.getDataDescriptor().getNumberOfCoefficientsPerDimension(); 30 : 31 : // print 3D containers with last dim 1 (this way we can slice it) 32 6 : if (dim != 2 && !(dim == 3 && shape[dim - 1] == 1)) { 33 2 : throw InvalidArgumentError("PGM:: Can only handle 2D data"); 34 2 : } 35 : 36 4 : const auto dims = data.getDataDescriptor().getNumberOfCoefficientsPerDimension(); 37 : 38 4 : const auto maxValue = data.maxElement(); 39 4 : const auto minValue = data.minElement(); 40 : 41 : // Scale all values from DataContainer to a range from [0, 255] 42 4 : const auto scaleFactor = 43 4 : 255.f / static_cast<CastType>(std::ceil(maxValue + std::abs(minValue))); 44 : 45 : // P2: Magic number specifying grey scale, then the two dimensions in the next line 46 : // Then the maximum value of the image in our case always 255 47 4 : stream << "P2\n" << dims[0] << " " << dims[1] << "\n" << 255 << "\n"; 48 : 49 : // Write data, ugly casts to silence warnings 50 2252 : for (int i = 0; i < data.getSize(); ++i) { 51 : // Scale everything to the range [0, 1] 52 2248 : const auto normalized = (data[i] - minValue) / (maxValue - minValue); 53 : 54 : // Then scale it up to the range [0, 255] 55 2248 : stream << static_cast<int>(normalized * 255.f) << " "; 56 2248 : } 57 4 : } 58 : 59 : template void PGM::write(const DataContainer<float>&, const std::string&); 60 : template void PGM::write(const DataContainer<double>&, const std::string&); 61 : template void PGM::write(const DataContainer<index_t>&, const std::string&); 62 : 63 : template void PGM::write(const DataContainer<float>&, std::ostream&); 64 : template void PGM::write(const DataContainer<double>&, std::ostream&); 65 : template void PGM::write(const DataContainer<index_t>&, std::ostream&); 66 : } // namespace elsa