iwa bokeh advanced fx

This commit is contained in:
shun-iwasawa 2021-06-07 12:26:20 +09:00 committed by manongjohn
parent f4b2e1dd6b
commit cb41b196c6
23 changed files with 3055 additions and 2423 deletions

View file

@ -1290,21 +1290,16 @@
<item>"STD_iwa_BokehFx.on_focus_distance" "On-Focus Distance"</item> <item>"STD_iwa_BokehFx.on_focus_distance" "On-Focus Distance"</item>
<item>"STD_iwa_BokehFx.bokeh_amount" "Bokeh Amount"</item> <item>"STD_iwa_BokehFx.bokeh_amount" "Bokeh Amount"</item>
<item>"STD_iwa_BokehFx.hardness" "Hardness"</item> <item>"STD_iwa_BokehFx.hardness" "Hardness"</item>
<item>"STD_iwa_BokehFx.premultiply1" "Layer1 Premultiply"</item> <item>"STD_iwa_BokehFx.distance1" "Source1 Distance"</item>
<item>"STD_iwa_BokehFx.distance1" "Layer1 Distance"</item> <item>"STD_iwa_BokehFx.bokeh_adjustment1" "Source1 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.bokeh_adjustment1" "Layer1 Bokeh Adjustment"</item> <item>"STD_iwa_BokehFx.distance2" "Source2 Distance"</item>
<item>"STD_iwa_BokehFx.premultiply2" "Layer2 Premultiply"</item> <item>"STD_iwa_BokehFx.bokeh_adjustment2" "Source2 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.distance2" "Layer2 Distance"</item> <item>"STD_iwa_BokehFx.distance3" "Source3 Distance"</item>
<item>"STD_iwa_BokehFx.bokeh_adjustment2" "Layer2 Bokeh Adjustment"</item> <item>"STD_iwa_BokehFx.bokeh_adjustment3" "Source3 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.premultiply3" "Layer3 Premultiply"</item> <item>"STD_iwa_BokehFx.distance4" "Source4 Distance"</item>
<item>"STD_iwa_BokehFx.distance3" "Layer3 Distance"</item> <item>"STD_iwa_BokehFx.bokeh_adjustment4" "Source4 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.bokeh_adjustment3" "Layer3 Bokeh Adjustment"</item> <item>"STD_iwa_BokehFx.distance5" "Source5 Distance"</item>
<item>"STD_iwa_BokehFx.premultiply4" "Layer4 Premultiply"</item> <item>"STD_iwa_BokehFx.bokeh_adjustment5" "Source5 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.distance4" "Layer4 Distance"</item>
<item>"STD_iwa_BokehFx.bokeh_adjustment4" "Layer4 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehFx.premultiply5" "Layer5 Premultiply"</item>
<item>"STD_iwa_BokehFx.distance5" "Layer5 Distance"</item>
<item>"STD_iwa_BokehFx.bokeh_adjustment5" "Layer5 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehRefFx" "Bokeh Ref Iwa"</item> <item>"STD_iwa_BokehRefFx" "Bokeh Ref Iwa"</item>
<item>"STD_iwa_BokehRefFx.on_focus_distance" "On-Focus Distance"</item> <item>"STD_iwa_BokehRefFx.on_focus_distance" "On-Focus Distance"</item>
@ -1314,6 +1309,42 @@
<item>"STD_iwa_BokehRefFx.fill_gap" "Fill Gap"</item> <item>"STD_iwa_BokehRefFx.fill_gap" "Fill Gap"</item>
<item>"STD_iwa_BokehRefFx.fill_gap_with_median_filter" "Use Median Filter"</item> <item>"STD_iwa_BokehRefFx.fill_gap_with_median_filter" "Use Median Filter"</item>
<item>"STD_iwa_BokehAdvancedFx" "Bokeh Advanced Iwa"</item>
<item>"STD_iwa_BokehAdvancedFx.on_focus_distance" "On-Focus Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_amount" "Bokeh Amount"</item>
<item>"STD_iwa_BokehAdvancedFx.masterHardness" "Master Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.hardnessPerSource" "Hardness per Source"</item>
<item>"STD_iwa_BokehAdvancedFx.distance1" "Source1 Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_adjustment1" "Source1 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehAdvancedFx.hardness1" "Source1 Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.depth_ref1" "Depth Image"</item>
<item>"STD_iwa_BokehAdvancedFx.depthRange1" "Source1 Depth Range"</item>
<item>"STD_iwa_BokehAdvancedFx.distance2" "Source2 Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_adjustment2" "Source2 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehAdvancedFx.hardness2" "Source2 Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.depth_ref2" "Depth Image"</item>
<item>"STD_iwa_BokehAdvancedFx.depthRange2" "Source2 Depth Range"</item>
<item>"STD_iwa_BokehAdvancedFx.distance3" "Source3 Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_adjustment3" "Source3 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehAdvancedFx.hardness3" "Source3 Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.depth_ref3" "Depth Image"</item>
<item>"STD_iwa_BokehAdvancedFx.depthRange3" "Source3 Depth Range"</item>
<item>"STD_iwa_BokehAdvancedFx.distance4" "Source4 Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_adjustment4" "Source4 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehAdvancedFx.hardness4" "Source4 Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.depth_ref4" "Depth Image"</item>
<item>"STD_iwa_BokehAdvancedFx.depthRange4" "Source4 Depth Range"</item>
<item>"STD_iwa_BokehAdvancedFx.distance5" "Source5 Distance"</item>
<item>"STD_iwa_BokehAdvancedFx.bokeh_adjustment5" "Source5 Bokeh Adjustment"</item>
<item>"STD_iwa_BokehAdvancedFx.hardness5" "Source5 Hardness"</item>
<item>"STD_iwa_BokehAdvancedFx.depth_ref5" "Depth Image"</item>
<item>"STD_iwa_BokehAdvancedFx.depthRange5" "Source5 Depth Range"</item>
<item>"STD_iwa_TimeCodeFx" "TimeCode Iwa"</item> <item>"STD_iwa_TimeCodeFx" "TimeCode Iwa"</item>
<item>"STD_iwa_TimeCodeFx.displayType" "Display Type"</item> <item>"STD_iwa_TimeCodeFx.displayType" "Display Type"</item>
<item>"STD_iwa_TimeCodeFx.frameRate" "Frame Rate"</item> <item>"STD_iwa_TimeCodeFx.frameRate" "Frame Rate"</item>

View file

