shun-iwasawa 021eef
#include "iwa_bloomfx.h"
shun-iwasawa 021eef
shun-iwasawa 021eef
#include "tparamuiconcept.h"
shun-iwasawa 021eef
shun-iwasawa 021eef
#include <qvector></qvector>
shun-iwasawa 021eef
#include <qpair></qpair>
shun-iwasawa 021eef
shun-iwasawa 021eef
namespace {
shun-iwasawa 021eef
// convert sRGB color space to power space
shun-iwasawa 021eef
template <typename t="double"></typename>
shun-iwasawa 021eef
inline T to_linear_color_space(T nonlinear_color, T exposure, T gamma) {
shun-iwasawa 481b59
  if (nonlinear_color <= T(0)) return T(0);
shun-iwasawa 021eef
  return std::pow(nonlinear_color, gamma) / exposure;
shun-iwasawa 021eef
}
shun-iwasawa 021eef
// convert power space to sRGB color space
shun-iwasawa 021eef
template <typename t="double"></typename>
shun-iwasawa 021eef
inline T to_nonlinear_color_space(T linear_color, T exposure, T gamma) {
shun-iwasawa 481b59
  if (linear_color <= T(0)) return T(0);
shun-iwasawa 021eef
  return std::pow(linear_color * exposure, T(1) / gamma);
shun-iwasawa 021eef
}
shun-iwasawa 021eef
template <class t="double"></class>
shun-iwasawa 021eef
const T &clamp(const T &v, const T &lo, const T &hi) {
shun-iwasawa 021eef
  assert(!(hi < lo));
shun-iwasawa 021eef
  return (v < lo) ? lo : (hi < v) ? hi : v;
shun-iwasawa 021eef
}
shun-iwasawa 021eef
shun-iwasawa 021eef
void blurByRotate(cv::Mat &mat) {
shun-iwasawa 021eef
  double angle = 45.0;
shun-iwasawa 021eef
shun-iwasawa 021eef
  int size   = std::ceil(std::sqrt(mat.cols * mat.cols + mat.rows * mat.rows));
shun-iwasawa 021eef
  int width  = ((size - mat.cols) % 2 == 0) ? size : size + 1;
shun-iwasawa 021eef
  int height = ((size - mat.rows) % 2 == 0) ? size : size + 1;
shun-iwasawa 021eef
shun-iwasawa 021eef
  cv::Point2f center((mat.cols - 1) / 2.0, (mat.rows - 1) / 2.0);
shun-iwasawa 021eef
shun-iwasawa 021eef
  cv::Mat rot = cv::getRotationMatrix2D(center, angle, 1.0);
shun-iwasawa 021eef
  rot.at<double>(0, 2) += (width - mat.cols) / 2.0;</double>
shun-iwasawa 021eef
  rot.at<double>(1, 2) += (height - mat.rows) / 2.0;</double>
shun-iwasawa 021eef
shun-iwasawa 021eef
  cv::Mat tmp;
shun-iwasawa 021eef
  cv::warpAffine(mat, tmp, rot, cv::Size(width, height));
shun-iwasawa 021eef
shun-iwasawa 021eef
  center = cv::Point2f((width - 1) / 2.0, (height - 1) / 2.0);
shun-iwasawa 021eef
  rot    = cv::getRotationMatrix2D(center, -angle, 1.0);
shun-iwasawa 021eef
  rot.at<double>(0, 2) += (mat.cols - width) / 2.0;</double>
shun-iwasawa 021eef
  rot.at<double>(1, 2) += (mat.rows - height) / 2.0;</double>
shun-iwasawa 021eef
shun-iwasawa 021eef
  cv::warpAffine(tmp, mat, rot, mat.size());
shun-iwasawa 021eef
}
shun-iwasawa 021eef
shun-iwasawa 021eef
}  // namespace
shun-iwasawa 021eef
shun-iwasawa 021eef
//--------------------------------------------
shun-iwasawa 021eef
// Iwa_BloomFx
shun-iwasawa 021eef
//--------------------------------------------
shun-iwasawa 021eef
Iwa_BloomFx::Iwa_BloomFx()
shun-iwasawa d76928
    : m_gamma(2.2)
shun-iwasawa 481b59
    , m_gammaAdjust(0.)
