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/ostr.h" 9 : 10 : namespace elsa 11 : { 12 : template <typename data_t> 13 : void PGM::write(const DataContainer<data_t>& data, const std::string& filename) 14 4 : { 15 4 : std::ofstream ofs(filename, std::ios_base::out); 16 : 17 4 : PGM::write(data, ofs); 18 4 : } 19 : 20 : template <typename data_t> 21 : void PGM::write(const DataContainer<data_t>& data, std::ostream& stream) 22 6 : { 23 : // If `data_t` is float or double use that to cast values to, if it's 24 : // `index_t` then use real_t for multiplications 25 6 : using CastType = std::conditional_t<std::is_floating_point_v<data_t>, data_t, real_t>; 26 : 27 6 : const auto dim = data.getDataDescriptor().getNumberOfDimensions(); 28 6 : const auto shape = data.getDataDescriptor().getNumberOfCoefficientsPerDimension(); 29 : 30 : // print 3D containers with last dim 1 (this way we can slice it) 31 6 : if (dim != 2 && !(dim == 3 && shape[dim - 1] == 1)) { 32 2 : throw InvalidArgumentError("PGM:: Can only handle 2D data"); 33 2 : } 34 : 35 4 : const auto dims = data.getDataDescriptor().getNumberOfCoefficientsPerDimension(); 36 : 37 4 : const auto maxValue = data.maxElement(); 38 4 : const auto minValue = data.minElement(); 39 : 40 4 : const auto range = static_cast<real_t>(maxValue - minValue); 41 4 : real_t scaleFactor; 42 4 : if (unlikely(range < std::numeric_limits<real_t>::epsilon())) { 43 2 : scaleFactor = 0.f; 44 2 : } else { 45 : // data is scaled to the range of [0, 255] 46 2 : scaleFactor = 255.f / range; 47 2 : } 48 : 49 : // P2: Magic number specifying grey scale, then the two dimensions in the next line 50 : // Then the maximum value of the image in our case always 255 51 4 : stream << "P2\n" << dims[0] << " " << dims[1] << "\n" << 255 << "\n"; 52 : 53 : // write all image pixels 54 2252 : for (int i = 0; i < data.getSize(); ++i) { 55 : // move data down to its minimum value, then scale it to the range of [0, 255] 56 2248 : int pixel_value = 57 2248 : static_cast<int>(static_cast<CastType>(data[i] - minValue) * scaleFactor); 58 : 59 2248 : stream << pixel_value << " "; 60 2248 : } 61 4 : } 62 : 63 : template void PGM::write(const DataContainer<float>& data, const std::string& filename); 64 : template void PGM::write(const DataContainer<double>& data, const std::string& filename); 65 : template void PGM::write(const DataContainer<index_t>& data, const std::string& filename); 66 : 67 : template void PGM::write(const DataContainer<float>& data, std::ostream& stream); 68 : template void PGM::write(const DataContainer<double>& data, std::ostream& stream); 69 : template void PGM::write(const DataContainer<index_t>& data, std::ostream& stream); 70 : } // namespace elsa