#はじめに
桑原フィルターとは
前記事で桑原フィルターについて解説していますのでご参照ください。
#今回は
今回は前記事の最後にチラっと提案した、
"深度マップを用意してそれによって正方形領域のサイズを調整したら面白いかも…"
を実際にやってみたいと思います。
この発想は前回の、正方形領域の一辺が一定でフィルターをかけた画像に対して、メインの被写体がはっきりしない(どこにもピントが合っていない)状態だと、絵画というよりは背景に見えるという意見を元に得たものです。
#実装
前回の記事に対して、コードの意味が理解できない(しづらい)という意見も見られたので、計算速度度外視の"そのまんま"コードで書きました。
とはいえ、Pythonにあまり大量のループをそのままさせるのは実行時間が大変なことになりますのでJITコンパイラ
に力をお借りしました。
Numba(JITを含むライブラリ)が入っていない人は、JITコンパイラライブラリNumbaを使ってPythonコードを劇的に高速化する方法などを参考にしてください。
import matplotlib.pyplot as plt
import numpy as np
import cv2
from numba import jit
@jit
def mean(arr):
h, w, c = arr.shape
avg = np.array([0]*c)
for i in range(h):
for j in range(w):
for k in range(c):
avg[k] += arr[i, j, k]
return avg/(h*w)
@jit
def var(arr, mean):
h, w, c = arr.shape
vari = 0
for i in range(h):
for j in range(w):
for k in range(c):
vari += (arr[i, j, k]-mean[k])**2
return vari
@jit
def kuwahara_with_depth(pic, r, r_min, depth):
h, w, c = pic.shape
out = np.empty_like(pic)
pic = np.pad(pic, ((r, r), (r, r), (0, 0)), "edge")
depth = depth/depth.max()
surr = ((1, 0), (0, 1), (1, 1))
for i in range(h):
for j in range(w):
dr = int(depth[i, j]*(r-r_min))+r_min
arr = pic[i+r-dr:i+r, j+r-dr:j+r]
avg = mean(arr)
var_min = var(arr, avg)
color = avg
for s, t in surr:
arr = pic[i+r-(1-s)*dr:i+r+s*dr, j+r-(1-t)*dr:j+r+t*dr]
avg = mean(arr)
vari = var(arr, avg)
if vari < var_min:
color = avg
var_min = vari
out[i, j] = color
return out
def main(picpath, r, r_min, rate, depthpath): #入力画像のパス、正方形領域の一辺の最大値、正方形領域の一辺の最小値、画像サイズの縮小率、深度マップのパス
pic = np.array(plt.imread(picpath))
pic = cv2.resize(pic, (int(pic.shape[1]*rate), int(pic.shape[0]*rate)))
depth = cv2.resize(np.array(plt.imread(depthpath)[:, :, 0]), (pic.shape[1], pic.shape[0]))
# depth=cv2.resize(np.rot90(np.array(plt.imread(depthpath))[:,:,0]),(pic.shape[1],pic.shape[0])) #深度マップの向きが元画像と合っていない時用
fpic = kuwahara_with_depth(pic, r, r_min, depth).astype(pic.dtype)
plt.imshow(fpic)
# plt.imshow(np.rot90(fpic,3)) #出力画像が横を向いてしまっている時用
plt.show()
picpath = "input_pic.jpg" #入力画像のパス
depthpath = "depthmap.jpg" #深度マップ画像のパス
if __name__ == "__main__":
main(picpath, 20, 3, 0.5, depthpath)
#結果
今回もフランスの写真から、フレンチネッコをサンプルに使用します。
上記までの説明では深度マップと表現していましたが、当然そんなデータはありませんので何らかの方法でそれらしい画像を作ります。今回はフォトショで適当に作りました。ちなみに白いほど正方形領域の一辺は大きくなります。
(一部の背景ぼかしが使えるスマホの写真ファイルには深度マップの情報が含まれているようです。Google Camera Deph map を使用したステレオ画像/多視点画像作成)
これらを用いて今回のフィルターをかけたものがこちらです。是非クリックして拡大して見てみてください。
写真と絵が自然に融合しような、レンズのボケの代わりに絵の具でぼかしたような、そんな不思議な仕上がりです。
#まとめ
サンプルで用いた写真でも、正方形領域の最大最小値で印象が大きく変わると思います。
上手く調節すれば主題と背景がしっかり描き分けられた絵画のようになるかもしれませんし、フォトジェニックが求められる昨今、タイトルで示したとおり一風変わった写真表現としても活用できると思います。
一度試してみてはいかがでしょうか。