shun-iwasawa d76928
    , m_auto_gain(false)
shun-iwasawa d76928
    , m_gain_adjust(0.0)
shun-iwasawa d76928
    , m_gain(2.0)
shun-iwasawa d76928
    , m_decay(1)
shun-iwasawa d76928
    , m_size(100.0)
shun-iwasawa d76928
    , m_alpha_rendering(false)
shun-iwasawa d76928
    , m_alpha_mode(new TIntEnumParam(NoAlpha, "No Alpha")) {
shun-iwasawa 021eef
  addInputPort("Source", m_source);
shun-iwasawa 021eef
  bindParam(this, "gamma", m_gamma);
shun-iwasawa 481b59
  bindParam(this, "gammaAdjust", m_gammaAdjust);
shun-iwasawa d76928
  bindParam(this, "auto_gain", m_auto_gain);
shun-iwasawa d76928
  bindParam(this, "gain_adjust", m_gain_adjust);
shun-iwasawa 021eef
  bindParam(this, "gain", m_gain);
shun-iwasawa d76928
  bindParam(this, "decay", m_decay);
shun-iwasawa 021eef
  bindParam(this, "size", m_size);
shun-iwasawa d76928
  bindParam(this, "alpha_mode", m_alpha_mode);
shun-iwasawa d76928
  bindParam(this, "alpha_rendering", m_alpha_rendering, false,
shun-iwasawa d76928
            true);  // obsolete
shun-iwasawa d76928
shun-iwasawa d76928
  m_alpha_mode->addItem(Light, "Light");
shun-iwasawa d76928
  m_alpha_mode->addItem(LightAndSource, "Light and Source");
shun-iwasawa 021eef
shun-iwasawa 021eef
  m_gamma->setValueRange(0.1, 5.0);
shun-iwasawa 481b59
  m_gammaAdjust->setValueRange(-5., 5.);
shun-iwasawa d76928
  m_gain_adjust->setValueRange(-1.0, 1.0);
shun-iwasawa 021eef
  m_gain->setValueRange(0.1, 10.0);
shun-iwasawa d76928
  m_decay->setValueRange(0, 4);
shun-iwasawa 021eef
  m_size->setValueRange(0.1, 1024.0);
shun-iwasawa 021eef
shun-iwasawa 021eef
  m_size->setMeasureName("fxLength");
shun-iwasawa 481b59
shun-iwasawa 481b59
  enableComputeInFloat(true);
shun-iwasawa 481b59
shun-iwasawa 481b59
  // Version 1 : gaussian filter applied with standard deviation 0
shun-iwasawa 481b59
  // Version 2 : standard deviation = blurRadius * 0.3
shun-iwasawa 481b59
  // Version 3: Gamma is computed by rs.m_colorSpaceGamma + gammaAdjust
shun-iwasawa 481b59
  setFxVersion(3);
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
double Iwa_BloomFx::getSizePixelAmount(const double val, const TAffine affine) {
shun-iwasawa 021eef
  /*--- Convert to vector --- */
shun-iwasawa 021eef
  TPointD vect;
shun-iwasawa 021eef
  vect.x = val;
shun-iwasawa 021eef
  vect.y = 0.0;
shun-iwasawa 021eef
  /*--- Apply geometrical transformation ---*/
shun-iwasawa 021eef
  // For the following lines I referred to lines 586-592 of
shun-iwasawa 021eef
  // sources/stdfx/motionblurfx.cpp
shun-iwasawa 021eef
  TAffine aff(affine);
shun-iwasawa 021eef
  aff.a13 = aff.a23 = 0; /* ignore translation */
shun-iwasawa 021eef
  vect              = aff * vect;
shun-iwasawa 021eef
  /*--- return the length of the vector ---*/
shun-iwasawa 021eef
  return sqrt(vect.x * vect.x + vect.y * vect.y);
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 021eef
void Iwa_BloomFx::setSourceTileToMat(const RASTER ras, cv::Mat &imgMat,
shun-iwasawa 021eef
                                     const double gamma) {
shun-iwasawa 481b59
  double maxi = static_cast<double>(PIXEL::maxChannelValue);  // 255or65535or1.0</double>
shun-iwasawa 021eef
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa 021eef
    const PIXEL *pix = ras->pixels(j);
shun-iwasawa 021eef
    cv::Vec3f *mat_p = imgMat.ptr<cv::vec3f>(j);</cv::vec3f>
shun-iwasawa 021eef
    for (int i = 0; i < ras->getLx(); i++, pix++, mat_p++) {
shun-iwasawa 021eef
      double pix_a = static_cast<double>(pix->m) / maxi;</double>
shun-iwasawa 021eef
      if (pix_a <= 0.0) {
shun-iwasawa 021eef
        *mat_p = cv::Vec3f(0, 0, 0);
shun-iwasawa 021eef
        continue;
shun-iwasawa 021eef
      }
shun-iwasawa 021eef
      double bgra[3];
shun-iwasawa 481b59
      if (areAlmostEqual(gamma, 1.0)) {
shun-iwasawa 481b59
        bgra[0] = static_cast<double>(pix->b) / maxi;</double>
shun-iwasawa 481b59
        bgra[1] = static_cast<double>(pix->g) / maxi;</double>
shun-iwasawa 481b59
        bgra[2] = static_cast<double>(pix->r) / maxi;</double>
shun-iwasawa 481b59
      } else {
shun-iwasawa 481b59
        bgra[0] = static_cast<double>(pix->b) / maxi;</double>
shun-iwasawa 481b59
        bgra[1] = static_cast<double>(pix->g) / maxi;</double>
shun-iwasawa 481b59
        bgra[2] = static_cast<double>(pix->r) / maxi;</double>
shun-iwasawa 481b59
        for (int c = 0; c < 3; c++) {
shun-iwasawa 481b59
          // assuming that the source image is premultiplied
shun-iwasawa 481b59
          bgra[c] = to_linear_color_space(bgra[c] / pix_a, 1.0, gamma) * pix_a;
shun-iwasawa 481b59
        }
shun-iwasawa 021eef
      }
shun-iwasawa 021eef
      *mat_p = cv::Vec3f(bgra[0], bgra[1], bgra[2]);
shun-iwasawa 021eef
    }
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa 021eef
void Iwa_BloomFx::setMatToOutput(const RASTER ras, const RASTER srcRas,
shun-iwasawa d76928
                                 cv::Mat &imgMat, const double gamma,
shun-iwasawa d76928
                                 const double gain, const AlphaMode alphaMode,
shun-iwasawa 021eef
                                 const int margin) {
shun-iwasawa 021eef
  double maxi = static_cast<double>(PIXEL::maxChannelValue);  // 255or65535</double>
shun-iwasawa 021eef
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa d76928
    cv::Vec3f const *mat_p = imgMat.ptr<cv::vec3f>(j);</cv::vec3f>
shun-iwasawa 021eef
    PIXEL *pix             = ras->pixels(j);
shun-iwasawa 021eef
    PIXEL *srcPix          = srcRas->pixels(j + margin) + margin;
shun-iwasawa 021eef
shun-iwasawa 021eef
    for (int i = 0; i < ras->getLx(); i++, pix++, srcPix++, mat_p++) {
shun-iwasawa 481b59
      double nonlinear_b, nonlinear_g, nonlinear_r;
shun-iwasawa 481b59
      if (areAlmostEqual(gamma, 1.)) {
shun-iwasawa 481b59
        nonlinear_b = (double)(*mat_p)[0] * gain;
shun-iwasawa 481b59
        nonlinear_g = (double)(*mat_p)[1] * gain;
shun-iwasawa 481b59
        nonlinear_r = (double)(*mat_p)[2] * gain;
shun-iwasawa 481b59
      } else {
shun-iwasawa 481b59
        nonlinear_b =
shun-iwasawa 481b59
            to_nonlinear_color_space((double)(*mat_p)[0] * gain, 1.0, gamma);
shun-iwasawa 481b59
        nonlinear_g =
shun-iwasawa 481b59
            to_nonlinear_color_space((double)(*mat_p)[1] * gain, 1.0, gamma);
shun-iwasawa 481b59
        nonlinear_r =
shun-iwasawa 481b59
            to_nonlinear_color_space((double)(*mat_p)[2] * gain, 1.0, gamma);
shun-iwasawa 481b59
      }
shun-iwasawa 021eef
shun-iwasawa 021eef
      nonlinear_b = clamp(nonlinear_b, 0.0, 1.0);
shun-iwasawa 021eef
      nonlinear_g = clamp(nonlinear_g, 0.0, 1.0);
shun-iwasawa 021eef
      nonlinear_r = clamp(nonlinear_r, 0.0, 1.0);
shun-iwasawa 021eef
shun-iwasawa 021eef
      pix->r = (typename PIXEL::Channel)(nonlinear_r * (maxi + 0.999999));
shun-iwasawa 021eef
      pix->g = (typename PIXEL::Channel)(nonlinear_g * (maxi + 0.999999));
shun-iwasawa 021eef
      pix->b = (typename PIXEL::Channel)(nonlinear_b * (maxi + 0.999999));
shun-iwasawa d76928
      if (alphaMode == NoAlpha)
shun-iwasawa d76928
        pix->m = (typename PIXEL::Channel)(PIXEL::maxChannelValue);
shun-iwasawa d76928
      else {
shun-iwasawa 021eef
        double chan_a =
shun-iwasawa 021eef
            std::max(std::max(nonlinear_b, nonlinear_g), nonlinear_r);
shun-iwasawa d76928
        if (alphaMode == Light)
shun-iwasawa d76928
          pix->m = (typename PIXEL::Channel)(chan_a * (maxi + 0.999999));
shun-iwasawa d76928
        else  // alphaMode == LightAndSource
shun-iwasawa d76928
          pix->m = std::max(
shun-iwasawa d76928
              (typename PIXEL::Channel)(chan_a * (maxi + 0.999999)), srcPix->m);
shun-iwasawa d76928
      }
shun-iwasawa d76928
    }
shun-iwasawa d76928
  }
shun-iwasawa d76928
}
shun-iwasawa d76928
shun-iwasawa 481b59
template <>
shun-iwasawa 481b59
void Iwa_BloomFx::setMatToOutput<trasterfp, tpixelf="">(</trasterfp,>
shun-iwasawa 481b59
    const TRasterFP ras, const TRasterFP srcRas, cv::Mat &imgMat,
shun-iwasawa 481b59
    const double gamma, const double gain, const AlphaMode alphaMode,
shun-iwasawa 481b59
    const int margin) {
shun-iwasawa 481b59
  for (int j = 0; j < ras->getLy(); j++) {
shun-iwasawa 481b59
    cv::Vec3f const *mat_p = imgMat.ptr<cv::vec3f>(j);</cv::vec3f>
shun-iwasawa 481b59
    TPixelF *pix           = ras->pixels(j);
shun-iwasawa 481b59
    TPixelF *srcPix        = srcRas->pixels(j + margin) + margin;
shun-iwasawa 481b59
shun-iwasawa 481b59
    for (int i = 0; i < ras->getLx(); i++, pix++, srcPix++, mat_p++) {
shun-iwasawa 481b59
      if (areAlmostEqual(gamma, 1.)) {
shun-iwasawa 481b59
        pix->b = (*mat_p)[0] * (float)gain;
shun-iwasawa 481b59
        pix->g = (*mat_p)[1] * (float)gain;
shun-iwasawa 481b59
        pix->r = (*mat_p)[2] * (float)gain;
shun-iwasawa 481b59
      } else {
shun-iwasawa 481b59
        pix->b = to_nonlinear_color_space((*mat_p)[0] * (float)gain, 1.f,
shun-iwasawa 481b59
                                          (float)gamma);
shun-iwasawa 481b59
        pix->g = to_nonlinear_color_space((*mat_p)[1] * (float)gain, 1.f,
shun-iwasawa 481b59
                                          (float)gamma);
shun-iwasawa 481b59
        pix->r = to_nonlinear_color_space((*mat_p)[2] * (float)gain, 1.f,
shun-iwasawa 481b59
                                          (float)gamma);
shun-iwasawa 481b59
      }
shun-iwasawa 481b59
shun-iwasawa 481b59
      if (alphaMode == NoAlpha)
shun-iwasawa 481b59
        pix->m = 1.f;
shun-iwasawa 481b59
      else {
shun-iwasawa 481b59
        float chan_a = std::max(std::max(pix->b, pix->g), pix->r);
shun-iwasawa 481b59
        if (alphaMode == Light)
shun-iwasawa 481b59
          pix->m = chan_a;
shun-iwasawa 481b59
        else  // alphaMode == LightAndSource
shun-iwasawa 481b59
          pix->m = std::max(chan_a, srcPix->m);
shun-iwasawa 481b59
      }
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
}
shun-iwasawa 481b59
shun-iwasawa d76928
//------------------------------------------------
shun-iwasawa d76928
shun-iwasawa d76928
double Iwa_BloomFx::computeAutoGain(cv::Mat &imgMat) {
shun-iwasawa d76928
  double maxChanelValue = 0.0;
shun-iwasawa d76928
  for (int j = 0; j < imgMat.size().height; j++) {
shun-iwasawa d76928
    cv::Vec3f const *mat_p = imgMat.ptr<cv::vec3f>(j);</cv::vec3f>
shun-iwasawa d76928
    for (int i = 0; i < imgMat.size().width; i++, mat_p++) {
shun-iwasawa d76928
      for (int c = 0; c < 3; c++)
shun-iwasawa d76928
        maxChanelValue = std::max(maxChanelValue, (double)(*mat_p)[c]);
shun-iwasawa 021eef
    }
shun-iwasawa 021eef
  }
shun-iwasawa d76928
shun-iwasawa d76928
  if (maxChanelValue == 0.0) return 1.0;
shun-iwasawa d76928
shun-iwasawa d76928
  return 1.0 / maxChanelValue;
shun-iwasawa 021eef
}
shun-iwasawa 021eef
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
void Iwa_BloomFx::doCompute(TTile &tile, double frame,
shun-iwasawa 021eef
                            const TRenderSettings &settings) {
shun-iwasawa 021eef
  // If the source is not connected, then do nothing
shun-iwasawa 021eef
  if (!m_source.isConnected()) {
shun-iwasawa 021eef
    tile.getRaster()->clear();
shun-iwasawa 021eef
    return;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  // obtain parameters
shun-iwasawa 481b59
  double gamma;
shun-iwasawa 481b59
  if (getFxVersion() <= 2)
shun-iwasawa 481b59
    gamma = m_gamma->getValue(frame);
shun-iwasawa 481b59
  else
shun-iwasawa 481b59
    gamma = std::max(
shun-iwasawa 481b59
        1., settings.m_colorSpaceGamma + m_gammaAdjust->getValue(frame));
shun-iwasawa 481b59
  double adjustGamma = gamma;
shun-iwasawa 481b59
  if (tile.getRaster()->isLinear()) gamma /= settings.m_colorSpaceGamma;
shun-iwasawa 481b59
shun-iwasawa d76928
  bool autoGain = m_auto_gain->getValue();
shun-iwasawa d76928
  double gainAdjust =
shun-iwasawa d76928
      (autoGain) ? std::pow(10.0, m_gain_adjust->getValue(frame)) : 1.0;
shun-iwasawa d76928
  double gain    = (autoGain) ? 1.0 : m_gain->getValue(frame);
shun-iwasawa d76928
  int blurRadius = (int)std::round(m_decay->getValue(frame));
shun-iwasawa d76928
  double size = getSizePixelAmount(m_size->getValue(frame), settings.m_affine);
shun-iwasawa d76928
  AlphaMode alphaMode = (AlphaMode)m_alpha_mode->getValue();
shun-iwasawa 021eef
shun-iwasawa 021eef
  int margin = static_cast<int>(std::ceil(size));</int>
shun-iwasawa 021eef
  TRectD _rect(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
shun-iwasawa 021eef
                                       tile.getRaster()->getLy()));
shun-iwasawa 021eef
  _rect = _rect.enlarge(static_cast<double>(margin));</double>
shun-iwasawa 021eef
  TDimensionI dimSrc(static_cast<int>(_rect.getLx() + 0.5),</int>
shun-iwasawa 021eef
                     static_cast<int>(_rect.getLy() + 0.5));</int>
shun-iwasawa 021eef
shun-iwasawa 021eef
  // obtain the source tile
shun-iwasawa 021eef
  TTile sourceTile;
shun-iwasawa 021eef
  m_source->allocateAndCompute(sourceTile, _rect.getP00(), dimSrc,
shun-iwasawa 021eef
                               tile.getRaster(), frame, settings);
shun-iwasawa 021eef
shun-iwasawa 021eef
  // set the source image to cvMat, converting to linear color space
shun-iwasawa 021eef
  cv::Mat imgMat(cv::Size(dimSrc.lx, dimSrc.ly), CV_32FC3);
shun-iwasawa 021eef
  TRaster32P ras32 = tile.getRaster();
shun-iwasawa 021eef
  TRaster64P ras64 = tile.getRaster();
shun-iwasawa 481b59
  TRasterFP rasF   = tile.getRaster();
shun-iwasawa 021eef
  if (ras32)
shun-iwasawa 021eef
    setSourceTileToMat<traster32p, tpixel32="">(sourceTile.getRaster(), imgMat,</traster32p,>
shun-iwasawa 021eef
                                             gamma);
shun-iwasawa 021eef
  else if (ras64)
shun-iwasawa 021eef
    setSourceTileToMat<traster64p, tpixel64="">(sourceTile.getRaster(), imgMat,</traster64p,>
shun-iwasawa 021eef
                                             gamma);
shun-iwasawa 481b59
  else if (rasF)
shun-iwasawa 481b59
    setSourceTileToMat<trasterfp, tpixelf="">(sourceTile.getRaster(), imgMat,</trasterfp,>
shun-iwasawa 481b59
                                           gamma);
shun-iwasawa 021eef
shun-iwasawa 021eef
  // compute size and intensity ratios of resampled layers
shun-iwasawa 021eef
  // resample size is reduced from the specified size, taking into account
shun-iwasawa 021eef
  // that the gaussian blur (x 2) and the blur by rotation resampling (x sqrt2)
shun-iwasawa d76928
  double blurScale    = 1.0 + (double)blurRadius;
shun-iwasawa d76928
  double no_blur_size = size / (blurScale * 1.5);
luz paz 6454c4
  // find the minimum "power of 2" value which is the same as or larger than the
shun-iwasawa 021eef
  // filter size
shun-iwasawa 021eef
  int level         = 1;
shun-iwasawa 021eef
  double power_of_2 = 1.0;
shun-iwasawa 021eef
  while (1) {
shun-iwasawa 021eef
    if (power_of_2 >= no_blur_size) break;
shun-iwasawa 021eef
    level++;
shun-iwasawa d76928
    power_of_2 *= 2;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  // store the size of resampled layers
shun-iwasawa 021eef
  QVector<cv::size> sizes;</cv::size>
shun-iwasawa 021eef
  double tmp_filterSize = no_blur_size;
shun-iwasawa 021eef
  double width          = static_cast<double>(imgMat.size().width);</double>
shun-iwasawa 021eef
  double height         = static_cast<double>(imgMat.size().height);</double>
shun-iwasawa 021eef
  for (int lvl = 0; lvl < level - 1; lvl++) {
shun-iwasawa 021eef
    int tmp_w = static_cast<int>(std::ceil(width / tmp_filterSize));</int>
shun-iwasawa 021eef
    int tmp_h = static_cast<int>(std::ceil(height / tmp_filterSize));</int>
shun-iwasawa 021eef
    sizes.push_front(cv::Size(tmp_w, tmp_h));
shun-iwasawa 021eef
    tmp_filterSize *= 0.5;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  sizes.push_front(imgMat.size());
shun-iwasawa 021eef
shun-iwasawa 021eef
  // the filter is based on the nearest power-of-2 sized one with an adjustment
shun-iwasawa 021eef
  // reducing the sizes and increasing the intensity with this ratio
shun-iwasawa 021eef
  double ratio = power_of_2 / no_blur_size;
shun-iwasawa 021eef
  // base filter sizes will be 1, 2, 4, ... 2^(level-1)
shun-iwasawa 021eef
  // intensity of the filter with sizes > 2
shun-iwasawa 021eef
  double intensity_all = power_of_2 / (power_of_2 * 2.0 - 1.0);
shun-iwasawa 021eef
  // intensity of the filter with size 1, so that the amount of the filter at
shun-iwasawa 021eef
  // the center point is always 1.0
shun-iwasawa 021eef
  double intensity_front = 1.0 - (1.0 - intensity_all) * ratio;
shun-iwasawa 021eef
shun-iwasawa 021eef
  std::vector<cv::mat> dst(level);</cv::mat>
shun-iwasawa d76928
  cv::Size const ksize(1 + blurRadius * 2, 1 + blurRadius * 2);
shun-iwasawa d76928
  // standard deviation
shun-iwasawa d76928
  double sdRatio = (getFxVersion() == 1) ? 0.0 : 0.3;
shun-iwasawa 021eef
shun-iwasawa 021eef
  cv::Mat tmp;
shun-iwasawa 021eef
  int i;
shun-iwasawa 021eef
  // for each level of filter (from larger to smaller)
shun-iwasawa 021eef
  for (i = 0; i < level;) {
shun-iwasawa 021eef
    // scaling down the size
shun-iwasawa 021eef
    if (i) {
shun-iwasawa 021eef
      cv::resize(imgMat, tmp, sizes[i], 0.0, 0.0, cv::INTER_AREA);
shun-iwasawa 021eef
      imgMat = tmp;
shun-iwasawa 021eef
    }
shun-iwasawa 021eef
    // gaussian blur
shun-iwasawa d76928
    if (blurRadius == 0)
shun-iwasawa d76928
      dst[i] = imgMat;
shun-iwasawa d76928
    else
shun-iwasawa d76928
      cv::GaussianBlur(imgMat, dst[i], ksize, (double)blurRadius * sdRatio);
shun-iwasawa 021eef
    ++i;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  // for each level of filter (from smaller to larger)
shun-iwasawa 021eef
  for (--i; i > 0; --i) {
shun-iwasawa 021eef
    // scaling up the size
shun-iwasawa 021eef
    cv::resize(dst[i], tmp, dst[i - 1].size());
shun-iwasawa 021eef
    // blur by rotational resampling in order to reduce box-shaped artifact
shun-iwasawa 021eef
    blurByRotate(tmp);
shun-iwasawa 021eef
    // add to the upper resampled image
shun-iwasawa 021eef
    if (i > 1)
shun-iwasawa 021eef
      dst[i - 1] += tmp;
shun-iwasawa 021eef
    else
shun-iwasawa 021eef
      imgMat = dst[0] * intensity_front + tmp * intensity_all;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
shun-iwasawa 021eef
  // get the subimage without margin
shun-iwasawa 021eef
  cv::Rect roi(cv::Point(margin, margin),
shun-iwasawa 021eef
               cv::Size(tile.getRaster()->getLx(), tile.getRaster()->getLy()));
shun-iwasawa 021eef
  imgMat = imgMat(roi);
shun-iwasawa 021eef
shun-iwasawa d76928
  if (autoGain) {
shun-iwasawa 481b59
    gain = to_linear_color_space(gainAdjust, 1.0, adjustGamma) *
shun-iwasawa 481b59
           computeAutoGain(imgMat);
shun-iwasawa d76928
  }
shun-iwasawa d76928
shun-iwasawa 021eef
  // set the result to the tile, converting to rgb channel values
shun-iwasawa 021eef
  if (ras32)
shun-iwasawa 021eef
    setMatToOutput<traster32p, tpixel32="">(tile.getRaster(),</traster32p,>
shun-iwasawa 021eef
                                         sourceTile.getRaster(), imgMat, gamma,
shun-iwasawa d76928
                                         gain, alphaMode, margin);
shun-iwasawa 021eef
  else if (ras64)
shun-iwasawa 021eef
    setMatToOutput<traster64p, tpixel64="">(tile.getRaster(),</traster64p,>
shun-iwasawa 021eef
                                         sourceTile.getRaster(), imgMat, gamma,
shun-iwasawa d76928
                                         gain, alphaMode, margin);
shun-iwasawa 481b59
  else if (rasF)
shun-iwasawa 481b59
    setMatToOutput<trasterfp, tpixelf="">(tile.getRaster(), sourceTile.getRaster(),</trasterfp,>
shun-iwasawa 481b59
                                       imgMat, gamma, gain, alphaMode, margin);
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
bool Iwa_BloomFx::doGetBBox(double frame, TRectD &bBox,
shun-iwasawa 021eef
                            const TRenderSettings &info) {
shun-iwasawa 021eef
  if (!m_source.isConnected()) {
shun-iwasawa 021eef
    bBox = TRectD();
shun-iwasawa 021eef
    return false;
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  bool ret   = m_source->doGetBBox(frame, bBox, info);
shun-iwasawa 021eef
  int margin = static_cast<int>(</int>
shun-iwasawa 021eef
      std::ceil(getSizePixelAmount(m_size->getValue(frame), info.m_affine)));
shun-iwasawa 021eef
  if (margin > 0) {
shun-iwasawa 021eef
    bBox = bBox.enlarge(static_cast<double>(margin));</double>
shun-iwasawa 021eef
  }
shun-iwasawa 021eef
  return ret;
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
bool Iwa_BloomFx::canHandle(const TRenderSettings &info, double frame) {
shun-iwasawa 021eef
  return false;
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 021eef
void Iwa_BloomFx::getParamUIs(TParamUIConcept *&concepts, int &length) {
shun-iwasawa 021eef
  concepts = new TParamUIConcept[length = 1];
shun-iwasawa 021eef
shun-iwasawa 021eef
  concepts[0].m_type  = TParamUIConcept::RADIUS;
shun-iwasawa 021eef
  concepts[0].m_label = "Size";
shun-iwasawa 021eef
  concepts[0].m_params.push_back(m_size);
shun-iwasawa 021eef
}
shun-iwasawa 021eef
//------------------------------------------------
shun-iwasawa d76928
// This will be called in TFx::loadData when obsolete "alpha rendering" value is
shun-iwasawa d76928
// loaded
shun-iwasawa d76928
void Iwa_BloomFx::onObsoleteParamLoaded(const std::string ¶mName) {
shun-iwasawa d76928
  if (paramName != "alpha_rendering") return;
shun-iwasawa 481b59
shun-iwasawa 481b59
  // this condition is to prevent overwriting the alpha mode parameter
shun-iwasawa 481b59
  // when both "alpha rendering" and "alpha mode" are saved in the scene
shun-iwasawa 481b59
  // due to the previous bug
shun-iwasawa 481b59
  if (m_alpha_mode->getValue() != NoAlpha) return;
shun-iwasawa 481b59
shun-iwasawa d76928
  if (m_alpha_rendering->getValue())
shun-iwasawa d76928
    m_alpha_mode->setValue(LightAndSource);
shun-iwasawa d76928
  else
shun-iwasawa d76928
    m_alpha_mode->setValue(NoAlpha);
shun-iwasawa d76928
}
shun-iwasawa d76928
//------------------------------------------------
shun-iwasawa 021eef
shun-iwasawa 481b59
void Iwa_BloomFx::onFxVersionSet() {
shun-iwasawa 481b59
  bool useGamma = getFxVersion() <= 2;
shun-iwasawa 481b59
  if (getFxVersion() == 2) {
shun-iwasawa 481b59
    // Automatically update version
shun-iwasawa 481b59
    if (m_gamma->getKeyframeCount() == 0 &&
shun-iwasawa 481b59
        areAlmostEqual(m_gamma->getDefaultValue(), 2.2)) {
shun-iwasawa 481b59
      useGamma = false;
shun-iwasawa 481b59
      setFxVersion(3);
shun-iwasawa 481b59
    }
shun-iwasawa 481b59
  }
shun-iwasawa 481b59
  getParams()->getParamVar("gamma")->setIsHidden(!useGamma);
shun-iwasawa 481b59
  getParams()->getParamVar("gammaAdjust")->setIsHidden(useGamma);
shun-iwasawa 481b59
}
shun-iwasawa 481b59
shun-iwasawa 481b59
//------------------------------------------------
shun-iwasawa 481b59
shun-iwasawa 481b59
bool Iwa_BloomFx::toBeComputedInLinearColorSpace(bool settingsIsLinear,
shun-iwasawa 481b59
                                                 bool tileIsLinear) const {
shun-iwasawa 481b59
  // made this effect to compute always in nonlinear
shun-iwasawa 481b59
  return false;
shun-iwasawa 481b59
  // return tileIsLinear;
shun-iwasawa 481b59
}
shun-iwasawa 481b59
shun-iwasawa 481b59
//------------------------------------------------
shun-iwasawa 021eef
FX_PLUGIN_IDENTIFIER(Iwa_BloomFx, "iwa_BloomFx")