@ -0,0 +1,104 @@
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Bokeh Advanced Iwa</title>
</head>
<body bgcolor="#f5f5f5" text="#220011">
<h1><img src = ".\img\fx_iwa_bokeh_advanced.png" width = 30 height = 30 > Bokeh Iwa</h1>
<h4>● Overview</h4>
This effect reproduces a camera lens blur. The RGB values of each layer will be converted<br>
to exposure values, then blurred using the Iris shape, and finally composed together.<br>
Unlike the <a href="./BokehIwa.html">Bokeh Iwa Fx</a>, this fx can use depth reference images
for dividing layer into several sub-layers within specified range of depth.<br>
Also, this fx can apply individual hardness value for each source for adjusting bokeh brightness.<br>
To achieve a faster processing time, a Fourier transformation is used to process the filter.
<h4>● Input Port</h4>
<UL>
<LI><b>Iris</b> : Connects the image to define the shape of the Iris. The image luminance<br>
values will be used for the effect. If no image is connected to the Iris port, no calculation<br>
will take place. It's possible to connect 8bit or 16bit RGBA images.
<LI><b>Source [15]</b> : Connects images for the layers. The order in which they are<br>
connected here doesn't define the layer stacking order. If nothing is connected to any<br>
Source port, no calculation will be performed.
<LI><b>Depth [1]</b> : Connect the Depth reference image for the layer to be divided into sub-layers.<br>
The brightness of each pixel corresponds to the depth. <br>
The higher (brighter) the value, the farther away from the camera.
</UL>
<h4>● Parameters</h4>
Common
<UL>
<LI><b>On-Focus Distance</b> : If there's a layer or sub-layer in this position, it will look on focus and it will be<br>
composed normally. 0 represents the camera position. (Range 0.0-1.0)
<LI><b>Bokeh Amount</b> : Maximum size of blur (in scene units). When the focus position and the<br>
layer position are 1.0 away from each other and Bokeh Adjustment is 1, the Iris image is<br>
enlarged until the width of this image reaches this value.
<LI><b>Master Hardness</b> : The gamma value of the film. Used to convert between RGB value and<br>
exposure. This is equivalent to the increase in RGB value (0.0 to 1.0) when the exposure is<br>
increased 10 times. The lower the value, the more the highlights are emphasized.<br>
(Range 0.05-3.0)
<LI><b>Hardness per Source</b> : Specify whether to use individual hardness value instead of the master hardness for converting the layer RGB values to exposures.
</UL>
Sources
<UL>
<LI><b>Distance</b> : The distance of the layer from the camera. The layer stacking order is<br>
automatically sorted according to this value. (Range 0.0-1.0)
<LI><b>Bokeh Adjustment</b> : Bokeh size correction value. The size of the bokeh is multiplied by N,<br>
keeping the order of layer stacking. If this value is 0, the layers will be composited normally<br>
without blurring regardless of the distance of the layer. (Range 0.0-2.0)
<LI><b>Hardness</b> : Individual hardness used for converting this layer's RGB values to exposure.
<LI><b>Depth Image</b> : Specifies the Depth port number. If some available Depth port is set, this layer will be divided into sub-layers at different depths in the specified range.
<LI><b>Depth Range</b> : Specifies the range of depth where the sub-layers will be distributed.
</UL>
<h4>● Notes</h4>
<UL>
<LI>Separating a layer into sub-layers is just like the <a href="./BokehRefIwa.html">Bokeh Ref Iwa Fx</a> except that the following parameters are hard-coded:<br>
<UL>
<LI>Distance Precision = 10
<LI>Fill Gap = ON
<LI>Use Median Filter = OFF
</UL>
<LI>When rendering multiple frames, the Iris and the layers images, must be present within<br>
the range of all frames to be rendered.
<LI>This effect uses a lot of RAM.
</UL>
<h4>● License Information</h4>
<UL>
<LI>This effect uses an open source library called Kiss FFT for the Fourier transform.<br>
</UL>
<font size = "-1">
<blockquote>
This is the BSD-style license for the KissFFT.<br>
<br>
Copyright (c) 2003-2010 Mark Borgerding<br>
<br>
All rights reserved.<br>
<br>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that<br>
the following conditions are met:<br>
<br>
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following<br>
disclaimer.<br>
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the<br>
following disclaimer in the documentation and/or other materials provided with the distribution.<br>
* Neither the author nor the names of any contributors may be used to endorse or promote products derived<br>
from this software without specific prior written permission.<br>
<br>
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY<br>
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT<br>
SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,<br>
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT<br>
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br>
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,<br>
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS<br>
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</blockquote>
</font>
</body>
</html>

View file

@ -34,10 +34,8 @@ exposure. This is equivalent to the increase in RGB value (0.0 to 1.0) when the
increased 10 times. The lower the value, the more the highlights are emphasized.<br> increased 10 times. The lower the value, the more the highlights are emphasized.<br>
(Range 0.05-3.0) (Range 0.05-3.0)
</UL> </UL>
Layers Sources
<UL> <UL>
<LI><b>Premultiply</b> : Check this box when connecting unpremultiplied material such as the ones<br>
from DigiBook, etc. directly to this effect.
<LI><b>Distance</b> : The distance of the layer from the camera. The layer stacking order is<br> <LI><b>Distance</b> : The distance of the layer from the camera. The layer stacking order is<br>
automatically sorted according to this value. (Range 0.0-1.0) automatically sorted according to this value. (Range 0.0-1.0)
<LI><b>Bokeh Adjustment</b> : Bokeh size correction value. The size of the bokeh is multiplied by N,<br> <LI><b>Bokeh Adjustment</b> : Bokeh size correction value. The size of the bokeh is multiplied by N,<br>

View file

