text: /*=========================================================================
   *
   *  Copyright NumFOCUS
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *         http://www.apache.org/licenses/LICENSE-2.0.txt
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   *=========================================================================*/
  #ifndef itkLabelToRGBFunctor_h
  #define itkLabelToRGBFunctor_h
  
  #include <vector>
  #include "itkNumericTraits.h"
  
  namespace itk
  {
  namespace Functor
  {
  /**
   *\class LabelToRGBFunctor
   *  \brief Functor for converting labels into RGB triplets.
   *
   * This functor class used internally by LabelToRGBImageFilter
   *
   * This code was contributed in the Insight Journal paper:
   * "The watershed transform in ITK - discussion and new developments"
   * by Beare R., Lehmann G.
   * https://hdl.handle.net/1926/202
   * http://www.insight-journal.org/browse/publication/92
   *
   * \author Gaetan Lehmann. Biologie du Developpement et de la Reproduction,
   * INRA de Jouy-en-Josas, France.
   *
   * \author Richard Beare. Department of
   * Medicine, Monash University, Melbourne, Australia.
   *
   * \sa LabelToRGBImageFilter
   *
   * \ingroup ITKImageFusion
   */
  template <typename TLabel, typename TRGBPixel>
  class LabelToRGBFunctor
  {
  public:
    using Self = LabelToRGBFunctor;
  
    LabelToRGBFunctor()
    {
      using ValueType = typename TRGBPixel::ValueType;
  
      // the following colors are from "R", and named:
      // "red"             "green3"          "blue"            "cyan"
      //"magenta"         "darkorange1"     "darkgreen"       "blueviolet"
      //"brown4"          "navy"            "yellow4"         "violetred1"
      //"salmon4"         "turquoise4"      "sienna3"         "darkorchid1"
      //"springgreen4"    "mediumvioletred" "orangered3"      "lightseagreen"
      //"slateblue"       "deeppink1"       "aquamarine4"     "royalblue1"
      //"tomato3"         "mediumblue"      "violetred4"      "darkmagenta"
      //"violet"          "red4"
      // They are a good selection of distinct colors for plotting and
      // overlays.
      constexpr size_t        numColors = 30;
      constexpr unsigned char colors[numColors][3] = {
        { 255, 0, 0 },   { 0, 205, 0 },    { 0, 0, 255 },    { 0, 255, 255 },  { 255, 0, 255 },   { 255, 127, 0 },
        { 0, 100, 0 },   { 138, 43, 226 }, { 139, 35, 35 },  { 0, 0, 128 },    { 139, 139, 0 },   { 255, 62, 150 },
        { 139, 76, 57 }, { 0, 134, 139 },  { 205, 104, 57 }, { 191, 62, 255 }, { 0, 139, 69 },    { 199, 21, 133 },
        { 205, 55, 0 },  { 32, 178, 170 }, { 106, 90, 205 }, { 255, 20, 147 }, { 69, 139, 116 },  { 72, 118, 255 },
        { 205, 79, 57 }, { 0, 0, 205 },    { 139, 34, 82 },  { 139, 0, 139 },  { 238, 130, 238 }, { 139, 0, 0 }
      };
  
      for (auto & color : colors)
      {
        AddColor(color[0], color[1], color[2]);
      }
  
      // provide some default value for external use (outside
      // LabelToRGBImageFilter)
      // Inside LabelToRGBImageFilter, the values are always initialized
      NumericTraits<TRGBPixel>::SetLength(m_BackgroundColor, 3);
      m_BackgroundColor.Fill(NumericTraits<ValueType>::ZeroValue());
      m_BackgroundValue = NumericTraits<TLabel>::ZeroValue();
    }
  
    inline TRGBPixel
    operator()(const TLabel & p) const
    {
      // value is background
      // return a gray pixel with the same intensity than the label pixel
      if (p == m_BackgroundValue)
      {
        return m_BackgroundColor;
      }
  
      // else, return a colored pixel from the color table
      return m_Colors[p % m_Colors.size()];
    }
  
    void
    AddColor(unsigned char r, unsigned char g, unsigned char b)
    {
      TRGBPixel rgbPixel;
      NumericTraits<TRGBPixel>::SetLength(rgbPixel, 3);
  
      using ValueType = typename TRGBPixel::ValueType;
  
      ValueType m = NumericTraits<ValueType>::max();
  
      rgbPixel[0] = static_cast<ValueType>(static_cast<double>(r) / 255 * m);
      rgbPixel[1] = static_cast<ValueType>(static_cast<double>(g) / 255 * m);
      rgbPixel[2] = static_cast<ValueType>(static_cast<double>(b) / 255 * m);
      m_Colors.push_back(rgbPixel);
    }
  
    // Empty the color LUT
    void
    ResetColors()
    {
      m_Colors.clear();
    }
  
    // Get number of colors in the LUT
    unsigned int
    GetNumberOfColors() const
    {
      return static_cast<unsigned int>(m_Colors.size());
    }
  
    bool
    operator!=(const Self & l) const
    {
      if (m_BackgroundColor != l.m_BackgroundColor || m_BackgroundValue != l.m_BackgroundValue ||
          m_Colors.size() != l.m_Colors.size())
      {
        return true;
      }
  
      // We need to check each color to see if it's different
      for (typename std::vector<TRGBPixel>::size_type i = 0; i < m_Colors.size(); ++i)
      {
        if (m_Colors[i] != l.m_Colors[i])
        {
          return true;
        }
      }
      return false;
    }
  
    bool
    operator==(const Self & other) const
    {
      return !(*this != other);
    }
  
    void
    SetBackgroundValue(TLabel v)
    {
      m_BackgroundValue = v;
    }
  
    void
    SetBackgroundColor(TRGBPixel rgb)
    {
      m_BackgroundColor = rgb;
    }
  
    ~LabelToRGBFunctor() = default;
  
    std::vector<TRGBPixel> m_Colors;
  
    TRGBPixel m_BackgroundColor;
  
    TLabel m_BackgroundValue;
  };
  } // end namespace Functor
  } // end namespace itk
  
  #endif
  