Python
OpenCV
numpy

水滴を落としたように画像を歪める処理をpythonで組んでみた

More than 1 year has passed since last update.


やりたいこと

画像中に、水滴を落としたようなエフェクトを乗っける

素材は他の記事から使いまわしの、以下の硬貨の画像です。

coin_series_b.png

今回は、50円玉のところに水滴を落としてみようと思います。


環境


  • python 3.6.1

  • opencv 3.4.1+contrib

  • numpy 1.14.3

  • jupyter notebook上で処理しています。


方法

水滴による屈折があると、見ている位置と実際に見える位置がずれる、という現象を利用して、水滴っぽい見え方を再現します。

具体的には、水滴を置いた部分のピクセルの色を、少しずれた部分のピクセルの色で置き換える、ということになります。

作成したコードはこちら。

#画像の読み込みとBGR→RGBの変換

img_BGR = cv2.imread("coin_series_b.png")
img_RGB = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2RGB)

#画像サイズの取得
height = np.shape(img_RGB)[0]
width = np.shape(img_RGB)[1]

#水滴を落としたあとの画像として、元画像のコピーを作成。後処理で
img_RGB_2 = img_RGB.copy()

#水滴の中心と半径の指定
center = np.array((50,400))
r = 45

#ピクセルの座標を変換
for x in range(width):
for y in range(height):
#dはこれから処理を行うピクセルの、水滴の中心からの距離
d = np.linalg.norm(center - np.array((y,x)))

#dが水滴の半径より小さければ座標を変換する処理をする
if d < r:
#vectorは変換ベクトル。説明はコード外で。
vector = (d / r)**1.4 * (np.array((y,x)) - center)

#変換後の座標を整数に変換
p = (center + vector).astype(np.int32)

#色のデータの置き換え
img_RGB_2[y,x,:]=img_RGB[p[0],p[1],:]

vector = (d / r)**1.4 * (np.array((y,x)) - center) の処理について、少し解説します。

後半の「(np.array((y,x)) - center)」は、水滴の中心から見た、処理を行う点を指すベクトルです。

前半「(d/r)」は、水滴の中心から処理を行うピクセルまでの距離を、水滴の半径で割ったものです。

この値を1.4乗すると、値が小さくなるのですが、ことで、水滴による見え方の歪みを発生させています。

軸をうまくつけられなかったのですが、横軸が(d/r) 縦軸が(d/r)**1.4の値です。

image.png

y = x の直線から下に凸になっています。つまり、これをベクトルに書けると、もとのベクトルより短いベクトルを生成する事ができます。

下図で、赤矢印のベクトルが、処理を行う点を指すベクトルで、ここに、「(d / r)**1.4 」を書けることで、紫色のベクトルに変わります。

image.png

赤矢印が示す点に、紫矢印が示す点の色を移す(置き換える)ことで、歪ませるわけです。


処理結果

結果として、以下のような画像が得られます。

test.png

50円玉部分が歪んでいるのがわかるかと思います。

水滴ぽいと言えなくもない。


発展

opencvのremapを使えば、もう少しスマートに書けるのかも。

また、水滴の境界部分とか反射とかをつければもっとリアルに見えるかもしれませんね。

今度試します。