@ -12,7 +12,7 @@ based on the gradation of the Depth reference image, and the RGB values of each
layer are converted into exposure values, blurred using the Iris shape, and combined.<br> layer are converted into exposure values, blurred using the Iris shape, and combined.<br>
Higher speed is achieved by using the discrete Fourier transform. Before blurring,<br> Higher speed is achieved by using the discrete Fourier transform. Before blurring,<br>
a process of extending the parts of each layer that is hidden in the foreground with a<br> a process of extending the parts of each layer that is hidden in the foreground with a<br>
Median filter is performed. Median filter can be performed.
<h4>● Input Port</h4> <h4>● Input Port</h4>
<UL> <UL>
@ -39,6 +39,9 @@ is increased 10 times. The lower the value, the more the highlights are emphasiz
<LI><b>Distance Precision</b> : The number of divisions of the depth reference image. The larger<br> <LI><b>Distance Precision</b> : The number of divisions of the depth reference image. The larger<br>
the value, the finer the gradation of the blur size, but the slower the processing.<br> the value, the finer the gradation of the blur size, but the slower the processing.<br>
(Range 3-128) (Range 3-128)
<LI><b>Fill Gap</b> : Specifies whether to extend the further segmented layer pixels in order to fill gap.
<LI><b>Use Median Filter</b> : Specifies whether to use median filter for the extension. <br>
This option is recommended when the depth is distributed discretely.
</UL> </UL>
<h4>● Notes</h4> <h4>● Notes</h4>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,74 @@
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Bokeh Fx Iwa</title>
</head>
<body bgcolor="#f5f5f5" text="#220011">
<h1><img src = ".\img\fx_iwa_bokeh_advanced.png" width = 30 height = 30 > Bokeh Advanced Iwa</h1>
<h4>● 概要</h4>
レンズのボケを再現するエフェクトです。各レイヤのRGB値を露光値に変換して、絞り形状でボカし、合成します。<br>
<a href="./BokehIwa.html">Bokeh Iwa Fx</a>と異なり、このエフェクトは任意のレイヤーを深度参照画像を用いてサブレイヤーに分割することができます。また、各レイヤーに異なるHardnessの値を用いて、ボケの明るさを調整することができます。<br>
フィルタ処理にフーリエ変換を用いて高速化を図っています。
<h4>● 入力ポート</h4>
<UL>
<LI><b>Iris</b> : 絞り画像を接続します。入力された画像の輝度値がフィルタに用いられます。Irisポートに何も接続されていない場合は、計算が行われません。RGBA8bit又はRGBA16bit画像が入力できます。
<LI><b>Source[15]</b> : レイヤー画像を接続します。ここでの接続の順番は、レイヤーの重ね順に影響しません。全てのSourceポートに何も接続されていない場合は、計算が行われません。
<LI><b>Depth[1]</b> : サブレイヤーに分割したいレイヤーがあるとき、深度参照画像を接続します。
</UL>
<h4>● パラメータ</h4>
共通パラメータ
<UL>
<LI><b>On-Focus Distance</b> : フォーカス位置。この位置にレイヤーがあると、
そのレイヤーはボカされず、通常合成されます。0がカメラ位置です。(範囲 0.01.0)
<LI><b>Bokeh Amount</b> : ボケの最大サイズ(単位 Unit。フォーカス位置とレイヤー位置が 1.0 離れていて、Bokeh Adjustmentが 1 のとき、絞り画像の横幅がこの値になるまで拡大されて用いられます。
<LI><b>Master Hardness</b> : フィルムのガンマ値。RGB値と露光量の変換に用います。露光量が10倍増えた時の、RGB値0.01.0)の増加量に相当します。この値が小さいほど、ハイライトが強調されます。(範囲 0.053.0)
<LI><b>Hardness per Source</b> : ONのとき、各レイヤーのRGB値を露光値に変換するとき、個別のHardnessの値を用いることができます。
</UL>
レイヤー毎のパラメータ
<UL>
<LI><b>Distance</b> : レイヤーのカメラからの距離。この値に合わせ、レイヤーの重なる順序が自動的にソートされます。(範囲 0.01.0)
<LI><b>Bokeh Adjustment</b> : ボケサイズの補正値。レイヤーの重なる順序はそのままに、ボケのサイズが N 倍されます。この値が 0 なら、どの距離にレイヤーを置いても、ボケずに通常合成されます。(範囲 0.02.0)
<LI><b>Hardness</b> : 各レイヤーのRGB値を露光値に変換するときに用いる個々のHardness値。Hardness per SourceがONのとき有効
<LI><b>Depth Image</b> : 深度参照画像を接続したポート番号を指定します。有効なポート番号が指定されているとき、このレイヤーはサブレイヤーに分割され、Depth Rangeで指定された奥行きの範囲に分布します。
<LI><b>Depth Range</b> : レイヤーをサブレイヤーに分割するときの奥行の範囲を指定します。
</UL>
<h4>● 注意点</h4>
<UL>
<LI>レイヤーを深度参照画像を用いてサブレイヤーに分割するのは、<a href="./BokehRefIwa.html">Bokeh Ref Iwa Fx</a>の挙動とほぼ同じです。ただし、下記のパラメータは固定となっています:<br>
<UL>
<LI>Distance Precision = 10
<LI>Fill Gap = ON
<LI>Use Median Filter = OFF
</UL>
<LI>複数フレームをレンダリングする際、レイヤーだけでなくIrisの素材も、レンダリングされるすべてのフレームの範囲に入っている必要があります。
<LI>メモリを多く使います。
</UL>
<h4>● ライセンス情報</h4>
<UL>
<LI>このエフェクトは、フーリエ変換にKiss FFTというオープンソース・ライブラリを用いています。<br>
</UL>
<font size = "-1">
<blockquote>
This is the BSD-style license for the KissFFT.<br>
<br>
Copyright (c) 2003-2010 Mark Borgerding<br>
<br>
All rights reserved.<br>
<br>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:<br>
<br>
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.<br>
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.<br>
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.<br>
<br>
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</blockquote>
</font>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,60 @@
<fxlayout help_command="iexplore" help_file="BokehAdvancedIwa.html">
<page name="iwa Bokeh Advanced">
<vbox>
<control>on_focus_distance</control>
<control>bokeh_amount</control>
<control>masterHardness</control>
<control>hardnessPerSource</control>
</vbox>
<vbox shrink="1" label="Source1">
<control>distance1</control>
<control>bokeh_adjustment1</control>
<control>hardness1</control>
<control>depth_ref1</control>
<control>depthRange1</control>
</vbox>
<vbox shrink="0" label="Source2">
<control>distance2</control>
<control>bokeh_adjustment2</control>
<control>hardness2</control>
<control>depth_ref2</control>
<control>depthRange2</control>
</vbox>
<vbox shrink="0" label="Source3">
<control>distance3</control>
<control>bokeh_adjustment3</control>
<control>hardness3</control>
<control>depth_ref3</control>
<control>depthRange3</control>
</vbox>
<vbox shrink="0" label="Source4">
<control>distance4</control>
<control>bokeh_adjustment4</control>
<control>hardness4</control>
<control>depth_ref4</control>
<control>depthRange4</control>
</vbox>
<vbox shrink="0" label="Source5">
<control>distance5</control>
<control>bokeh_adjustment5</control>
<control>hardness5</control>
<control>depth_ref5</control>
<control>depthRange5</control>
</vbox>
<visibleToggle>
<controller>hardnessPerSource</controller>
<on>hardness1</on>
<on>hardness2</on>
<on>hardness3</on>
<on>hardness4</on>
<on>hardness5</on>
</visibleToggle>
</page>
</fxlayout>

View file

@ -6,37 +6,32 @@
<control>hardness</control> <control>hardness</control>
</vbox> </vbox>
<separator label="Layer1"/> <separator label="Source1"/>
<vbox> <vbox>
<control>premultiply1</control>
<control>distance1</control> <control>distance1</control>
<control>bokeh_adjustment1</control> <control>bokeh_adjustment1</control>
</vbox> </vbox>
<separator label="Layer2"/> <separator label="Source2"/>
<vbox> <vbox>
<control>premultiply2</control>
<control>distance2</control> <control>distance2</control>
<control>bokeh_adjustment2</control> <control>bokeh_adjustment2</control>
</vbox> </vbox>
<separator label="Layer3"/> <separator label="Source3"/>
<vbox> <vbox>
<control>premultiply3</control>
<control>distance3</control> <control>distance3</control>
<control>bokeh_adjustment3</control> <control>bokeh_adjustment3</control>
</vbox> </vbox>
<separator label="Layer4"/> <separator label="Source4"/>
<vbox> <vbox>
<control>premultiply4</control>
<control>distance4</control> <control>distance4</control>
<control>bokeh_adjustment4</control> <control>bokeh_adjustment4</control>
</vbox> </vbox>
<separator label="Layer5"/> <separator label="Source5"/>
<vbox> <vbox>
<control>premultiply5</control>
<control>distance5</control> <control>distance5</control>
<control>bokeh_adjustment5</control> <control>bokeh_adjustment5</control>
</vbox> </vbox>

View file

@ -8,5 +8,9 @@
<control>fill_gap</control> <control>fill_gap</control>
<control>fill_gap_with_median_filter</control> <control>fill_gap_with_median_filter</control>
</vbox> </vbox>
<visibleToggle>
<controller>fill_gap</controller>
<on>fill_gap_with_median_filter</on>
</visibleToggle>
</page> </page>
</fxlayout> </fxlayout>

View file

@ -22,6 +22,7 @@
STD_inoSpinBlurFx STD_inoSpinBlurFx
STD_iwa_BokehFx STD_iwa_BokehFx
STD_iwa_BokehRefFx STD_iwa_BokehRefFx
STD_iwa_BokehAdvancedFx
</Blur> </Blur>
<Distort> <Distort>
STD_freeDistortFx STD_freeDistortFx

View file

@ -388,7 +388,7 @@ public:
void updateField(double value) override; void updateField(double value) override;
QSize getPreferedSize() override { return QSize(260, 28); } QSize getPreferedSize() override { return QSize(260, 26); }
void setPrecision(int precision) override; void setPrecision(int precision) override;
protected slots: protected slots:
@ -534,11 +534,14 @@ signals:
class DVAPI ModeSensitiveBox final : public QWidget { class DVAPI ModeSensitiveBox final : public QWidget {
Q_OBJECT Q_OBJECT
QList<int> m_modes; QList<int> m_modes;
int m_currentMode;
public: public:
ModeSensitiveBox(QWidget *parent, ModeChangerParamField *modeChanger, ModeSensitiveBox(QWidget *parent, ModeChangerParamField *modeChanger,
QList<int> modes); QList<int> modes);
ModeSensitiveBox(QWidget *parent, QCheckBox *checkBox);
QList<int> modes() { return m_modes; } QList<int> modes() { return m_modes; }
bool isActive() { return m_modes.contains(m_currentMode); }
protected slots: protected slots:
void onModeChanged(int mode); void onModeChanged(int mode);
}; };
@ -612,7 +615,7 @@ public:
int frame) override; int frame) override;
void update(int frame) override; void update(int frame) override;
QSize getPreferedSize() override { return QSize(50, 20); } QSize getPreferedSize() override { return QSize(50, 19); }
protected slots: protected slots:
void onChange(bool isDragging = false); void onChange(bool isDragging = false);

