shun-iwasawa 1b1839
#pragma once
shun-iwasawa 1b1839
shun-iwasawa 1b1839
#ifndef IWA_BOKEH_UTIL_H
shun-iwasawa 1b1839
#define IWA_BOKEH_UTIL_H
shun-iwasawa 1b1839
shun-iwasawa 1b1839
#include "tgeometry.h"
shun-iwasawa 1b1839
#include "traster.h"
shun-iwasawa 1b1839
#include "kiss_fft.h"
shun-iwasawa 1b1839
#include "tools/kiss_fftnd.h"
shun-iwasawa 1b1839
#include "ttile.h"
shun-iwasawa 1b1839
#include "stdfx.h"
shun-iwasawa 1b1839
#include "tfxparam.h"
shun-iwasawa 1b1839
shun-iwasawa 1b1839
#include <QThread>
shun-iwasawa 1b1839
#include <QVector>
shun-iwasawa 1b1839
shun-iwasawa 1b1839
struct double4 {
shun-iwasawa 1b1839
  double x, y, z, w;
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
struct double2 {
shun-iwasawa 1b1839
  double x, y;
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
struct int2 {
shun-iwasawa 1b1839
  int x, y;
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
namespace BokehUtils {
shun-iwasawa 1b1839
shun-iwasawa 1b1839
//------------------------------------
shun-iwasawa 1b1839
shun-iwasawa 1b1839
class MyThread : public QThread {
shun-iwasawa 1b1839
public:
shun-iwasawa 1b1839
  enum Channel { Red = 0, Green, Blue };
shun-iwasawa 1b1839
shun-iwasawa 1b1839
private:
shun-iwasawa 1b1839
  int m_channel;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  volatile bool m_finished;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  TRasterP m_layerTileRas;
shun-iwasawa 1b1839
  double4* m_result;
shun-iwasawa 1b1839
  double* m_alpha_bokeh;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  kiss_fft_cpx* m_kissfft_comp_iris;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  double m_layerHardness;
shun-iwasawa 1b1839
  double m_masterHardness;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  TRasterGR8P m_kissfft_comp_in_ras, m_kissfft_comp_out_ras;
shun-iwasawa 1b1839
  kiss_fft_cpx *m_kissfft_comp_in, *m_kissfft_comp_out;
shun-iwasawa 1b1839
  kiss_fftnd_cfg m_kissfft_plan_fwd, m_kissfft_plan_bkwd;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool m_isTerminated;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  // not used for now
shun-iwasawa 1b1839
  bool m_doLightenComp;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
public:
shun-iwasawa 1b1839
  MyThread(Channel channel, TRasterP layerTileRas, double4* result,
shun-iwasawa 1b1839
           double* alpha_bokeh, kiss_fft_cpx* kissfft_comp_iris,
shun-iwasawa 1b1839
           double layerHardness, double masterHardness = 0.0,
shun-iwasawa 1b1839
           bool doLightenComp = false);  // not used for now
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  // Convert the pixels from RGB values to exposures and multiply it by alpha
shun-iwasawa 1b1839
  // channel value.
shun-iwasawa 1b1839
  // Store the results in the real part of kiss_fft_cpx.
shun-iwasawa 1b1839
  template <typename RASTER, typename PIXEL>
shun-iwasawa 1b1839
  void setLayerRaster(const RASTER srcRas, kiss_fft_cpx* dstMem,
shun-iwasawa 1b1839
                      TDimensionI dim);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void run();
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool isFinished() { return m_finished; }
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  //ÉÅÉÇÉäämï€
shun-iwasawa 1b1839
  bool init();
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void terminateThread() { m_isTerminated = true; }
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool checkTerminationAndCleanupThread();
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
//------------------------------------
shun-iwasawa 1b1839
shun-iwasawa 1b1839
class BokehRefThread : public QThread {
shun-iwasawa 1b1839
  int m_channel;
shun-iwasawa 1b1839
  volatile bool m_finished;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  kiss_fft_cpx* m_fftcpx_channel_before;
shun-iwasawa 1b1839
  kiss_fft_cpx* m_fftcpx_channel;
shun-iwasawa 1b1839
  kiss_fft_cpx* m_fftcpx_alpha;
shun-iwasawa 1b1839
  kiss_fft_cpx* m_fftcpx_iris;
shun-iwasawa 1b1839
  double4* m_result_buff;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  kiss_fftnd_cfg m_kissfft_plan_fwd, m_kissfft_plan_bkwd;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  TDimensionI m_dim;
shun-iwasawa 1b1839
  bool m_isTerminated;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
public:
shun-iwasawa 1b1839
  BokehRefThread(int channel, kiss_fft_cpx* fftcpx_channel_before,
shun-iwasawa 1b1839
                 kiss_fft_cpx* fftcpx_channel, kiss_fft_cpx* fftcpx_alpha,
shun-iwasawa 1b1839
                 kiss_fft_cpx* fftcpx_iris, double4* result_buff,
shun-iwasawa 1b1839
                 kiss_fftnd_cfg kissfft_plan_fwd,
shun-iwasawa 1b1839
                 kiss_fftnd_cfg kissfft_plan_bkwd, TDimensionI& dim);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void run() override;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool isFinished() { return m_finished; }
shun-iwasawa 1b1839
  void terminateThread() { m_isTerminated = true; }
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
//------------------------------------
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// normalize the source raster image to 0-1 and set to dstMem
shun-iwasawa 1b1839
// returns true if the source is (seems to be) premultiplied
shun-iwasawa 1b1839
template <typename RASTER, typename PIXEL>
shun-iwasawa 1b1839
void setSourceRaster(const RASTER srcRas, double4* dstMem, TDimensionI dim);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// normalize brightness of the depth reference image to unsigned char
shun-iwasawa 1b1839
// and store into dstMem
shun-iwasawa 1b1839
template <typename RASTER, typename PIXEL>
shun-iwasawa 1b1839
void setDepthRaster(const RASTER srcRas, unsigned char* dstMem,
shun-iwasawa 1b1839
                    TDimensionI dim);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// create the depth index map
shun-iwasawa 1b1839
void defineSegemntDepth(
shun-iwasawa 1b1839
    const unsigned char* indexMap_main, const unsigned char* indexMap_sub,
shun-iwasawa 1b1839
    const double* mainSub_ratio, const unsigned char* depth_host,
shun-iwasawa 1b1839
    const TDimensionI& dimOut, QVector<double>& segmentDepth_main,
shun-iwasawa 1b1839
    QVector<double>& segmentDepth_sub, const double focusDepth,
shun-iwasawa 1b1839
    int distancePrecision = 10, double nearDepth = 0.0, double farDepth = 1.0);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// convert source image value rgb -> exposure
shun-iwasawa 1b1839
void convertRGBToExposure(const double4* source_buff, int size,
shun-iwasawa 1b1839
                          double filmGamma);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// convert result image value exposure -> rgb
shun-iwasawa 1b1839
void convertExposureToRGB(const double4* result_buff, int size,
shun-iwasawa 1b1839
                          double filmGamma);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// obtain iris size from the depth value
shun-iwasawa 1b1839
double calcIrisSize(const double depth, const double bokehPixelAmount,
shun-iwasawa 1b1839
                    const double onFocusDistance,
shun-iwasawa 1b1839
                    const double bokehAdjustment = 1.0, double nearDepth = 0.0,
shun-iwasawa 1b1839
                    double farDepth = 1.0);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// generate the segment layer source at the current depth
shun-iwasawa 1b1839
// considering fillGap and doMedian options
shun-iwasawa 1b1839
void retrieveLayer(const double4* source_buff,
shun-iwasawa 1b1839
                   const double4* segment_layer_buff,
shun-iwasawa 1b1839
                   const unsigned char* indexMap_mainSub, int index, int lx,
shun-iwasawa 1b1839
                   int ly, bool fillGap = true, bool doMedian = false,
shun-iwasawa 1b1839
                   int margin = 0);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// normal-composite the layer as is, without filtering
shun-iwasawa 1b1839
void compositeAsIs(const double4* segment_layer_buff,
shun-iwasawa 1b1839
                   const double4* result_buff_mainSub, int size);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// Resize / flip the iris image according to the size ratio.
shun-iwasawa 1b1839
// Normalize the brightness of the iris image.
shun-iwasawa 1b1839
// Enlarge the iris to the output size.
shun-iwasawa 1b1839
void convertIris(const double irisSize, kiss_fft_cpx* kissfft_comp_iris_before,
shun-iwasawa 1b1839
                 const TDimensionI& dimOut, const TRectD& irisBBox,
shun-iwasawa 1b1839
                 const TTile& irisTile);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// retrieve segment layer image for each channel
shun-iwasawa 1b1839
void retrieveChannel(const double4* segment_layer_buff,  // src
shun-iwasawa 1b1839
                     kiss_fft_cpx* fftcpx_r_before,      // dst
shun-iwasawa 1b1839
                     kiss_fft_cpx* fftcpx_g_before,      // dst
shun-iwasawa 1b1839
                     kiss_fft_cpx* fftcpx_b_before,      // dst
shun-iwasawa 1b1839
                     kiss_fft_cpx* fftcpx_a_before,      // dst
shun-iwasawa 1b1839
                     int size);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// multiply filter on channel
shun-iwasawa 1b1839
void multiplyFilter(kiss_fft_cpx* fftcpx_channel,  // dst
shun-iwasawa 1b1839
                    kiss_fft_cpx* fftcpx_iris,     // filter
shun-iwasawa 1b1839
                    int size);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// normal comosite the alpha channel
shun-iwasawa 1b1839
void compositeAlpha(const double4* result_buff,        // dst
shun-iwasawa 1b1839
                    const kiss_fft_cpx* fftcpx_alpha,  // alpha
shun-iwasawa 1b1839
                    int lx, int ly);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// interpolate main and sub exposures
shun-iwasawa 1b1839
// set to result
shun-iwasawa 1b1839
void interpolateExposureAndConvertToRGB(
shun-iwasawa 1b1839
    const double4* result_main_buff,  // result1
shun-iwasawa 1b1839
    const double4* result_sub_buff,   // result2
shun-iwasawa 1b1839
    const double* mainSub_ratio,      // ratio
shun-iwasawa 1b1839
    const double4* result_buff,       // dst
shun-iwasawa 1b1839
    int size, double layerHardnessRatio = 1.0);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
//"Over" composite the layer to the output exposure.
shun-iwasawa 1b1839
void compositLayerAsIs(TTile& layerTile, double4* result, TDimensionI& dimOut,
shun-iwasawa 1b1839
                       double filmGamma);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// Do FFT the alpha channel.
shun-iwasawa 1b1839
// Forward FFT -> Multiply by the iris data -> Backward FFT
shun-iwasawa 1b1839
void calcAlfaChannelBokeh(kiss_fft_cpx* kissfft_comp_iris, TTile& layerTile,
shun-iwasawa 1b1839
                          double* alpha_bokeh);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// convert to channel value and set to output
shun-iwasawa 1b1839
template <typename RASTER, typename PIXEL>
shun-iwasawa 1b1839
void setOutputRaster(double4* src, const RASTER dstRas, TDimensionI& dim,
shun-iwasawa 1b1839
                     int2 margin);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
// Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
shun-iwasawa 1b1839
double getBokehPixelAmount(const double bokehAmount, const TAffine affine);
shun-iwasawa 1b1839
}  // namespace BokehUtils
shun-iwasawa 1b1839
shun-iwasawa 1b1839
//-----------------------------------------------------
shun-iwasawa 1b1839
shun-iwasawa 1b1839
class Iwa_BokehCommonFx : public TStandardRasterFx {
shun-iwasawa 1b1839
protected:
shun-iwasawa 1b1839
  TRasterFxPort m_iris;
shun-iwasawa 1b1839
  TDoubleParamP m_onFocusDistance;  // Focus Distance (0-1)
shun-iwasawa 1b1839
  TDoubleParamP m_bokehAmount;  // The maximum bokeh size. The size of bokeh at
shun-iwasawa 1b1839
                                // the layer separated by 1.0 from the focal
shun-iwasawa 1b1839
                                // position
shun-iwasawa 1b1839
  TDoubleParamP m_hardness;     // Film gamma
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  struct LayerValue {
shun-iwasawa 1b1839
    TTile* sourceTile;
shun-iwasawa 1b1839
    // set to false if the input image is already premultiplied.
shun-iwasawa 1b1839
    // this parameter is now always false (assuming input images are always
shun-iwasawa 1b1839
    // premultiplied). the value is left to keep backward compatibility
shun-iwasawa 1b1839
    bool premultiply;
shun-iwasawa 1b1839
    double layerHardness;
shun-iwasawa 1b1839
    int depth_ref;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
    double irisSize;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
    double distance;
shun-iwasawa 1b1839
    double bokehAdjustment;
shun-iwasawa 1b1839
    double depthRange;
shun-iwasawa 1b1839
    int distancePrecision;
shun-iwasawa 1b1839
    bool fillGap;
shun-iwasawa 1b1839
    bool doMedian;
shun-iwasawa 1b1839
  };
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void doFx(TTile& tile, double frame, const TRenderSettings& settings,
shun-iwasawa 1b1839
            double bokehPixelAmount, int margin, TDimensionI& dimOut,
shun-iwasawa 1b1839
            TRectD& irisBBox, TTile& irisTile, QList<LayerValue>& layerValues,
shun-iwasawa 1b1839
            QMap<int, unsigned char*>& ctrls);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void doBokehRef(double4* result, double frame,
shun-iwasawa 1b1839
                  const TRenderSettings& settings, double bokehPixelAmount,
shun-iwasawa 1b1839
                  int margin, TDimensionI& dimOut, TRectD& irisBBox,
shun-iwasawa 1b1839
                  TTile& irisTile, kiss_fft_cpx* kissfft_comp_iris,
shun-iwasawa 1b1839
                  LayerValue layer, unsigned char* ctrl);
shun-iwasawa 1b1839
shun-iwasawa 1b1839
public:
shun-iwasawa 1b1839
  Iwa_BokehCommonFx();
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  void doCompute(TTile& tile, double frame,
shun-iwasawa 1b1839
                 const TRenderSettings& settings) override = 0;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool doGetBBox(double frame, TRectD& bBox,
shun-iwasawa 1b1839
                 const TRenderSettings& info) final override;
shun-iwasawa 1b1839
shun-iwasawa 1b1839
  bool canHandle(const TRenderSettings& info, double frame) final override;
shun-iwasawa 1b1839
};
shun-iwasawa 1b1839
shun-iwasawa 1b1839
#endif