Shinya Kitaoka 810553
#pragma once
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_IMAGE_OPS_HPP
Toshihiro Shimizu 890ddd
#define TCG_IMAGE_OPS_HPP
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "../image_ops.h"
Toshihiro Shimizu 890ddd
#include "../pixel.h"
Toshihiro Shimizu 890ddd
#include "../unique_ptr.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
#include <memory></memory>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace tcg {
Shinya Kitaoka 120a6e
namespace image_ops {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************
Toshihiro Shimizu 890ddd
//    Flat Blur  implementation
Toshihiro Shimizu 890ddd
//**************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename pixsum="" ptrin,="" ptrout,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void _flatFilterLine(PtrIn in, PtrOut out, int lx, int addIn, int addOut,
Shinya Kitaoka 120a6e
                     int radius, PixSum *sums) {
Shinya Kitaoka 120a6e
  typedef typename std::iterator_traits<ptrin> trIn;</ptrin>
Shinya Kitaoka 120a6e
  typedef typename trIn::value_type pixIn_type;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    inline static void fillSums(int lx, int radius, PtrIn lineIn,
Shinya Kitaoka 120a6e
                                PixSum *pixsum, int addIn, int addSum) {
Shinya Kitaoka 120a6e
      using namespace pixel_ops;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      PtrIn newPixIn = lineIn;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      PixSum sum;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Build up to radius pixels adding new pixels only
Shinya Kitaoka 120a6e
      int x, xNew, xEnd = tmin(radius, lx);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      for (xNew = 0; xNew != xEnd; ++xNew, newPixIn += addIn)
Shinya Kitaoka 120a6e
        sum = sum + *newPixIn;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Store sums AND add new pixels. Observe that the current pixel value is
Shinya Kitaoka 120a6e
      // decreased
Shinya Kitaoka 120a6e
      // BEFORE storage. This makes this function "strict" in calculating the
Shinya Kitaoka 120a6e
      // sums.
Shinya Kitaoka 120a6e
      for (x = 0; xNew != lx;
Shinya Kitaoka 120a6e
           ++x, ++xNew, lineIn += addIn, newPixIn += addIn, pixsum += addSum) {
Shinya Kitaoka 120a6e
        sum     = (sum + *newPixIn) - *lineIn;
Shinya Kitaoka 120a6e
        *pixsum = *pixsum + sum;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Finally, without adding new pixels
Shinya Kitaoka 120a6e
      for (; x != lx; ++x, lineIn += addIn, pixsum += addSum) {
Shinya Kitaoka 120a6e
        sum     = sum - *lineIn;
Shinya Kitaoka 120a6e
        *pixsum = *pixsum + sum;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  memset(sums, 0, lx * sizeof(PixSum));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Add *strict* halves of the convolution sums
Shinya Kitaoka 120a6e
  locals::fillSums(lx, radius, in, sums, addIn,
Shinya Kitaoka 120a6e
                   1);  // Right part of the convolution
Shinya Kitaoka 120a6e
  locals::fillSums(lx, radius, in + addIn * (lx - 1), sums + lx - 1, -addIn,
Shinya Kitaoka 120a6e
                   -1);  // Left   ...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Normalize sums
Shinya Kitaoka 120a6e
  int diameter = 2 * radius + 1;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (int x = 0; x != lx; ++x, in += addIn, out += addOut, ++sums) {
Shinya Kitaoka 120a6e
    using namespace pixel_ops;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    pixIn_type pix(*in);
Shinya Kitaoka 120a6e
    pixel_ops::assign(
Shinya Kitaoka 120a6e
        pix, (*sums + pix) / diameter);  // Note that *in is added, due *strict*
Shinya Kitaoka 120a6e
                                         // halving the sums above
Shinya Kitaoka 120a6e
    *out = pix;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
template 
Shinya Kitaoka 120a6e
          typename SelectorFunc>
Toshihiro Shimizu 890ddd
void _flatFilterLine(PtrIn in, PtrOut out, int lx, int addIn, int addOut,
Shinya Kitaoka 120a6e
                     SelectorFunc selector, int radius, PixSum *sums,
Shinya Kitaoka 120a6e
                     int *counts) {
Shinya Kitaoka 120a6e
  typedef typename std::iterator_traits<ptrin> trIn;</ptrin>
Shinya Kitaoka 120a6e
  typedef typename trIn::value_type pixIn_type;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  struct locals {
Shinya Kitaoka 120a6e
    inline static void fillSums(int lx, int radius, PtrIn lineIn,
Shinya Kitaoka 120a6e
                                PixSum *pixsum, int *pixcount, int addIn,
Shinya Kitaoka 120a6e
                                int addSum, SelectorFunc selector) {
Shinya Kitaoka 120a6e
      using namespace pixel_ops;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      PtrIn newPixIn = lineIn;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      PixSum sum;
Shinya Kitaoka 120a6e
      int count = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Build up to radius pixels adding new pixels only
Shinya Kitaoka 120a6e
      int x, xNew, xEnd = tmin(radius, lx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      for (xNew = 0; xNew != xEnd; ++xNew, newPixIn += addIn) {
Shinya Kitaoka 120a6e
        const pixIn_type &npi = *newPixIn;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if (selector(npi)) sum = sum + npi, ++count;
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Store sums AND add new pixels. Observe that the current pixel value is
Shinya Kitaoka 120a6e
      // decreased
Shinya Kitaoka 120a6e
      // BEFORE storage. This makes this function "strict" in calculating the
Shinya Kitaoka 120a6e
      // sums.
Shinya Kitaoka 120a6e
      for (x = 0; xNew != lx; ++x, ++xNew, lineIn += addIn, newPixIn += addIn,
Shinya Kitaoka 120a6e
          pixsum += addSum, pixcount += addSum) {
Shinya Kitaoka 120a6e
        const pixIn_type &npi = *newPixIn, &li = *lineIn;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if (selector(npi)) sum = sum + npi, ++count;
Shinya Kitaoka 120a6e
        if (selector(li)) sum  = sum - li, --count;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        *pixsum = *pixsum + sum, *pixcount += count;
Shinya Kitaoka 120a6e
      }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      // Finally, without adding new pixels
Shinya Kitaoka 120a6e
      for (; x != lx;
Shinya Kitaoka 120a6e
           ++x, lineIn += addIn, pixsum += addSum, pixcount += addSum) {
Shinya Kitaoka 120a6e
        const pixIn_type &li = *lineIn;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        if (selector(li)) sum = sum - li, --count;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
        *pixsum = *pixsum + sum, *pixcount += count;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  memset(sums, 0, lx * sizeof(PixSum));
Shinya Kitaoka 120a6e
  memset(counts, 0, lx * sizeof(int));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Add *strict* halves of the convolution sums
Shinya Kitaoka 120a6e
  locals::fillSums(lx, radius, in, sums, counts, addIn, 1, selector);
Shinya Kitaoka 120a6e
  locals::fillSums(lx, radius, in + addIn * (lx - 1), sums + lx - 1,
Shinya Kitaoka 120a6e
                   counts + lx - 1, -addIn, -1, selector);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Normalize sums
Shinya Kitaoka 120a6e
  for (int x = 0; x != lx; ++x, in += addIn, out += addOut, ++sums, ++counts) {
Shinya Kitaoka 120a6e
    using namespace pixel_ops;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    assert(*counts >= 0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    pixIn_type pix(*in);
Shinya Kitaoka 120a6e
    pixel_ops::assign(pix, (*sums + pix) / (*counts + 1));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    *out = pix;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename imgin,="" imgout,="" scalar="" typename=""></typename>
Shinya Kitaoka 120a6e
void blurRows(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgin>::pixel_ptr_type PtrIn;</imgin>
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgout>::pixel_ptr_type PtrOut;</imgout>
Shinya Kitaoka 120a6e
  typedef tcg::Pixel<scalar, image_traits<imgin="">::pixel_category> PixSum;</scalar,>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Validate parameters
Shinya Kitaoka 120a6e
  int inLx  = image_traits<imgin>::width(imgIn),</imgin>
Shinya Kitaoka 120a6e
      inLy  = image_traits<imgin>::height(imgIn);</imgin>
Shinya Kitaoka 120a6e
  int outLx = image_traits<imgout>::width(imgOut),</imgout>
Shinya Kitaoka 120a6e
      outLy = image_traits<imgout>::height(imgOut);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(inLx == outLx && inLy == outLy);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int inWrap  = image_traits<imgin>::wrap(imgIn),</imgin>
Shinya Kitaoka 120a6e
      outWrap = image_traits<imgout>::wrap(imgOut);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Allocate an intermediate line of pixels to store sum values
Shinya Kitaoka 120a6e
  tcg::unique_ptr<pixsum[]> sums(new PixSum[inLx]);</pixsum[]>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Filter rows
Shinya Kitaoka 120a6e
  for (int y = 0; y != inLy; ++y) {
Shinya Kitaoka 120a6e
    PtrIn lineIn   = image_traits<imgin>::pixel(imgIn, 0, y);</imgin>
Shinya Kitaoka 120a6e
    PtrOut lineOut = image_traits<imgout>::pixel(imgOut, 0, y);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    _flatFilterLine(lineIn, lineOut, inLx, 1, 1, radius, sums.get());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
template 
Shinya Kitaoka 120a6e
          typename Scalar>
Shinya Kitaoka 120a6e
void blurRows(const ImgIn &imgIn, ImgOut &imgOut, int radius,
Shinya Kitaoka 120a6e
              SelectorFunc selector, Scalar) {
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgin>::pixel_ptr_type PtrIn;</imgin>
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgout>::pixel_ptr_type PtrOut;</imgout>
Shinya Kitaoka 120a6e
  typedef tcg::Pixel<scalar, image_traits<imgin="">::pixel_category> PixSum;</scalar,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Validate parameters
Shinya Kitaoka 120a6e
  int inLx  = image_traits<imgin>::width(imgIn),</imgin>
Shinya Kitaoka 120a6e
      inLy  = image_traits<imgin>::height(imgIn);</imgin>
Shinya Kitaoka 120a6e
  int outLx = image_traits<imgout>::width(imgOut),</imgout>
Shinya Kitaoka 120a6e
      outLy = image_traits<imgout>::height(imgOut);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(inLx == outLx && inLy == outLy);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int inWrap  = image_traits<imgin>::wrap(imgIn),</imgin>
Shinya Kitaoka 120a6e
      outWrap = image_traits<imgout>::wrap(imgOut);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Allocate an intermediate line of pixels to store sum values
Shinya Kitaoka 120a6e
  tcg::unique_ptr<pixsum[]> sums(new PixSum[inLx]);</pixsum[]>
Shinya Kitaoka 120a6e
  tcg::unique_ptr<int[]> counts(new int[inLx]);</int[]>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Filter rows
Shinya Kitaoka 120a6e
  for (int y = 0; y != inLy; ++y) {
Shinya Kitaoka 120a6e
    PtrIn lineIn   = image_traits<imgin>::pixel(imgIn, 0, y);</imgin>
Shinya Kitaoka 120a6e
    PtrOut lineOut = image_traits<imgout>::pixel(imgOut, 0, y);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    _flatFilterLine(lineIn, lineOut, inLx, 1, 1, selector, radius, sums.get(),
Shinya Kitaoka 120a6e
                    counts.get());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename imgin,="" imgout,="" scalar="" typename=""></typename>
Shinya Kitaoka 120a6e
void blurCols(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgin>::pixel_ptr_type PtrIn;</imgin>
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgout>::pixel_ptr_type PtrOut;</imgout>
Shinya Kitaoka 120a6e
  typedef tcg::Pixel<scalar, image_traits<imgin="" typename="">::pixel_category></scalar,>
Shinya Kitaoka 120a6e
      PixSum;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Validate parameters
Shinya Kitaoka 120a6e
  int inLx  = image_traits<imgin>::width(imgIn),</imgin>
Shinya Kitaoka 120a6e
      inLy  = image_traits<imgin>::height(imgIn);</imgin>
Shinya Kitaoka 120a6e
  int outLx = image_traits<imgout>::width(imgOut),</imgout>
Shinya Kitaoka 120a6e
      outLy = image_traits<imgout>::height(imgOut);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(inLx == outLx && inLy == outLy);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  int inWrap  = image_traits<imgin>::wrap(imgIn),</imgin>
Shinya Kitaoka 120a6e
      outWrap = image_traits<imgout>::wrap(imgOut);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Allocate an intermediate line of pixels to store sum values
Shinya Kitaoka 120a6e
  tcg::unique_ptr<pixsum[]> sums(new PixSum[inLy]);</pixsum[]>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Filter columns
Shinya Kitaoka 120a6e
  for (int x = 0; x != inLx; ++x) {
Shinya Kitaoka 120a6e
    PtrIn lineIn   = image_traits<imgin>::pixel(imgIn, x, 0);</imgin>
Shinya Kitaoka 120a6e
    PtrOut lineOut = image_traits<imgout>::pixel(imgOut, x, 0);</imgout>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    _flatFilterLine(lineIn, lineOut, inLy, inWrap, outWrap, radius, sums.get());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
template 
Shinya Kitaoka 120a6e
          typename Scalar>
Shinya Kitaoka 120a6e
void blurCols(const ImgIn &imgIn, ImgOut &imgOut, int radius,
Shinya Kitaoka 120a6e
              SelectorFunc selector, Scalar) {
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgin>::pixel_ptr_type PtrIn;</imgin>
Shinya Kitaoka 120a6e
  typedef typename image_traits<imgout>::pixel_ptr_type PtrOut;</imgout>
Shinya Kitaoka 120a6e
  typedef tcg::Pixel<scalar, image_traits<imgin="" typename="">::pixel_category></scalar,>
Shinya Kitaoka 120a6e
      PixSum;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Validate parameters
Shinya Kitaoka 120a6e
  int inLx  = image_traits<imgin>::width(imgIn),</imgin>
Shinya Kitaoka 120a6e
      inLy  = image_traits<imgin>::height(imgIn);</imgin>
Shinya Kitaoka 120a6e
  int outLx = image_traits<imgout>::width(imgOut),</imgout>
Shinya Kitaoka 120a6e
      outLy = image_traits<imgout>::height(imgOut);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  assert(inLx == outLx && inLy == outLy);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int inWrap  = image_traits<imgin>::wrap(imgIn),</imgin>
Shinya Kitaoka 120a6e
      outWrap = image_traits<imgout>::wrap(imgOut);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Allocate an intermediate line of pixels to store sum values
Shinya Kitaoka 120a6e
  tcg::unique_ptr<pixsum[]> sums(new PixSum[inLy]);</pixsum[]>
Shinya Kitaoka 120a6e
  tcg::unique_ptr<int[]> counts(new int[inLy]);</int[]>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Filter columns
Shinya Kitaoka 120a6e
  for (int x = 0; x != inLx; ++x) {
Shinya Kitaoka 120a6e
    PtrIn lineIn   = image_traits<imgin>::pixel(imgIn, x, 0);</imgin>
Shinya Kitaoka 120a6e
    PtrOut lineOut = image_traits<imgout>::pixel(imgOut, x, 0);</imgout>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    _flatFilterLine(lineIn, lineOut, inLy, inWrap, outWrap, selector, radius,
Shinya Kitaoka 120a6e
                    sums.get(), counts.get());
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename imgin,="" imgout,="" scalar="" typename=""></typename>
Shinya Kitaoka 120a6e
void blur(const ImgIn &imgIn, ImgOut &imgOut, int radius, Scalar) {
Shinya Kitaoka 120a6e
  blurRows(imgIn, imgOut, radius, Scalar);
Shinya Kitaoka 120a6e
  blurCols(imgOut, imgOut, radius, Scalar);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
template 
Shinya Kitaoka 120a6e
          typename Scalar>
Shinya Kitaoka 120a6e
void blur(const ImgIn &imgIn, ImgOut &imgOut, int radius, SelectorFunc selector,
Shinya Kitaoka 120a6e
          Scalar) {
Shinya Kitaoka 120a6e
  blurRows(imgIn, imgOut, radius, selector, Scalar);
Shinya Kitaoka 120a6e
  blurCols(imgOut, imgOut, radius, selector, Scalar);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
}
Shinya Kitaoka 120a6e
}  // namespace tcg::image_ops
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#endif  // TCG_IMAGE_OPS_HPP