View file

@ -83,6 +83,8 @@ set(HEADERS
iwa_fractalnoisefx.h iwa_fractalnoisefx.h
iwa_rainbow_intensity.h iwa_rainbow_intensity.h
iwa_rainbowfx.h iwa_rainbowfx.h
iwa_bokeh_advancedfx.h
iwa_bokeh_util.h
) )
if(OpenCV_FOUND) if(OpenCV_FOUND)
@ -275,6 +277,8 @@ set(SOURCES
iwa_glarefx.cpp iwa_glarefx.cpp
iwa_fractalnoisefx.cpp iwa_fractalnoisefx.cpp
iwa_rainbowfx.cpp iwa_rainbowfx.cpp
iwa_bokeh_advancedfx.cpp
iwa_bokeh_util.cpp
) )
if(OpenCV_FOUND) if(OpenCV_FOUND)

View file

@ -0,0 +1,321 @@
#include "iwa_bokeh_advancedfx.h"
#include "trop.h"
#include "trasterfx.h"
#include "trasterimage.h"
#include <QReadWriteLock>
#include <QMutexLocker>
#include <QVector>
#include <QMap>
#include <QSet>
namespace {
QReadWriteLock lock;
QMutex fx_mutex;
bool isFurtherLayer(const QPair<int, double> val1,
const QPair<int, double> val2) {
// if the layers are at the same depth, then put the layer with smaller index
// above
if (val1.second == val2.second) return val1.first > val2.first;
return val1.second > val2.second;
}
template <typename T>
TRasterGR8P allocateRasterAndLock(T** buf, TDimensionI dim) {
TRasterGR8P ras(dim.lx * sizeof(T), dim.ly);
ras->lock();
*buf = (T*)ras->getRawData();
return ras;
}
// release all registered raster memories and free all fft plans
void releaseAllRastersAndPlans(QList<TRasterGR8P>& rasterList,
QList<kiss_fftnd_cfg>& planList) {
for (int r = 0; r < rasterList.size(); r++) rasterList.at(r)->unlock();
for (int p = 0; p < planList.size(); p++) kiss_fft_free(planList.at(p));
}
}; // namespace
//--------------------------------------------
// sort source images
QList<int> Iwa_BokehAdvancedFx::getSortedSourceIndices(double frame) {
QList<QPair<int, double>> usedSourceList;
// gather connected sources
for (int i = 0; i < LAYER_NUM; i++) {
if (m_layerParams[i].m_source.isConnected())
usedSourceList.push_back(
QPair<int, double>(i, m_layerParams[i].m_distance->getValue(frame)));
}
if (usedSourceList.empty()) return QList<int>();
// sort by distance
std::sort(usedSourceList.begin(), usedSourceList.end(), isFurtherLayer);
QList<int> indicesList;
for (int i = 0; i < usedSourceList.size(); i++) {
indicesList.push_back(usedSourceList.at(i).first);
}
return indicesList;
}
//--------------------------------------------
// Compute the bokeh size for each layer. The source tile will be enlarged by
// the largest size of them.
QMap<int, double> Iwa_BokehAdvancedFx::getIrisSizes(
const double frame, const QList<int> sourceIndices,
const double bokehPixelAmount, double& maxIrisSize) {
// create a list of available reference image ports
QList<int> availableCtrPorts;
for (int i = 0; i < getInputPortCount(); ++i) {
QString portName = QString::fromStdString(getInputPortName(i));
if (portName.startsWith("Depth") && getInputPort(i)->isConnected())
availableCtrPorts.push_back(portName.remove(0, 5).toInt());
}
double focus = m_onFocusDistance->getValue(frame);
double max = 0.0;
QMap<int, double> irisSizes;
for (int s = 0; s < sourceIndices.size(); s++) {
int index = sourceIndices.at(s);
double layer = m_layerParams[index].m_distance->getValue(frame);
double adjust = m_layerParams[index].m_bokehAdjustment->getValue(frame);
double irisSize;
// In case there is no available reference image
if (m_layerParams[index].m_depth_ref->getValue() == 0 ||
!availableCtrPorts.contains(
m_layerParams[index].m_depth_ref->getValue())) {
irisSize = (focus - layer) * bokehPixelAmount * adjust;
}
// in case using the reference image
else {
double refRangeHalf =
m_layerParams[index].m_depthRange->getValue(frame) * 0.5;
double nearToFocus = focus - layer + refRangeHalf;
double farToFocus = focus - layer - refRangeHalf;
// take further point from the focus distance
if (std::abs(nearToFocus) > std::abs(farToFocus))
irisSize = nearToFocus * bokehPixelAmount * adjust;
else
irisSize = farToFocus * bokehPixelAmount * adjust;
}
irisSizes[index] = irisSize;
// update the maximum
if (max < std::abs(irisSize)) max = std::abs(irisSize);
}
maxIrisSize = max;
return irisSizes;
}
//-----------------------------------------------------
// return true if the control image is available and used
bool Iwa_BokehAdvancedFx::portIsUsed(int portIndex) {
for (int layer = 0; layer < LAYER_NUM; layer++) {
if (m_layerParams[layer].m_source.isConnected() &&
m_layerParams[layer].m_depth_ref->getValue() == portIndex)
return true;
}
return false;
}
//--------------------------------------------
Iwa_BokehAdvancedFx::Iwa_BokehAdvancedFx()
: m_hardnessPerSource(false), m_control("Depth") {
// Bind common parameters
bindParam(this, "on_focus_distance", m_onFocusDistance, false);
bindParam(this, "bokeh_amount", m_bokehAmount, false);
bindParam(this, "masterHardness", m_hardness, false);
bindParam(this, "hardnessPerSource", m_hardnessPerSource, false);
// Bind layer parameters
for (int layer = 0; layer < LAYER_NUM; layer++) {
m_layerParams[layer].m_distance = TDoubleParamP(0.5);
m_layerParams[layer].m_bokehAdjustment = TDoubleParamP(1);
m_layerParams[layer].m_hardness = TDoubleParamP(0.3);
m_layerParams[layer].m_depth_ref = TIntParamP(0);
m_layerParams[layer].m_depthRange = TDoubleParamP(1.0);
std::string str = QString("Source%1").arg(layer + 1).toStdString();
addInputPort(str, m_layerParams[layer].m_source);
bindParam(this, QString("distance%1").arg(layer + 1).toStdString(),
m_layerParams[layer].m_distance);
bindParam(this, QString("bokeh_adjustment%1").arg(layer + 1).toStdString(),
m_layerParams[layer].m_bokehAdjustment);
bindParam(this, QString("hardness%1").arg(layer + 1).toStdString(),
m_layerParams[layer].m_hardness);
bindParam(this, QString("depth_ref%1").arg(layer + 1).toStdString(),
m_layerParams[layer].m_depth_ref);
bindParam(this, QString("depthRange%1").arg(layer + 1).toStdString(),
m_layerParams[layer].m_depthRange);
m_layerParams[layer].m_distance->setValueRange(0.0, 1.0);
m_layerParams[layer].m_bokehAdjustment->setValueRange(0.0, 2.0);
m_layerParams[layer].m_hardness->setValueRange(0.05, 3.0);
m_layerParams[layer].m_depthRange->setValueRange(0.0, 1.0);
}
addInputPort("Depth1", new TRasterFxPort, 0);
}
//--------------------------------------------
void Iwa_BokehAdvancedFx::doCompute(TTile& tile, double frame,
const TRenderSettings& settings) {
// If the iris is not connected, then do nothing
if (!m_iris.isConnected()) {
tile.getRaster()->clear();
return;
}
// If none of the source ports is connected, then do nothing
bool sourceIsConnected = false;
for (int i = 0; i < LAYER_NUM; i++) {
if (m_layerParams[i].m_source.isConnected()) {
sourceIsConnected = true;
break;
}
}
if (!sourceIsConnected) {
tile.getRaster()->clear();
return;
}
// Sort source layers by distance
QList<int> sourceIndices = getSortedSourceIndices(frame);
// Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
double bokehPixelAmount = BokehUtils::getBokehPixelAmount(
m_bokehAmount->getValue(frame), settings.m_affine);
// Compute the bokeh size for each layer. The source tile will be enlarged by
// the largest size of them.
double maxIrisSize;
QMap<int, double> irisSizes =
getIrisSizes(frame, sourceIndices, bokehPixelAmount, maxIrisSize);
int margin = (int)std::ceil(maxIrisSize * 0.5);
TRectD _rectOut(tile.m_pos, TDimensionD(tile.getRaster()->getLx(),
tile.getRaster()->getLy()));
_rectOut = _rectOut.enlarge(static_cast<double>(margin));
TDimensionI dimOut(static_cast<int>(_rectOut.getLx() + 0.5),
static_cast<int>(_rectOut.getLy() + 0.5));
// Enlarge the size to the "fast size" for kissfft which has no factors other
// than 2,3, or 5.
if (dimOut.lx < 10000 && dimOut.ly < 10000) {
int new_x = kiss_fft_next_fast_size(dimOut.lx);
int new_y = kiss_fft_next_fast_size(dimOut.ly);
// margin should be integer
while ((new_x - dimOut.lx) % 2 != 0)
new_x = kiss_fft_next_fast_size(new_x + 1);
while ((new_y - dimOut.ly) % 2 != 0)
new_y = kiss_fft_next_fast_size(new_y + 1);
_rectOut = _rectOut.enlarge(static_cast<double>(new_x - dimOut.lx) / 2.0,
static_cast<double>(new_y - dimOut.ly) / 2.0);
dimOut.lx = new_x;
dimOut.ly = new_y;
}
// compute the input tiles
QMap<int, TTile*> sourceTiles;
for (auto index : sourceIndices) {
TTile* layerTile = new TTile();
m_layerParams[index].m_source->allocateAndCompute(
*layerTile, _rectOut.getP00(), dimOut, tile.getRaster(), frame,
settings);
sourceTiles[index] = layerTile;
}
// obtain pixel size of original iris image
TRectD irisBBox;
m_iris->getBBox(frame, irisBBox, settings);
// compute the iris tile
TTile irisTile;
m_iris->allocateAndCompute(
irisTile, irisBBox.getP00(),
TDimension(static_cast<int>(irisBBox.getLx() + 0.5),
static_cast<int>(irisBBox.getLy() + 0.5)),
tile.getRaster(), frame, settings);
// compute the reference image
std::vector<TRasterGR8P> ctrl_rasters; // to be stored in uchar
QMap<int, unsigned char*>
ctrls; // container of [port number, reference image buffer in uchar]
for (int i = 0; i < getInputPortCount(); ++i) {
QString portName = QString::fromStdString(getInputPortName(i));
if (portName.startsWith("Depth") && getInputPort(i)->isConnected()) {
int portIndex = portName.remove(0, 5).toInt();
if (portIsUsed(portIndex)) {
TTile tmpTile;
TRasterFxPort* tmpCtrl = dynamic_cast<TRasterFxPort*>(getInputPort(i));
(*tmpCtrl)->allocateAndCompute(tmpTile, _rectOut.getP00(), dimOut,
tile.getRaster(), frame, settings);
TRasterGR8P ctrlRas(dimOut.lx, dimOut.ly);
ctrlRas->lock();
unsigned char* ctrl_mem = (unsigned char*)ctrlRas->getRawData();
TRaster32P ras32 = (TRaster32P)tmpTile.getRaster();
TRaster64P ras64 = (TRaster64P)tmpTile.getRaster();
lock.lockForRead();
if (ras32)
BokehUtils::setDepthRaster<TRaster32P, TPixel32>(ras32, ctrl_mem,
dimOut);
else if (ras64)
BokehUtils::setDepthRaster<TRaster64P, TPixel64>(ras64, ctrl_mem,
dimOut);
lock.unlock();
ctrl_rasters.push_back(ctrlRas);
ctrls[portIndex] = ctrl_mem;
}
}
}
double masterHardness = m_hardness->getValue(frame);
QList<LayerValue> layerValues;
for (auto index : sourceIndices) {
LayerValue layerValue;
layerValue.sourceTile = sourceTiles[index];
layerValue.premultiply =
false; // assuming input images are always premultiplied
layerValue.layerHardness =
(m_hardnessPerSource->getValue())
? m_layerParams[index].m_hardness->getValue(frame)
: masterHardness;
layerValue.depth_ref = m_layerParams[index].m_depth_ref->getValue();
layerValue.irisSize = irisSizes.value(index);
layerValue.distance = m_layerParams[index].m_distance->getValue(frame);
layerValue.bokehAdjustment =
m_layerParams[index].m_bokehAdjustment->getValue(frame);
layerValue.depthRange = m_layerParams[index].m_depthRange->getValue(frame);
layerValue.distancePrecision = 10;
layerValue.fillGap = true;
layerValue.doMedian = false;
layerValues.append(layerValue);
}
Iwa_BokehCommonFx::doFx(tile, frame, settings, bokehPixelAmount, margin,
dimOut, irisBBox, irisTile, layerValues, ctrls);
// release control image buffers
for (int r = 0; r < ctrl_rasters.size(); r++) ctrl_rasters[r]->unlock();
qDeleteAll(sourceTiles);
}
//--------------------------------------------
FX_PLUGIN_IDENTIFIER(Iwa_BokehAdvancedFx, "iwa_BokehAdvancedFx")

