shun-iwasawa e2505a
#pragma once
shun-iwasawa e2505a
shun-iwasawa e2505a
/*------------------------------------
shun-iwasawa e2505a
Iwa_BokehRefFx
shun-iwasawa e2505a
Apply an off-focus effect to a single source image.
shun-iwasawa e2505a
The amount of bokeh is specified by user input reference image,
shun-iwasawa e2505a
which represents the depth by brightness of pixels.
shun-iwasawa e2505a
It considers characteristics of films (which is known as Hurter–Driffield
shun-iwasawa e2505a
curves) or human eye's perception (which is known as Weber–Fechner law).
shun-iwasawa e2505a
For filtering process I used KissFFT, an FFT library by Mark Borgerding,
shun-iwasawa e2505a
distributed with a 3-clause BSD-style license.
shun-iwasawa e2505a
------------------------------------*/
shun-iwasawa e2505a
shun-iwasawa e2505a
#ifndef IWA_BOKEH_REF_H
shun-iwasawa e2505a
#define IWA_BOKEH_REF_H
shun-iwasawa e2505a
shun-iwasawa e2505a
#include "stdfx.h"
shun-iwasawa e2505a
#include "tfxparam.h"
shun-iwasawa e2505a
shun-iwasawa e2505a
#include <qvector></qvector>
shun-iwasawa e2505a
#include <qthread></qthread>
shun-iwasawa e2505a
shun-iwasawa e2505a
#include "tools/kiss_fftnd.h"
shun-iwasawa e2505a
shun-iwasawa e2505a
struct float4 {
shun-iwasawa e2505a
  float x, y, z, w;
shun-iwasawa e2505a
};
shun-iwasawa e2505a
shun-iwasawa e2505a
//------------------------------------
shun-iwasawa e2505a
shun-iwasawa e2505a
class BokehRefThread : public QThread {
shun-iwasawa e2505a
  int m_channel;
shun-iwasawa e2505a
  volatile bool m_finished;
shun-iwasawa e2505a
shun-iwasawa e2505a
  kiss_fft_cpx* m_fftcpx_channel_before;
shun-iwasawa e2505a
  kiss_fft_cpx* m_fftcpx_channel;
shun-iwasawa e2505a
  kiss_fft_cpx* m_fftcpx_alpha;
shun-iwasawa e2505a
  kiss_fft_cpx* m_fftcpx_iris;
shun-iwasawa e2505a
  float4* m_result_buff;
shun-iwasawa e2505a
shun-iwasawa e2505a
  kiss_fftnd_cfg m_kissfft_plan_fwd, m_kissfft_plan_bkwd;
shun-iwasawa e2505a
shun-iwasawa e2505a
  TDimensionI m_dim;
shun-iwasawa e2505a
  bool m_isTerminated;
shun-iwasawa e2505a
shun-iwasawa e2505a
public:
shun-iwasawa e2505a
  BokehRefThread(int channel, kiss_fft_cpx* fftcpx_channel_before,
shun-iwasawa e2505a
                 kiss_fft_cpx* fftcpx_channel, kiss_fft_cpx* fftcpx_alpha,
shun-iwasawa e2505a
                 kiss_fft_cpx* fftcpx_iris, float4* result_buff,
shun-iwasawa e2505a
                 kiss_fftnd_cfg kissfft_plan_fwd,
shun-iwasawa e2505a
                 kiss_fftnd_cfg kissfft_plan_bkwd, TDimensionI& dim);
shun-iwasawa e2505a
shun-iwasawa e2505a
  void run() override;
shun-iwasawa e2505a
shun-iwasawa e2505a
  bool isFinished() { return m_finished; }
shun-iwasawa e2505a
  void terminateThread() { m_isTerminated = true; }
shun-iwasawa e2505a
};
shun-iwasawa e2505a
shun-iwasawa e2505a
//------------------------------------
shun-iwasawa e2505a
shun-iwasawa e2505a
class Iwa_BokehRefFx : public TStandardRasterFx {
shun-iwasawa e2505a
  FX_PLUGIN_DECLARATION(Iwa_BokehRefFx)
shun-iwasawa e2505a
shun-iwasawa e2505a
protected:
shun-iwasawa e2505a
  TRasterFxPort m_iris;    // iris image
shun-iwasawa e2505a
  TRasterFxPort m_source;  // source image
shun-iwasawa e2505a
  TRasterFxPort m_depth;   // depth reference image
shun-iwasawa e2505a
shun-iwasawa e2505a
  TDoubleParamP m_onFocusDistance;  // Focus Distance (0-1)
shun-iwasawa e2505a
  TDoubleParamP m_bokehAmount;  // The maximum bokeh size. The size of bokeh at
shun-iwasawa e2505a
                                // the layer separated by 1.0 from the focal
shun-iwasawa e2505a
                                // position
shun-iwasawa e2505a
  TDoubleParamP m_hardness;     // Film gamma
shun-iwasawa e2505a
  TIntParamP m_distancePrecision;  // Separation of depth image
shun-iwasawa e2505a
shun-iwasawa e2505a
  TBoolParamP m_fillGap;  // Toggles whether to extend pixels behind the front
shun-iwasawa e2505a
                          // layers in order to fill gap
shun-iwasawa e2505a
  // It should be ON for normal backgrounds and should be OFF for the layer
shun-iwasawa e2505a
  // which is
shun-iwasawa e2505a
  // "floating" from the lower layers such as dust, snowflake or spider-web.
shun-iwasawa e2505a
  TBoolParamP m_doMedian;  // (Effective only when the Fill Gap option is ON)
shun-iwasawa e2505a
  // Toggles whether to use Median Filter for extending the pixels.
shun-iwasawa e2505a
shun-iwasawa e2505a
  // Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
shun-iwasawa e2505a
  float getBokehPixelAmount(const double frame, const TAffine affine);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // normalize the source raster image to 0-1 and set to dstMem
shun-iwasawa e2505a
  // returns true if the source is (seems to be) premultiplied
shun-iwasawa e2505a
  template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa e2505a
  bool setSourceRaster(const RASTER srcRas, float4* dstMem, TDimensionI dim);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // normalize brightness of the depth reference image to unsigned char
shun-iwasawa e2505a
  // and store into dstMem
shun-iwasawa e2505a
  template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa e2505a
  void setDepthRaster(const RASTER srcRas, unsigned char* dstMem,
shun-iwasawa e2505a
                      TDimensionI dim);
shun-iwasawa e2505a
  template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa e2505a
  void setDepthRasterGray(const RASTER srcRas, unsigned char* dstMem,
shun-iwasawa e2505a
                          TDimensionI dim);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // create the depth index map
shun-iwasawa e2505a
  void defineSegemntDepth(const unsigned char* indexMap_main,
shun-iwasawa e2505a
                          const unsigned char* indexMap_sub,
shun-iwasawa e2505a
                          const float* mainSub_ratio,
shun-iwasawa e2505a
                          const unsigned char* depth_buff,
shun-iwasawa e2505a
                          const TDimensionI& dimOut, const double frame,
shun-iwasawa e2505a
                          QVector<float>& segmentDepth_main,</float>
shun-iwasawa e2505a
                          QVector<float>& segmentDepth_sub);</float>
shun-iwasawa e2505a
shun-iwasawa e2505a
  // set the result
shun-iwasawa e2505a
  template <typename pixel="" raster,="" typename=""></typename>
shun-iwasawa e2505a
  void setOutputRaster(float4* srcMem, const RASTER dstRas, TDimensionI dim,
shun-iwasawa e2505a
                       TDimensionI margin);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // obtain iris size from the depth value
shun-iwasawa e2505a
  float calcIrisSize(const float depth, const float bokehPixelAmount,
shun-iwasawa e2505a
                     const double onFocusDistance);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // resize/invert the iris according to the size ratio
shun-iwasawa e2505a
  // normalize the brightness
shun-iwasawa e2505a
  // resize to the output size
shun-iwasawa e2505a
  void convertIris(const float irisSize, const TRectD& irisBBox,
shun-iwasawa e2505a
                   const TTile& irisTile, const TDimensionI& enlargedDim,
shun-iwasawa e2505a
                   kiss_fft_cpx* fftcpx_iris_before);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // convert source image value rgb -> exposure
shun-iwasawa e2505a
  void convertRGBToExposure(const float4* source_buff, int size,
shun-iwasawa e2505a
                            float filmGamma, bool sourceIsPremultiplied);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // generate the segment layer source at the current depth
shun-iwasawa e2505a
  // considering fillGap and doMedian options
shun-iwasawa e2505a
  void retrieveLayer(const float4* source_buff,
shun-iwasawa e2505a
                     const float4* segment_layer_buff,
shun-iwasawa e2505a
                     const unsigned char* indexMap_mainSub, int index, int lx,
shun-iwasawa e2505a
                     int ly, bool fillGap, bool doMedian, int margin);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // apply single median filter
shun-iwasawa e2505a
  void doSingleMedian(const float4* source_buff,
shun-iwasawa e2505a
                      const float4* segment_layer_buff,
shun-iwasawa e2505a
                      const unsigned char* indexMap_mainSub, int index, int lx,
shun-iwasawa e2505a
                      int ly, const unsigned char* generation_buff, int curGen);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // normal-composite the layer as is, without filtering
shun-iwasawa e2505a
  void compositeAsIs(const float4* segment_layer_buff,
shun-iwasawa e2505a
                     const float4* result_buff_mainSub, int size);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // retrieve segment layer image for each channel
shun-iwasawa e2505a
  void retrieveChannel(const float4* segment_layer_buff,  // src
shun-iwasawa e2505a
                       kiss_fft_cpx* fftcpx_r_before,     // dst
shun-iwasawa e2505a
                       kiss_fft_cpx* fftcpx_g_before,     // dst
shun-iwasawa e2505a
                       kiss_fft_cpx* fftcpx_b_before,     // dst
shun-iwasawa e2505a
                       kiss_fft_cpx* fftcpx_a_before,     // dst
shun-iwasawa e2505a
                       int size);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // multiply filter on channel
shun-iwasawa e2505a
  void multiplyFilter(kiss_fft_cpx* fftcpx_channel,  // dst
shun-iwasawa e2505a
                      kiss_fft_cpx* fftcpx_iris,     // filter
shun-iwasawa e2505a
                      int size);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // normal comosite the alpha channel
shun-iwasawa e2505a
  void compositeAlpha(const float4* result_buff,         // dst
shun-iwasawa e2505a
                      const kiss_fft_cpx* fftcpx_alpha,  // alpha
shun-iwasawa e2505a
                      int lx, int ly);
shun-iwasawa e2505a
shun-iwasawa e2505a
  // interpolate main and sub exposures
shun-iwasawa e2505a
  // convert exposure -> RGB (0-1)
shun-iwasawa e2505a
  // set to the result
shun-iwasawa e2505a
  void interpolateExposureAndConvertToRGB(
shun-iwasawa e2505a
      const float4* result_main_buff,  // result1
shun-iwasawa e2505a
      const float4* result_sub_buff,   // result2
shun-iwasawa e2505a
      const float* mainSub_ratio,      // ratio
shun-iwasawa e2505a
      float filmGamma,
shun-iwasawa e2505a
      const float4* source_buff,  // dst
shun-iwasawa e2505a
      int size);
shun-iwasawa e2505a
shun-iwasawa e2505a
public:
shun-iwasawa e2505a
  Iwa_BokehRefFx();
shun-iwasawa e2505a
shun-iwasawa e2505a
  void doCompute(TTile& tile, double frame, const TRenderSettings& settings);
shun-iwasawa e2505a
shun-iwasawa e2505a
  bool doGetBBox(double frame, TRectD& bBox, const TRenderSettings& info);
shun-iwasawa e2505a
shun-iwasawa e2505a
  bool canHandle(const TRenderSettings& info, double frame);
shun-iwasawa e2505a
shun-iwasawa e2505a
  void doCompute_CPU(const double frame, const TRenderSettings& settings,
shun-iwasawa e2505a
                     float bokehPixelAmount, float maxIrisSize, int margin,
shun-iwasawa e2505a
                     TDimensionI& dimOut, float4* source_buff,
shun-iwasawa e2505a
                     unsigned char* indexMap_main, unsigned char* indexMap_sub,
shun-iwasawa e2505a
                     float* mainSub_ratio, QVector<float>& segmentDepth_main,</float>
shun-iwasawa e2505a
                     QVector<float>& segmentDepth_sub, TTile& irisTile,</float>
shun-iwasawa e2505a
                     TRectD& irisBBox, bool sourceIsPremultiplied);
shun-iwasawa e2505a
};
shun-iwasawa e2505a
shun-iwasawa e2505a
#endif