LCOV - code coverage report
Current view: top level - elsa/io - PGMHandler.cpp (source / functions) Hit Total Coverage
Test: coverage-all.lcov Lines: 28 28 100.0 %
Date: 2024-12-21 07:37:52 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/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

Generated by: LCOV version 1.14