View file

@ -0,0 +1,70 @@
#pragma once
//----------------------------------------
// Iwa_BokehAdvancedFx
// Advanced version of Bokeh Fx Iwa
// - Enabled to set different hardness for each layer
// - Enabled to apply the depth referene image for each layer
//----------------------------------------
#ifndef IWA_BOKEH_ADVANCED_H
#define IWA_BOKEH_ADVANCED_H
#include "stdfx.h"
#include "tfxparam.h"
#include "traster.h"
#include "kiss_fft.h"
#include "tools/kiss_fftnd.h"
#include "iwa_bokeh_util.h"
#include <array>
#include <QThread>
const int LAYER_NUM = 5;
//------------------------------------
class Iwa_BokehAdvancedFx : public Iwa_BokehCommonFx {
FX_PLUGIN_DECLARATION(Iwa_BokehAdvancedFx)
protected:
TFxPortDG m_control;
TBoolParamP m_hardnessPerSource; // switch between layer and master hardness
struct LAYERPARAM {
TRasterFxPort m_source;
TDoubleParamP m_distance; // The layer distance from the camera (0-1)
TDoubleParamP m_bokehAdjustment; // Factor for adjusting distance (= focal
// distance - layer distance) (0-2.0)
TDoubleParamP m_hardness; // film gamma for each layer
TIntParamP m_depth_ref; // port index of depth reference image
TDoubleParamP m_depthRange; // distance range varies depends on the
// brightness of the reference image (0-1)
};
std::array<LAYERPARAM, LAYER_NUM> m_layerParams;
// sort source images
QList<int> getSortedSourceIndices(double frame);
// Compute the bokeh size for each layer. The source tile will be enlarged by
// the largest size of them.
QMap<int, double> getIrisSizes(const double frame,
const QList<int> sourceIndices,
const double bokehPixelAmount,
double& maxIrisSize);
// return true if the control image is available and used
bool portIsUsed(int portIndex);
public:
Iwa_BokehAdvancedFx();
void doCompute(TTile& tile, double frame,
const TRenderSettings& settings) override;
int dynamicPortGroupsCount() const override { return 1; }
const TFxPortDG* dynamicPortGroup(int g) const override {
return (g == 0) ? &m_control : 0;
}
};
#endif

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

