|
shun-iwasawa |
e2505a |
#include "iwa_bokehreffx.h"
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
#include "trop.h"
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
#include <qreadwritelock></qreadwritelock>
|
|
shun-iwasawa |
e2505a |
#include <qset></qset>
|
|
shun-iwasawa |
1b1839 |
#include <qmap></qmap>
|
|
shun-iwasawa |
e2505a |
#include <math.h></math.h>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
namespace {
|
|
shun-iwasawa |
e2505a |
QReadWriteLock lock;
|
|
shun-iwasawa |
1b1839 |
QMutex fx_mutex;
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
template <typename t=""></typename>
|
|
shun-iwasawa |
e2505a |
TRasterGR8P allocateRasterAndLock(T** buf, TDimensionI dim) {
|
|
shun-iwasawa |
e2505a |
TRasterGR8P ras(dim.lx * sizeof(T), dim.ly);
|
|
shun-iwasawa |
e2505a |
ras->lock();
|
|
shun-iwasawa |
e2505a |
*buf = (T*)ras->getRawData();
|
|
shun-iwasawa |
e2505a |
return ras;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// release all registered raster memories
|
|
shun-iwasawa |
e2505a |
void releaseAllRasters(QList<trastergr8p>& rasterList) {</trastergr8p>
|
|
shun-iwasawa |
e2505a |
for (int r = 0; r < rasterList.size(); r++) rasterList.at(r)->unlock();
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// release all registered raster memories and free all fft plans
|
|
shun-iwasawa |
e2505a |
void releaseAllRastersAndPlans(QList<trastergr8p>& rasterList,</trastergr8p>
|
|
shun-iwasawa |
e2505a |
QList<kiss_fftnd_cfg>& planList) {</kiss_fftnd_cfg>
|
|
shun-iwasawa |
e2505a |
releaseAllRasters(rasterList);
|
|
shun-iwasawa |
e2505a |
for (int p = 0; p < planList.size(); p++) kiss_fft_free(planList.at(p));
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
09e972 |
}; // namespace
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
//============================================================
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
//------------------------------------------------------------
|
|
shun-iwasawa |
e2505a |
// normalize brightness of the depth reference image to unsigned char
|
|
shun-iwasawa |
e2505a |
// and store into detMem
|
|
shun-iwasawa |
e2505a |
//------------------------------------------------------------
|
|
shun-iwasawa |
e2505a |
template <typename pixel="" raster,="" typename=""></typename>
|
|
shun-iwasawa |
e2505a |
void Iwa_BokehRefFx::setDepthRaster(const RASTER srcRas, unsigned char* dstMem,
|
|
shun-iwasawa |
e2505a |
TDimensionI dim) {
|
|
shun-iwasawa |
e2505a |
unsigned char* depth_p = dstMem;
|
|
shun-iwasawa |
e2505a |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
e2505a |
PIXEL* pix = srcRas->pixels(j);
|
|
shun-iwasawa |
e2505a |
for (int i = 0; i < dim.lx; i++, pix++, depth_p++) {
|
|
shun-iwasawa |
e2505a |
// normalize brightness to 0-1
|
|
shun-iwasawa |
1b1839 |
double val = ((double)pix->r * 0.3 + (double)pix->g * 0.59 +
|
|
shun-iwasawa |
1b1839 |
(double)pix->b * 0.11) /
|
|
shun-iwasawa |
1b1839 |
(double)PIXEL::maxChannelValue;
|
|
shun-iwasawa |
e2505a |
// convert to unsigned char
|
|
shun-iwasawa |
1b1839 |
(*depth_p) = (unsigned char)(val * (double)UCHAR_MAX + 0.5);
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
template <typename pixel="" raster,="" typename=""></typename>
|
|
shun-iwasawa |
e2505a |
void Iwa_BokehRefFx::setDepthRasterGray(const RASTER srcRas,
|
|
shun-iwasawa |
e2505a |
unsigned char* dstMem,
|
|
shun-iwasawa |
e2505a |
TDimensionI dim) {
|
|
shun-iwasawa |
e2505a |
unsigned char* depth_p = dstMem;
|
|
shun-iwasawa |
e2505a |
for (int j = 0; j < dim.ly; j++) {
|
|
shun-iwasawa |
e2505a |
PIXEL* pix = srcRas->pixels(j);
|
|
shun-iwasawa |
e2505a |
for (int i = 0; i < dim.lx; i++, pix++, depth_p++) {
|
|
shun-iwasawa |
e2505a |
// normalize brightness to 0-1
|
|
shun-iwasawa |
1b1839 |
double val = (double)pix->value / (double)PIXEL::maxChannelValue;
|
|
shun-iwasawa |
e2505a |
// convert to unsigned char
|
|
shun-iwasawa |
1b1839 |
(*depth_p) = (unsigned char)(val * (double)UCHAR_MAX + 0.5);
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
//--------------------------------------------
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
Iwa_BokehRefFx::Iwa_BokehRefFx()
|
|
shun-iwasawa |
1b1839 |
: m_distancePrecision(10), m_fillGap(true), m_doMedian(true) {
|
|
shun-iwasawa |
e2505a |
// Bind parameters
|
|
shun-iwasawa |
e2505a |
addInputPort("Source", m_source);
|
|
shun-iwasawa |
e2505a |
addInputPort("Depth", m_depth);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
bindParam(this, "on_focus_distance", m_onFocusDistance, false);
|
|
shun-iwasawa |
e2505a |
bindParam(this, "bokeh_amount", m_bokehAmount, false);
|
|
shun-iwasawa |
e2505a |
bindParam(this, "hardness", m_hardness, false);
|
|
shun-iwasawa |
e2505a |
bindParam(this, "distance_precision", m_distancePrecision, false);
|
|
shun-iwasawa |
e2505a |
bindParam(this, "fill_gap", m_fillGap, false);
|
|
shun-iwasawa |
e2505a |
bindParam(this, "fill_gap_with_median_filter", m_doMedian, false);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
m_distancePrecision->setValueRange(3, 128);
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
//--------------------------------------------
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
void Iwa_BokehRefFx::doCompute(TTile& tile, double frame,
|
|
shun-iwasawa |
e2505a |
const TRenderSettings& settings) {
|
|
shun-iwasawa |
e2505a |
// If any of input is not connected, then do nothing
|
|
shun-iwasawa |
e2505a |
if (!m_iris.isConnected() || !m_source.isConnected() ||
|
|
shun-iwasawa |
e2505a |
!m_depth.isConnected()) {
|
|
shun-iwasawa |
e2505a |
tile.getRaster()->clear();
|
|
shun-iwasawa |
e2505a |
return;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
QList<trastergr8p> rasterList;</trastergr8p>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
|
|
shun-iwasawa |
1b1839 |
double bokehPixelAmount = BokehUtils::getBokehPixelAmount(
|
|
shun-iwasawa |
1b1839 |
m_bokehAmount->getValue(frame), settings.m_affine);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// Obtain the larger size of bokeh between the nearest (black) point and
|
|
shun-iwasawa |
e2505a |
// the farthest (white) point, based on the focus distance.
|
|
shun-iwasawa |
e2505a |
double onFocusDistance = m_onFocusDistance->getValue(frame);
|
|
shun-iwasawa |
1b1839 |
double maxIrisSize =
|
|
shun-iwasawa |
e2505a |
bokehPixelAmount * std::max((1.0 - onFocusDistance), onFocusDistance);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
int margin =
|
|
shun-iwasawa |
1b1839 |
(maxIrisSize > 1.0f) ? (int)(std::ceil((maxIrisSize - 1.0) / 2.0)) : 0;
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// Range of computation
|
|
shun-iwasawa |
e2505a |
TRectD rectOut(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
|
|
shun-iwasawa |
e2505a |
tile.getRaster()->getLy()));
|
|
shun-iwasawa |
e2505a |
rectOut = rectOut.enlarge(static_cast<double>(margin));</double>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
TDimensionI dimOut(static_cast<int>(rectOut.getLx() + 0.5),</int>
|
|
shun-iwasawa |
e2505a |
static_cast<int>(rectOut.getLy() + 0.5));</int>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// Enlarge the size to the "fast size" for kissfft which has no factors other
|
|
shun-iwasawa |
e2505a |
// than 2,3, or 5.
|
|
shun-iwasawa |
e2505a |
if (dimOut.lx < 10000 && dimOut.ly < 10000) {
|
|
shun-iwasawa |
e2505a |
int new_x = kiss_fft_next_fast_size(dimOut.lx);
|
|
shun-iwasawa |
e2505a |
int new_y = kiss_fft_next_fast_size(dimOut.ly);
|
|
shun-iwasawa |
e917fd |
// margin should be integer
|
|
shun-iwasawa |
e917fd |
while ((new_x - dimOut.lx) % 2 != 0)
|
|
shun-iwasawa |
e917fd |
new_x = kiss_fft_next_fast_size(new_x + 1);
|
|
shun-iwasawa |
e917fd |
while ((new_y - dimOut.ly) % 2 != 0)
|
|
shun-iwasawa |
e917fd |
new_y = kiss_fft_next_fast_size(new_y + 1);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
rectOut = rectOut.enlarge(static_cast<double>(new_x - dimOut.lx) / 2.0,</double>
|
|
shun-iwasawa |
e2505a |
static_cast<double>(new_y - dimOut.ly) / 2.0);</double>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
dimOut.lx = new_x;
|
|
shun-iwasawa |
e2505a |
dimOut.ly = new_y;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// - - - Compute the input tiles - - -
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// source image buffer
|
|
shun-iwasawa |
1b1839 |
// double4* source_buff;
|
|
shun-iwasawa |
1b1839 |
// rasterList.append(allocateRasterAndLock<double4>(&source_buff, dimOut));</double4>
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
LayerValue layerValue;
|
|
shun-iwasawa |
32ddcd |
TRenderSettings infoOnInput(settings);
|
|
shun-iwasawa |
32ddcd |
infoOnInput.m_bpp = 64;
|
|
shun-iwasawa |
1b1839 |
// source tile is used only in this focus.
|
|
shun-iwasawa |
1b1839 |
// normalized source image data is stored in source_buff.
|
|
shun-iwasawa |
1b1839 |
layerValue.sourceTile = new TTile();
|
|
shun-iwasawa |
1b1839 |
m_source->allocateAndCompute(*layerValue.sourceTile, rectOut.getP00(), dimOut,
|
|
shun-iwasawa |
32ddcd |
0, frame, infoOnInput);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// - - - iris image - - -
|
|
shun-iwasawa |
e2505a |
// Get the original size of Iris image
|
|
shun-iwasawa |
e2505a |
TRectD irisBBox;
|
|
shun-iwasawa |
e2505a |
m_iris->getBBox(frame, irisBBox, settings);
|
|
shun-iwasawa |
e2505a |
// Compute the iris tile.
|
|
shun-iwasawa |
e2505a |
TTile irisTile;
|
|
shun-iwasawa |
e2505a |
m_iris->allocateAndCompute(
|
|
shun-iwasawa |
e2505a |
irisTile, irisBBox.getP00(),
|
|
shun-iwasawa |
e2505a |
TDimension(static_cast<int>(irisBBox.getLx() + 0.5),</int>
|
|
shun-iwasawa |
e2505a |
static_cast<int>(irisBBox.getLy() + 0.5)),</int>
|
|
shun-iwasawa |
e2505a |
tile.getRaster(), frame, settings);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// cancel check
|
|
shun-iwasawa |
e2505a |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
e2505a |
releaseAllRasters(rasterList);
|
|
shun-iwasawa |
e2505a |
tile.getRaster()->clear();
|
|
shun-iwasawa |
e2505a |
return;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
// compute the reference image
|
|
shun-iwasawa |
1b1839 |
std::vector<trastergr8p> ctrl_rasters; // to be stored in uchar</trastergr8p>
|
|
shun-iwasawa |
1b1839 |
QMap<int, char*="" unsigned=""></int,>
|
|
shun-iwasawa |
1b1839 |
ctrls; // container of [port number, reference image buffer in uchar]
|
|
shun-iwasawa |
1b1839 |
unsigned char* depth_buff;
|
|
shun-iwasawa |
1b1839 |
rasterList.append(allocateRasterAndLock<unsigned char="">(&depth_buff, dimOut));</unsigned>
|
|
shun-iwasawa |
1b1839 |
{
|
|
shun-iwasawa |
1b1839 |
TTile depthTile;
|
|
shun-iwasawa |
1b1839 |
m_depth->allocateAndCompute(depthTile, rectOut.getP00(), dimOut,
|
|
shun-iwasawa |
1b1839 |
tile.getRaster(), frame, settings);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
// cancel check
|
|
shun-iwasawa |
e2505a |
if (settings.m_isCanceled && *settings.m_isCanceled) {
|
|
shun-iwasawa |
1b1839 |
releaseAllRasters(rasterList);
|
|
shun-iwasawa |
1b1839 |
tile.getRaster()->clear();
|
|
shun-iwasawa |
e2505a |
return;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
// normalize brightness of the depth reference image to unsigned char
|
|
shun-iwasawa |
1b1839 |
// and store into depth_buff
|
|
shun-iwasawa |
1b1839 |
TRasterGR8P rasGR8 = (TRasterGR8P)depthTile.getRaster();
|
|
shun-iwasawa |
1b1839 |
TRasterGR16P rasGR16 = (TRasterGR16P)depthTile.getRaster();
|
|
shun-iwasawa |
1b1839 |
TRaster32P ras32 = (TRaster32P)depthTile.getRaster();
|
|
shun-iwasawa |
1b1839 |
TRaster64P ras64 = (TRaster64P)depthTile.getRaster();
|
|
shun-iwasawa |
1b1839 |
lock.lockForRead();
|
|
shun-iwasawa |
1b1839 |
if (rasGR8)
|
|
shun-iwasawa |
1b1839 |
setDepthRasterGray<trastergr8p, tpixelgr8="">(rasGR8, depth_buff, dimOut);</trastergr8p,>
|
|
shun-iwasawa |
1b1839 |
else if (rasGR16)
|
|
shun-iwasawa |
1b1839 |
setDepthRasterGray<trastergr16p, tpixelgr16="">(rasGR16, depth_buff, dimOut);</trastergr16p,>
|
|
shun-iwasawa |
1b1839 |
else if (ras32)
|
|
shun-iwasawa |
1b1839 |
BokehUtils::setDepthRaster<traster32p, tpixel32="">(ras32, depth_buff,</traster32p,>
|
|
shun-iwasawa |
1b1839 |
dimOut);
|
|
shun-iwasawa |
1b1839 |
else if (ras64)
|
|
shun-iwasawa |
1b1839 |
BokehUtils::setDepthRaster<traster64p, tpixel64="">(ras64, depth_buff,</traster64p,>
|
|
shun-iwasawa |
1b1839 |
dimOut);
|
|
shun-iwasawa |
1b1839 |
lock.unlock();
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
1b1839 |
ctrls[1] = depth_buff;
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
layerValue.premultiply = 2; // auto
|
|
shun-iwasawa |
1b1839 |
layerValue.layerHardness = m_hardness->getValue(frame);
|
|
shun-iwasawa |
1b1839 |
layerValue.depth_ref = 1;
|
|
shun-iwasawa |
1b1839 |
layerValue.distance = 0.5;
|
|
shun-iwasawa |
1b1839 |
layerValue.bokehAdjustment = 1.0;
|
|
shun-iwasawa |
1b1839 |
layerValue.depthRange = 1.0;
|
|
shun-iwasawa |
1b1839 |
layerValue.distancePrecision = m_distancePrecision->getValue();
|
|
shun-iwasawa |
1b1839 |
layerValue.fillGap = m_fillGap->getValue();
|
|
shun-iwasawa |
1b1839 |
layerValue.doMedian = m_doMedian->getValue();
|
|
shun-iwasawa |
1b1839 |
QList<layervalue> layerValues;</layervalue>
|
|
shun-iwasawa |
1b1839 |
layerValues.append(layerValue);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
Iwa_BokehCommonFx::doFx(tile, frame, settings, bokehPixelAmount, margin,
|
|
shun-iwasawa |
1b1839 |
dimOut, irisBBox, irisTile, layerValues, ctrls);
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
1b1839 |
releaseAllRasters(rasterList);
|
|
shun-iwasawa |
1b1839 |
delete layerValue.sourceTile;
|
|
shun-iwasawa |
e2505a |
}
|
|
shun-iwasawa |
e2505a |
|
|
shun-iwasawa |
e2505a |
FX_PLUGIN_IDENTIFIER(Iwa_BokehRefFx, "iwa_BokehRefFx")
|