LCOV - code coverage report
Current view: top level - io - PGMHandler.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 19 19 100.0 %
Date: 2022-05-27 02:48:28 Functions: 4 6 66.7 %

          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           4 :     void PGM::write(const DataContainer<data_t>& data, const std::string& filename)
      15             :     {
      16           8 :         std::ofstream ofs(filename, std::ios_base::out);
      17             : 
      18           4 :         PGM::write(data, ofs);
      19           2 :     }
      20             : 
      21             :     template <typename data_t>
      22           6 :     void PGM::write(const DataContainer<data_t>& data, std::ostream& stream)
      23             :     {
      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             :         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          12 :         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             :         }
      35             : 
      36           8 :         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             :         }
      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

Generated by: LCOV version 1.15