@ -21,89 +21,13 @@ distributed with a 3-clause BSD-style license.
#include <QThread> #include <QThread>
#include "tools/kiss_fftnd.h" #include "tools/kiss_fftnd.h"
#include "iwa_bokeh_util.h"
const int LAYER_NUM = 5; const int LAYER_NUM = 5;
struct double2 { class Iwa_BokehFx : public Iwa_BokehCommonFx {
double x, y;
};
struct int2 {
int x, y;
};
class MyThread : public QThread {
public:
enum Channel { Red = 0, Green, Blue };
private:
Channel m_channel;
volatile bool m_finished;
TRasterP m_layerTileRas;
TRasterP m_outTileRas;
TRasterP m_tmpAlphaRas;
kiss_fft_cpx *m_kissfft_comp_iris;
float m_filmGamma; // keep the film gamma in each thread as it is refered so
// often
TRasterGR8P m_kissfft_comp_in_ras, m_kissfft_comp_out_ras;
kiss_fft_cpx *m_kissfft_comp_in, *m_kissfft_comp_out;
kiss_fftnd_cfg m_kissfft_plan_fwd, m_kissfft_plan_bkwd;
bool m_isTerminated;
// not used for now
bool m_doLightenComp;
public:
MyThread(Channel channel, TRasterP layerTileRas, TRasterP outTileRas,
TRasterP tmpAlphaRas, kiss_fft_cpx *kissfft_comp_iris,
float m_filmGamma,
bool doLightenComp = false); // not used for now
// Convert the pixels from RGB values to exposures and multiply it by alpha
// channel value.
// Store the results in the real part of kiss_fft_cpx.
template <typename RASTER, typename PIXEL>
void setLayerRaster(const RASTER srcRas, kiss_fft_cpx *dstMem,
TDimensionI dim);
// Composite the bokeh layer to the result
template <typename RASTER, typename PIXEL, typename A_RASTER,
typename A_PIXEL>
void compositLayerToTile(const RASTER layerRas, const RASTER outTileRas,
const A_RASTER alphaRas, TDimensionI dim,
int2 margin);
void run();
bool isFinished() { return m_finished; }
// RGB value <--> Exposure
float valueToExposure(float value);
float exposureToValue(float exposure);
// memory allocation
bool init();
void terminateThread() { m_isTerminated = true; }
bool checkTerminationAndCleanupThread();
};
class Iwa_BokehFx : public TStandardRasterFx {
FX_PLUGIN_DECLARATION(Iwa_BokehFx) FX_PLUGIN_DECLARATION(Iwa_BokehFx)
protected:
TRasterFxPort m_iris;
TDoubleParamP m_onFocusDistance; // Focus Distance (0-1)
TDoubleParamP m_bokehAmount; // The maximum bokeh size. The size of bokeh at
// the layer separated by 1.0 from the focal
// position
TDoubleParamP m_hardness; // Film gamma
struct LAYERPARAM { struct LAYERPARAM {
TRasterFxPort m_source; TRasterFxPort m_source;
TBoolParamP m_premultiply; TBoolParamP m_premultiply;
@ -114,36 +38,17 @@ protected:
// Sort source layers by distance // Sort source layers by distance
QList<int> getSortedSourceIndices(double frame); QList<int> getSortedSourceIndices(double frame);
// Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
float getBokehPixelAmount(const double frame, const TAffine affine);
// Compute the bokeh size for each layer. The source tile will be enlarged by // Compute the bokeh size for each layer. The source tile will be enlarged by
// the largest size of them. // the largest size of them.
QVector<float> getIrisSizes(const double frame, QMap<int, double> getIrisSizes(const double frame,
const QList<int> sourceIndices, const QList<int> sourceIndices,
const float bokehPixelAmount, float &maxIrisSize); const double bokehPixelAmount,
//"Over" composite the layer to the output raster. double &maxIrisSize);
void compositLayerAsIs(TTile &tile, TTile &layerTile, const double frame,
const TRenderSettings &settings, const int index);
// Resize / flip the iris image according to the size ratio.
// Normalize the brightness of the iris image.
// Enlarge the iris to the output size.
void convertIris(const float irisSize, kiss_fft_cpx *kissfft_comp_iris_before,
const TDimensionI &dimOut, const TRectD &irisBBox,
const TTile &irisTile);
// Do FFT the alpha channel.
// Forward FFT -> Multiply by the iris data -> Backward FFT
void calcAlfaChannelBokeh(kiss_fft_cpx *kissfft_comp_iris, TTile &layerTile,
TRasterP tmpAlphaRas);
public: public:
Iwa_BokehFx(); Iwa_BokehFx();
void doCompute(TTile &tile, double frame, const TRenderSettings &settings) override; void doCompute(TTile &tile, double frame, const TRenderSettings &settings) override;
bool doGetBBox(double frame, TRectD &bBox, const TRenderSettings &info) override;
bool canHandle(const TRenderSettings &info, double frame) override;
}; };
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -21,56 +21,17 @@ distributed with a 3-clause BSD-style license.
#include <QThread> #include <QThread>
#include "tools/kiss_fftnd.h" #include "tools/kiss_fftnd.h"
#include "iwa_bokeh_util.h"
struct float4 {
float x, y, z, w;
};
//------------------------------------ //------------------------------------
class BokehRefThread : public QThread { class Iwa_BokehRefFx : public Iwa_BokehCommonFx {
int m_channel;
volatile bool m_finished;
kiss_fft_cpx* m_fftcpx_channel_before;
kiss_fft_cpx* m_fftcpx_channel;
kiss_fft_cpx* m_fftcpx_alpha;
kiss_fft_cpx* m_fftcpx_iris;
float4* m_result_buff;
kiss_fftnd_cfg m_kissfft_plan_fwd, m_kissfft_plan_bkwd;
TDimensionI m_dim;
bool m_isTerminated;
public:
BokehRefThread(int channel, kiss_fft_cpx* fftcpx_channel_before,
kiss_fft_cpx* fftcpx_channel, kiss_fft_cpx* fftcpx_alpha,
kiss_fft_cpx* fftcpx_iris, float4* result_buff,
kiss_fftnd_cfg kissfft_plan_fwd,
kiss_fftnd_cfg kissfft_plan_bkwd, TDimensionI& dim);
void run() override;
bool isFinished() { return m_finished; }
void terminateThread() { m_isTerminated = true; }
};
//------------------------------------
class Iwa_BokehRefFx : public TStandardRasterFx {
FX_PLUGIN_DECLARATION(Iwa_BokehRefFx) FX_PLUGIN_DECLARATION(Iwa_BokehRefFx)
protected: protected:
TRasterFxPort m_iris; // iris image
TRasterFxPort m_source; // source image TRasterFxPort m_source; // source image
TRasterFxPort m_depth; // depth reference image TRasterFxPort m_depth; // depth reference image
TDoubleParamP m_onFocusDistance; // Focus Distance (0-1)
TDoubleParamP m_bokehAmount; // The maximum bokeh size. The size of bokeh at
// the layer separated by 1.0 from the focal
// position
TDoubleParamP m_hardness; // Film gamma
TIntParamP m_distancePrecision; // Separation of depth image TIntParamP m_distancePrecision; // Separation of depth image
TBoolParamP m_fillGap; // Toggles whether to extend pixels behind the front TBoolParamP m_fillGap; // Toggles whether to extend pixels behind the front
@ -81,14 +42,6 @@ protected:
TBoolParamP m_doMedian; // (Effective only when the Fill Gap option is ON) TBoolParamP m_doMedian; // (Effective only when the Fill Gap option is ON)
// Toggles whether to use Median Filter for extending the pixels. // Toggles whether to use Median Filter for extending the pixels.
// Get the pixel size of bokehAmount ( referenced ino_blur.cpp )
float getBokehPixelAmount(const double frame, const TAffine affine);
// normalize the source raster image to 0-1 and set to dstMem
// returns true if the source is (seems to be) premultiplied
template <typename RASTER, typename PIXEL>
bool setSourceRaster(const RASTER srcRas, float4* dstMem, TDimensionI dim);
// normalize brightness of the depth reference image to unsigned char // normalize brightness of the depth reference image to unsigned char
// and store into dstMem // and store into dstMem
template <typename RASTER, typename PIXEL> template <typename RASTER, typename PIXEL>
@ -98,97 +51,11 @@ protected:
void setDepthRasterGray(const RASTER srcRas, unsigned char* dstMem, void setDepthRasterGray(const RASTER srcRas, unsigned char* dstMem,
TDimensionI dim); TDimensionI dim);
// create the depth index map
void defineSegemntDepth(const unsigned char* indexMap_main,
const unsigned char* indexMap_sub,
const float* mainSub_ratio,
const unsigned char* depth_buff,
const TDimensionI& dimOut, const double frame,
QVector<float>& segmentDepth_main,
QVector<float>& segmentDepth_sub);
// set the result
template <typename RASTER, typename PIXEL>
void setOutputRaster(float4* srcMem, const RASTER dstRas, TDimensionI dim,
TDimensionI margin);
// obtain iris size from the depth value
float calcIrisSize(const float depth, const float bokehPixelAmount,
const double onFocusDistance);
// resize/invert the iris according to the size ratio
// normalize the brightness
// resize to the output size
void convertIris(const float irisSize, const TRectD& irisBBox,
const TTile& irisTile, const TDimensionI& enlargedDim,
kiss_fft_cpx* fftcpx_iris_before);
// convert source image value rgb -> exposure
void convertRGBToExposure(const float4* source_buff, int size,
float filmGamma, bool sourceIsPremultiplied);
// generate the segment layer source at the current depth
// considering fillGap and doMedian options
void retrieveLayer(const float4* source_buff,
const float4* segment_layer_buff,
const unsigned char* indexMap_mainSub, int index, int lx,
int ly, bool fillGap, bool doMedian, int margin);
// apply single median filter
void doSingleMedian(const float4* source_buff,
const float4* segment_layer_buff,
const unsigned char* indexMap_mainSub, int index, int lx,
int ly, const unsigned char* generation_buff, int curGen);
// normal-composite the layer as is, without filtering
void compositeAsIs(const float4* segment_layer_buff,
const float4* result_buff_mainSub, int size);
// retrieve segment layer image for each channel
void retrieveChannel(const float4* segment_layer_buff, // src
kiss_fft_cpx* fftcpx_r_before, // dst
kiss_fft_cpx* fftcpx_g_before, // dst
kiss_fft_cpx* fftcpx_b_before, // dst
kiss_fft_cpx* fftcpx_a_before, // dst
int size);
// multiply filter on channel
void multiplyFilter(kiss_fft_cpx* fftcpx_channel, // dst
kiss_fft_cpx* fftcpx_iris, // filter
int size);
// normal comosite the alpha channel
void compositeAlpha(const float4* result_buff, // dst
const kiss_fft_cpx* fftcpx_alpha, // alpha
int lx, int ly);
// interpolate main and sub exposures
// convert exposure -> RGB (0-1)
// set to the result
void interpolateExposureAndConvertToRGB(
const float4* result_main_buff, // result1
const float4* result_sub_buff, // result2
const float* mainSub_ratio, // ratio
float filmGamma,
const float4* source_buff, // dst
int size);
public: public:
Iwa_BokehRefFx(); Iwa_BokehRefFx();
void doCompute(TTile& tile, double frame, const TRenderSettings& settings) override; void doCompute(TTile& tile, double frame,
const TRenderSettings& settings) override;
bool doGetBBox(double frame, TRectD& bBox, const TRenderSettings& info) override;
bool canHandle(const TRenderSettings& info, double frame) override;
void doCompute_CPU(const double frame, const TRenderSettings& settings,
float bokehPixelAmount, float maxIrisSize, int margin,
TDimensionI& dimOut, float4* source_buff,
unsigned char* indexMap_main, unsigned char* indexMap_sub,
float* mainSub_ratio, QVector<float>& segmentDepth_main,
QVector<float>& segmentDepth_sub, TTile& irisTile,
TRectD& irisBBox, bool sourceIsPremultiplied);
}; };
#endif #endif

View file

@ -43,6 +43,8 @@
#include <QDesktopServices> #include <QDesktopServices>
#include <QUrl> #include <QUrl>
#include <QGuiApplication>
#include <QScreen>
using namespace DVGui; using namespace DVGui;
@ -249,7 +251,6 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
if (shrinkStr != "" || modeSensitiveStr != "") { if (shrinkStr != "" || modeSensitiveStr != "") {
QWidget *tmpWidget; QWidget *tmpWidget;
if (shrinkStr != "") { if (shrinkStr != "") {
tmpWidget = new QWidget(this);
shrink = QString::fromStdString(shrinkStr).toInt(); shrink = QString::fromStdString(shrinkStr).toInt();
std::string label = is.getTagAttribute("label"); std::string label = is.getTagAttribute("label");
QCheckBox *checkBox = new QCheckBox(this); QCheckBox *checkBox = new QCheckBox(this);
@ -262,9 +263,7 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
int currentRow = m_mainLayout->rowCount(); int currentRow = m_mainLayout->rowCount();
m_mainLayout->addLayout(sepLay, currentRow, 0, 1, 2); m_mainLayout->addLayout(sepLay, currentRow, 0, 1, 2);
m_mainLayout->setRowStretch(currentRow, 0); m_mainLayout->setRowStretch(currentRow, 0);
//--- signal-slot connection tmpWidget = new ModeSensitiveBox(this, checkBox);
connect(checkBox, SIGNAL(toggled(bool)), tmpWidget,
SLOT(setVisible(bool)));
checkBox->setChecked(shrink == 1); checkBox->setChecked(shrink == 1);
tmpWidget->setVisible(shrink == 1); tmpWidget->setVisible(shrink == 1);
} else { // modeSensitiveStr != "" } else { // modeSensitiveStr != ""
@ -421,7 +420,7 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
throw TException("unexpected tag " + tagName); throw TException("unexpected tag " + tagName);
} }
/*-- 表示コントロールをconnect --*/ /*-- 表示コントロールをconnect --*/
if (controller_bpf) { if (controller_bpf && (!on_items.isEmpty() || !off_items.isEmpty())) {
/*-- ラベルとWidgetを両方表示/非表示 --*/ /*-- ラベルとWidgetを両方表示/非表示 --*/
for (int i = 0; i < on_items.size(); i++) { for (int i = 0; i < on_items.size(); i++) {
connect(controller_bpf, SIGNAL(toggled(bool)), on_items[i], connect(controller_bpf, SIGNAL(toggled(bool)), on_items[i],
@ -433,6 +432,8 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
SLOT(setHidden(bool))); SLOT(setHidden(bool)));
off_items[i]->show(); off_items[i]->show();
} }
connect(controller_bpf, SIGNAL(toggled(bool)), this,
SIGNAL(preferredPageSizeChanged()));
} else } else
std::cout << "controller_bpf NOT found!" << std::endl; std::cout << "controller_bpf NOT found!" << std::endl;
} else } else
@ -448,11 +449,8 @@ void ParamsPage::setPageField(TIStream &is, const TFxP &fx, bool isVertical) {
void ParamsPage::setPageSpace() { void ParamsPage::setPageSpace() {
if (m_fields.count() != 0) { if (m_fields.count() != 0) {
QWidget *spaceWidget = new QWidget();
int currentRow = m_mainLayout->rowCount(); int currentRow = m_mainLayout->rowCount();
m_mainLayout->addWidget(spaceWidget, currentRow, 0, 1, 2);
for (int i = 0; i < currentRow; i++) m_mainLayout->setRowStretch(i, 0); for (int i = 0; i < currentRow; i++) m_mainLayout->setRowStretch(i, 0);
m_mainLayout->setRowStretch(currentRow, 1); m_mainLayout->setRowStretch(currentRow, 1);
} }
@ -636,29 +634,25 @@ void updateMaximumPageSize(QGridLayout *layout, int &maxLabelWidth,
} }
} }
int itemCount = 0;
/*-- Widget側の最適な縦サイズおよび横幅の最大値を得る --*/ /*-- Widget側の最適な縦サイズおよび横幅の最大値を得る --*/
QMap<int, int> heightsByMode;
int maxModeHeight = 0;
for (int r = 0; r < layout->rowCount(); r++) { for (int r = 0; r < layout->rowCount(); r++) {
/*-- Column1にある可能性のあるものParamField, Histogram, Layout, /*-- Column1にある可能性のあるものParamField, Histogram, Layout,
* RgbLinkButtons --*/ * RgbLinkButtons --*/
QLayoutItem *item = layout->itemAtPosition(r, 1); QLayoutItem *item = layout->itemAtPosition(r, 1);
if (!item) continue; if (!item || (item->widget() && item->widget()->isHidden())) continue;
ModeSensitiveBox *box = dynamic_cast<ModeSensitiveBox *>(item->widget()); ModeSensitiveBox *box = dynamic_cast<ModeSensitiveBox *>(item->widget());
if (box) { if (box) {
if (!box->isActive()) continue;
// if (box->isHidden()) continue; // if (box->isHidden()) continue;
QGridLayout *innerLay = dynamic_cast<QGridLayout *>(box->layout()); QGridLayout *innerLay = dynamic_cast<QGridLayout *>(box->layout());
if (!innerLay) continue; if (!innerLay) continue;
int tmpHeight = 0; int tmpHeight = 0;
updateMaximumPageSize(innerLay, maxLabelWidth, maxWidgetWidth, tmpHeight); updateMaximumPageSize(innerLay, maxLabelWidth, maxWidgetWidth, tmpHeight);
for (int mode : box->modes()) { fieldsHeight += tmpHeight;
heightsByMode[mode] += tmpHeight;
maxModeHeight = std::max(maxModeHeight, heightsByMode[mode]);
}
// attempt to align the label column
innerLay->setColumnMinimumWidth(0, maxLabelWidth); innerLay->setColumnMinimumWidth(0, maxLabelWidth);
continue; continue;
} }
@ -666,10 +660,10 @@ void updateMaximumPageSize(QGridLayout *layout, int &maxLabelWidth,
QSize itemSize = getItemSize(item); QSize itemSize = getItemSize(item);
if (maxWidgetWidth < itemSize.width()) maxWidgetWidth = itemSize.width(); if (maxWidgetWidth < itemSize.width()) maxWidgetWidth = itemSize.width();
fieldsHeight += itemSize.height(); fieldsHeight += itemSize.height();
itemCount++;
} }
if (maxModeHeight > 0) fieldsHeight += maxModeHeight;
if (layout->rowCount() > 1) fieldsHeight += (layout->rowCount() - 1) * 10; if (itemCount >= 1) fieldsHeight += itemCount * 10;
} }
}; // namespace }; // namespace
@ -1585,10 +1579,17 @@ void FxSettings::onViewModeChanged(QAction *triggeredAct) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void FxSettings::onPreferredSizeChanged(QSize pvBestSize) { void FxSettings::onPreferredSizeChanged(QSize pvBestSize) {
DockWidget *popup = dynamic_cast<DockWidget *>(parentWidget());
if (!popup || !popup->isFloating()) return;
QSize popupBestSize = pvBestSize; QSize popupBestSize = pvBestSize;
static int maximumHeight =
(QGuiApplication::primaryScreen()->geometry().height()) * 0.9;
// Set minimum size, just in case // Set minimum size, just in case
popupBestSize.setHeight(std::max(popupBestSize.height(), 85)); popupBestSize.setHeight(
std::min(std::max(popupBestSize.height(), 85), maximumHeight));
popupBestSize.setWidth(std::max(popupBestSize.width(), 390)); popupBestSize.setWidth(std::max(popupBestSize.width(), 390));
if (m_toolBar->isVisible()) { if (m_toolBar->isVisible()) {
@ -1597,14 +1598,11 @@ void FxSettings::onPreferredSizeChanged(QSize pvBestSize) {
std::max(popupBestSize.width(), m_viewer->width() + 13)); std::max(popupBestSize.width(), m_viewer->width() + 13));
} }
DockWidget *popup = dynamic_cast<DockWidget *>(parentWidget());
if (popup && popup->isFloating()) {
QRect geom = popup->geometry(); QRect geom = popup->geometry();
geom.setSize(popupBestSize); geom.setSize(popupBestSize);
popup->setGeometry(geom); popup->setGeometry(geom);
popup->update(); popup->update();
} }
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -1304,14 +1304,30 @@ ModeSensitiveBox::ModeSensitiveBox(QWidget *parent,
ModeChangerParamField *modeChanger, ModeChangerParamField *modeChanger,
QList<int> modes) QList<int> modes)
: QWidget(parent), m_modes(modes) { : QWidget(parent), m_modes(modes) {
m_currentMode = m_modes.first();
connect(modeChanger, SIGNAL(modeChanged(int)), this, connect(modeChanger, SIGNAL(modeChanged(int)), this,
SLOT(onModeChanged(int))); SLOT(onModeChanged(int)));
} }
ModeSensitiveBox::ModeSensitiveBox(QWidget *parent, QCheckBox *checkBox)
: QWidget(parent) {
m_modes << 1;
connect(
checkBox, &QCheckBox::stateChanged, this,
[=]() { onModeChanged(checkBox->isChecked() ? 1 : 0); },
Qt::AutoConnection);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void ModeSensitiveBox::onModeChanged(int modeValue) { void ModeSensitiveBox::onModeChanged(int modeValue) {
setVisible(m_modes.contains(modeValue)); bool wasVisible = isVisible();
m_currentMode = modeValue;
if (wasVisible == m_modes.contains(modeValue)) return;
setVisible(!wasVisible);
ParamsPage *paramsPage = dynamic_cast<ParamsPage *>(parentWidget());
if (paramsPage) emit paramsPage->preferredPageSizeChanged();
} }
//============================================================================= //=============================================================================