ステレオグラムの作り方_実践編4(GIFアニメを作る)
■どんなステレオグラムを作ろうか
ステレオグラムを見るのは目のピント調節機能を鍛えるから、目にいいといいますが、いかんせん同じ画像をボケーっと見てるのは飽きるんですよね。慣れるとすぐピントを合わせられちゃうからピント調節の訓練している気がしないし。
私にとってのステレオグラムの欠点って「飽きる」なのです。
そこで、楽しく飽きずにステレオグラムを見続けられるためにステレオグラムを動かしたいと思いました。
■ステレオグラムの深度マップを動かしてみよう
今までに習得したあれこれで3Dの深度マップを作ってみました。
これで、人が歩いているようなアニメにしてみたい。
そこでもう一枚準備しました。
この2枚の画像でステレオグラムを作って、それをパラパラ漫画にしたら歩いているように見えるんじゃないかと。
よし、とりあえずやってみよう。
それぞれの画像から作ったステレオグラムは↓
ではパラパラ漫画にしてみましょう!
★GIFアニメを作るコマンド★
from PIL import Image
img_walking=[]
for i in range(2):
file_name='./in_img/gif/walking' +str(i+1)+ '.jpg'
img = Image.open(file_name)
img_walking.append(img)
2行目
file名の”str(i+1)”について
画像ファイル名は連番にしていて、小さい番号のファイルから順に読んでもらいたかったので、最初は
file_name='./in_img/gif/walking' +i+ '.jpg'
していたのですが、
can only concatenate str (not "int") to strとエラーが出ました。
この書き方はだめなのですね。
str(i+1)(※str(i)だと0から始まってしまうので。)でstrで囲って文字列にするとうまくいきました。(iが変数扱いのままにできるのが不思議…)
3行目
Imageモジュールのopen関数で画像を開く。
Image.open("画像のPath”)
4行目
リスト名.append()で、画像のファイル名とデータをimg_walkingに入れていく
ln[3] #gifアニメを出力する
img_walking[0].save('./out_img/walking.gif',save_all=True, append_images=img_walking[1:],
optimize=True, duration=800, loop=0)
静止画ファイルからGIFを作るのは以下コマンド。
img_walking[0].save( #リスト名[0].saveで画像の保存
'./out_img/walking.gif', #保存先Path名/ファイル名.gif
save_all=True, #ループの回数
append_images=img_walking[1:], #リスト名[0]に[1]以降の画像をつなげる
optimize=True, #??
duration=800, # フレームの表示時間 ミリ秒
loop=0 #ループ回数。無限にしたいときはゼロ
)
おお、イメージ通りにできました!
ただちょっとチカチカして目が疲れそう。もうちょっと滑らかに変化して貰いたいなぁ。うーん。どうしましょう。
OpneCVのフレーム補間って急な画像変化の緩衝に使えるでしょうか。。。
それとも深度マップ画像をモーフィングで徐々に変化させて動画のフレーム周波数を上げる?
なにかいい方法がないものでしょうか。。。
なお、今回はPILでgifにしましたが、OpenCVでmp4動画にすることもできました。
このあと画像を横にスライドさせて歩いている感を出したいと考えているので、画像をOpenCVで色々操作するならOpenCVで統一した方がいいかもしれないと後から思いました。
ステレオグラムの作り方_実践編3(2Dシルエット画像から3D画像を作る)
■前回までの取り組み
前回の更新から間が空いてしまったのでおさらいします。
<前回取り組んだ課題>
好きな背景画像で、
好きな深度マップ画像を使い、ステレオグラムを作ろうとしたところ、
3D表示にならないはずの箇所も部分的に3D表示になってしまった。
(余計な3D部分をゴミと呼んでいます。)
<出てきた解決策>
深度マップ画像を3Dグラフィック画像にする。
3Dグラフィック化にはBlenderという有名なフリーソフトが存在するのでそれを
使うのが良い。
ところがこのBlenderの使い方が簡単には行かなくて。
ちゃんと勉強しないと使いこなせなさそうだったので、心が折れそうになっていました。
だけど!今はPythonを勉強しているのです。
ならば3Dグラフィック化はPythonでするべきではないだろうかと思い至りました。
■Pythonで2Dシルエット画像から3D画像を作る
色々調べてみて、参考にしたのは以下の2サイトです。
【第15回Python流体の数値計算】2次元ポアソン方程式をPythonで実装する。|宇宙に入ったカマキリ (takun-physics.net)
こちらは何をしているのか感覚的に理解するのに使わせていただきました
方程式を解いたわけではないので正確に理解はできていないですけど。。
GitHub - unclearness/inflation_py: Generate a height/depth map and a mesh from a single silhouette.
こちらはソースをいただきました。
難しい説明はできません。
白黒のシルエット画像のエッジ端からの距離で、立体度を変える処理をしてくれています。単純にエッジ端からの距離だけで立体化しても滑らかな曲線は描けないので、ポワソン方程式を解く+αで滑らかな曲線にしているということらしいです。
ではもらってきたソースで、試しにシルエット画像の棒人間くんを3Dグラフィック化してみましょう。
import cv2
import numpy as np
from scipy.sparse import coo_matrix, linalg
def depth2orthomesh(depth, x_step=1, y_step=1, scale=[1.0, 1.0, 1.0], minus_depth=True):
vertices =
faces =
if len(depth.shape) != 2:
return None
h, w = depth.shape
vertex_id = 0
added_table = {}
for y in range(0, h, y_step):
for x in range(0, w, x_step):
added_table[(y, x)] = -1
max_connect_z_diff = 99999.9
# TODO
# pixel-wise loop in pure python is toooooooo slow
for y in range(0, h, y_step):
for x in range(0, w, x_step):
d = depth[y, x]
if d <= 0.000001:
continue
if minus_depth:
d = -d
vertices.append([x * scale[0], y * scale[1], d * scale[2]])
added_table[(y, x)] = vertex_id
current_index = vertex_id
upper_left_index = added_table[(
upper_index = added_table[(
left_index = added_table[(y, (x - x_step)
upper_left_diff = np.abs(depth[y - y_step, x - x_step] - d)
upper_diff = np.abs(depth[y - y_step, x] - d)
left_diff = np.abs(depth[y, x - x_step] - d)
if upper_left_index > 0 and upper_index > 0\
and upper_left_diff < max_connect_z_diff\
and upper_diff < max_connect_z_diff:
faces.append([upper_left_index, current_index, upper_index])
if upper_left_index > 0 and left_index > 0\
and upper_left_diff < max_connect_z_diff\
and left_diff < max_connect_z_diff:
faces.append([upper_left_index, left_index, current_index])
vertex_id += 1
return vertices, faces
def _make_ply_txt(vertices, faces, color=, normal=):
header_lines = ["ply", "format ascii 1.0",
"element vertex " + str(len(vertices)),
"property float x", "property float y", "property float z"]
has_normal = len(vertices) == len(normal)
has_color = len(vertices) == len(color)
if has_normal:
header_lines += ["property float nx",
"property float ny", "property float nz"]
if has_color:
header_lines += ["property uchar red", "property uchar green",
"property uchar blue", "property uchar alpha"]
# no face
header_lines += ["element face " + str(len(faces)),
"property list uchar int vertex_indices", "end_header"]
header = "\n".join(header_lines) + "\n"
data_lines =
for i in range(len(vertices)):
line = [vertices[i][0], vertices[i][1], vertices[i][2]]
if has_normal:
line += [normal[i][0], normal[i][1], normal[i][2]]
if has_color:
line += [int(color[i][0]), int(color[i][1]), int(color[i][2]), 255]
line_txt = " ".join([str(x) for x in line])
data_lines.append(line_txt)
for f in faces:
line_txt = " ".join(['3'] + [str(int(x)) for x in f])
data_lines.append(line_txt)
data_txt = "\n".join(data_lines)
ply_txt = header + data_txt
return ply_txt
# Implementation of the following paper
# "Notes on Inflating Curves" [Baran and Lehtinen 2009].
# http://alecjacobson.com/weblog/media/notes-on-inflating-curves-2009-baran.pdf
def inflationByBaran(mask, use_sparse=True):
h, w = mask.shape
depth = np.zeros((h, w))
img2param_idx = {}
param_idx = 0
def get_idx(x, y):
return y * w + x
for y in range(h):
for x in range(w):
c = mask[y, x]
if c != 0:
img2param_idx[get_idx(x, y)] = param_idx
param_idx += 1
num_param = len(img2param_idx.keys())
triplets =
cur_row = 0
# 4 neighbor laplacian
for y in range(1, h-1):
for x in range(1, w-1):
c = mask[y, x]
if c == 0:
continue
triplets.append([cur_row, img2param_idx[get_idx(x, y)], -4.0])
kernels = [(y, x - 1), (y, x + 1), (y - 1, x), (y + 1, x)]
for kernel in kernels:
jj, ii = kernel
if mask[jj, ii] != 0:
triplets.append([cur_row, img2param_idx[get_idx(ii, jj)], 1.0])
cur_row += 1 # Go to the next equation
# Prepare right hand side
b = np.zeros(
rhs = -4.0
cur_row = 0
for y in range(1, h-1):
for x in range(1, w-1):
c = mask[y, x]
if c == 0:
continue
b[cur_row] = rhs
cur_row += 1
if use_sparse:
# Sparse matrix version
data, row, col = , , []
for tri in triplets:
row.append(tri[0])
col.append(tri[1])
data.append(tri[2])
data = np.array(data)
row = np.array(row, dtype=np.int64)
col = np.array(col, dtype=np.int64)
A = coo_matrix(
x = linalg.spsolve(A, b)
else:
# Dense matrix version
A = np.zeros(
# Set from triplets
for tri in triplets:
row = tri[0]
col = tri[1]
val = tri[2]
A[row, col] = val
x = np.linalg.solve(A, b)
for j in range(1, h-1):
for i in range(1, w-1):
c = mask[j, i]
if c == 0:
continue
idx = img2param_idx[get_idx(i, j)]
# setting z = √ h
depth[j, i] = np.sqrt(x[idx])
return depth
def visualizeDepth(depth, path='', dmin=0, dmax=50, cm_name='viridis'):
import matplotlib.pyplot as plt
cm = plt.get_cmap(cm_name)
colors = (
colors = colors[..., ::-1] # -> BGR
normed = np.clip(
normed = (normed*255).astype(np.uint8)
vis = colors[normed]
if path != '':
cv2.imwrite(path, vis)
return vis
def writeMeshAsPly(path, vertices, faces):
with open(path, 'w') as f:
txt = _make_ply_txt(vertices, faces)
f.write(txt)
if __name__ == '__main__':
names = ['walking1']
for name in names:
mask_path = 'Path名/' + name + '.png'
print(mask_path)
mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
mask[mask > 100] = 255
mask[mask <= 100] = 0
depth = inflationByBaran(mask)
visualizeDepth(depth, name + '_baran.jpg')
vertices, faces = depth2orthomesh(depth)
writeMeshAsPly(name + '_baran.ply', vertices, faces)
def make_pattern(shape=(16, 16), levels=64 ):
return np.random.randint( 0, levels - 1, shape)/ levels
pattern = make_pattern(shape=(128,64))
def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
if invert:
depthmap = 1 - depthmap
autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype)
for r in np.arange(autostereogram.shape[0]):
for c in np.arange(autostereogram.shape[1]):
if c < pattern.shape[1]:
autostereogram[r, c] = pattern[r % pattern.shape[0], c]
else:
shift = int(depthmap[r, c] * shift_amplitude * pattern.shape[1])
autostereogram[r, c] = autostereogram[r, c - pattern.shape[1] + shift]
return autostereogram
ln[3] #ステレオグラム化
pattern = make_pattern(shape=(128,64))
depthmap = cv2.imread("Path/ファイル名.jpg")
depthmap = cv2.cvtColor(depthmap, cv2.COLOR_BGR2GRAY)
depthmap = depthmap/255
autostereogram = make_autostereogram(depthmap, pattern, 0.3)
autostereogram = np.clip(autostereogram * 255, a_min = 0, a_max = 255).astype(np.uint8)
cv2.imwrite("Path/ファイル名.jpg", autostereogram)
完了!
出来上がったものがこちらです。
ステレオグラムの作り方_実践編2(ゴミ対応)
■謎のゴミを消す
ステレオグラムの作り方_実践編1で発見されたゴミの対応を検討していきます。
前回作り上げた菜の花畑のステレオグラムですが、下図の赤線の形のゴミが出てしまっていました。特にピントを雲に合わせると見えやすいです。
深度マップは↓なので、間には何もないはずなのですが。
なんとなく察するに。。。立体の処理?が閉じていないというか。。。
左目用の画像はあるけど、右目用の画像を作らないまま立体にしてしまったような。
こうならなきゃいけないのに
今こんな感じ
深度マップに書かれている絵は2Dなのに3Dで表現しようとしているから奥行き表現を出さないといけない箇所で視差が生じなくておかしくなるのかな?
3Dグラフィックで立体的な雲を描いたら直るかもしれないですね。
・・・雲の絵を3Dグラフィックで描く???
どうやって?
・・・
調べてきました。
3Dグラフィックソフト「Blender」というフリーソフトがあり、これで3Dグラフィックを描けるそうです。ただし慣れが必要。GIMPより難しそうです。
さすがに雲は描けないなぁ。。
妥協してBlenderで球を描いてみました。これが精いっぱいです。
普通の2Dの円と3Dの球で比較しようと思います。
仮定が正しければ2Dではゴミが発生して、3Dではゴミが出ないはず。
まず、円をステレオグラムにした画像。
円の表面にピントを合わせるとゴミが見えますね。
次、球をステレオグラムにした画像だと。
見えません!成功です!
そっか、立体に見せようとすると、深度マップの画像も3Dで描くべきなんですね。
いやーでもBlender難しいなぁ。
ステレオグラムの作り方_実践編1(菜の花畑)
■ステレオグラムのデザインを考えよう
今日はステレオグラムのデザインをします。夢が広がる部分ですね。
まずは深度マップから。
深度マップの色の濃さによって3Dの浮き上がり度合いが変わると分かったときから、やってみたかったことがあります。
ステレオグラムをきれいな風景写真で作ってみたいのですが、浮き上がり度合いが変えられるのなら、風景を前景、中景、後景に分けて表現してみたいのです。前景は白にして一番大きく浮き上がらせて、中景はグレーに、後景は黒に近い灰色にして奥の方にという感じです。
背景には写真を使いますが、その写真にも遠近感をつけたいと思います。
こんな感じ↓
試行錯誤して、前景~空までのバランスを下のようにしました。あと、何も絵がないと寂しいので空に雲でも書いておきましょう。画像サイズは無難そうな1280×720にします。
では、上の深度マップに合わせる背景の写真を準備します。
以前スイカジュースの写真で試した時の感触から、背景写真の横のサイズは128ピクセルぐらいにとどめておいた方が良さそうです。
縦は深度マップのそれぞれ前景・中景・後景・空の高さと同じになるように作ります。
前景の画像
128(横)×64(縦)サイズ
中景の画像
128(横)×144(縦)サイズ
後景の画像
128(横)×92(縦)サイズ
空の画像
128(横)×420(縦)サイズ
これをPythonでくっつけます。
import numpy as np
import cv2
img1 = cv2.imread('画像のPath/ファイル名')
img2 = cv2.imread('画像のPath/ファイル名')
img3 = cv2.imread('画像のPath/ファイル名')
img4 = cv2.imread('画像のPath/ファイル名')
img5 = cv2.imread('画像のPath/ファイル名') pattern_imshape=[1080,128,3]
pattern = np.zeros(pattern_imshape, dtype= img1.dtype)
pattern = cv2.vconcat([img1,img2,img3,img4,img5])
cv2.imwrite(’保存先のPath/ファイル名' , pattern)
できた画像がこちらです。↓
128(横)×720(縦)サイズ
これで深度マップも背景の元も完成しました。
これをステレオグラム化のアルゴリズム(ステレオグラムの作り方_応用編3から変更なし)に放り込んでみます!
■ステレオグラム化
import numpy as np
import matplotlib.pyplot as plt
import cv2
In[2] #上で作った背景の元を読み込む
pattern = cv2.imread('画像のPath/ファイル名'')
pattern = cv2.cvtColor(pattern, cv2.COLOR_BGR2RGB)
img_depth = cv2.imread('画像のPath/ファイル名')
img_depth = cv2.cvtColor(depth_grad, cv2.COLOR_BGR2RGB)
def make_depthmap(shape=(720,1280,3)):
black_img = np.zeros(shape, dtype=np.float64)
depthmap = (black_img + img_depth)/255
return depthmap depthmap = make_depthmap()
def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
if invert:
depthmap = 1 - depthmap
autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype) for color in np.arange(autostereogram.shape[2]):
for r in np.arange(autostereogram.shape[0]):
for c in np.arange(autostereogram.shape[1]):
if c < pattern.shape[1]:
autostereogram[r, c, color] = pattern[r % pattern.shape[0], c, color]
else:
shift = int(depthmap[r, c, color] * shift_amplitude * pattern.shape[1])
autostereogram[r, c, color] = autostereogram[r, c - int(pattern.shape[1]) + shift, color]
return autostereogram
autostereogram = make_autostereogram(depthmap, pattern, 0.3)
plt.imshow(autostereogram)
よーしよしよしできました!
いざ!チェック!
おお
おお?
おや?
前景・中景・後景の見え方は大体期待通りではあるけれど、、、
雲の右側になんかゴミが残ってますね。
あと、左端から横128ピクセルまでは立体になってませんね。左の雲が切れちゃってます。
横0~128ピクセル目までは背景の元のパターンをそのまま貼っているから、よく考えたらそりゃそうですが横0~128ピクセルまでの画像を参照して129ピクセル目以降を作っているのでこれはやむなしかな。。。
うーん。雲の右側のゴミ。
これは気持ち悪いなぁ。
次はこのゴミを消す方法を考えていきたいと思います。
ステレオグラムの作り方_応用編3(カラー化)
■好きな画像でステレオグラムを作りたい
今回はいよいよカラー化をします。
ステレオグラムが作れることが分かると、次は綺麗なステレオグラムを見たくなってきてしまいました。
綺麗なステレオグラムを作るのにあたってカラー化は必須!
しっかり考えていきましょう。
背景は「ステレオグラムの作り方_応用編1」で使ったスイカジュースの画像を使います。
import numpy as np
import matplotlib.pyplot as plt
import cv2
In[2] #背景の元を作成
pattern = cv2.imread('画像のPath')
pattern = cv2.cvtColor(pattern, cv2.COLOR_BGR2RGB)
plt.imshow(pattern)
表示は無事にカラー化できました。
cv2で画像を読み込んでいるので色の並びがBGRになっています。cv2.cvtColorで画像データの並びをBGRからRGBに変換します。
plt.imshowのカラーマップは何を選んで良いか分からなかったので何も記載しませんでしたが、いい感じにカラー化してくれました。ありがとう。
次に深度マップですがこちらも「ステレオグラムの作り方_応用編2」で使った深度マップを使い回します。
depth_grad = cv2.imread('画像のPath/ファイル名.png')
depth_grad = cv2.cvtColor(depth_grad, cv2.COLOR_BGR2RGB)
def make_depthmap(shape=(400,600,3)):
black_img = np.zeros(shape, dtype=np.float64)
depthmap = (black_img + depth_grad)/255
return depthmap
depthmap = make_depthmap()
plt.imshow(depthmap, cmap="gray")
使い回しはしますが、shapeの型だけは背景画像のカラーと揃えておきます。
グレースケールの時はshapeが(400,600)でしたが、背景がカラーになったので
背景画像と同じカラーの型でshapeが(400,600,3)となるようにしておきます。
詳細は下のIn[5]にて。
In[4] #基本編1からずっとやってきた正規化は削除です。
def normalize(depthmap):
return depthmap/255
カラー化したらdepthmapの最大値が255じゃなくなったようで、255のままだとエラーが出るようになりました。そもそも正規化する意味が見つけられなかったので、必要性が理解できるときまで、削除しておきます。
def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
if invert:
depthmap = 1 - depthmap
autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype) for color in np.arange(autostereogram.shape[2]):
for r in np.arange(autostereogram.shape[0]):
for c in np.arange(autostereogram.shape[1]):
if c < pattern.shape[1]:
autostereogram[r, c] = pattern[r % pattern.shape[0], c]
else:
shift = int(depthmap[r, c] * shift_amplitude * pattern.shape[1])
autostereogram[r, c] = autostereogram[r, c - pattern.shape[1] + shift]
return autostereogram
autostereogram = make_autostereogram(depthmap, pattern, 0.3)
plt.imshow(autostereogram)
さて、問題はIn[5]ですね。
ステレオグラム化のアルゴリズムでは、背景の元になるスイカジュースの画像を台紙(深度マップと同じサイズの台紙)に並べてペタペタ貼っていくことをしています。
いままではグレースケール画像だったのでモノクロ用の台紙1枚だけに「台紙(深度マップ画像と同じサイズ)いっぱいになるまで背景画像を貼り続ける」ということを"for ** in "で実行すればよかったのですが、ここにカラーという要素が加わります。
カラーになると背景画像を張り付ける台紙が赤・緑・青の3枚に増えます。(下図のイメージ)
なので、 「深度マップ画像の縦サイズと横サイズいっぱいになるまで貼り続ける」ということを3回繰り返さないといけないです。
グレースケールの時 カラーの時
"for ** in range(3)"
と書いても動くと思いますが、格好をつけたいのでautostereogram.shapeの値を使いたいと思います。
"autostereogram.shape"と打つと(400,600,3)と出ます。 3番目の3が赤・緑・青の台紙の3色を表現してくれるので、これを
for color in np.arange(autostereogram.shape[2]):
という形で使います。
結果がこちら↓
おおおお!いい感じではないですか。
すごいすごい!
では、次回はちょっとヒネリを入れったデザインでステレオグラムを作っていきます!
ステレオグラムの作り方_応用編2(深度マップを作る)
■好きな画像でステレオグラムを作りたい
今回はステレオグラムで3D表示させたいものを作っていきます。
基本編では白黒の円を表示させてました。ステレオグラム化のアルゴリズムを見ると灰色も判別してくれるようなので、灰色も入れた深度マップを作りたいと思います。
試しに使ってみたのがこの3パターン
8諧調のグラデーション
16諧調のグラデーション
256諧調のグラデーション
それぞれどんな見え方になるのか確認ます。
背景はまずはランダムドットノイズに設定します。
import numpy as np
import matplotlib.pyplot as plt
import cv2
def make_pattern(shape=(16,16), levels=64):
return np.random.randint(0, levels-1, shape)/ levels
pattern= make_pattern(shape=(128,64))
depth_grad = cv2.imread('画像のPath/ファイル名.png')
depth_grad = cv2.cvtColor(depth_grad, cv2.COLOR_BGR2GRAY)
def make_depthmap(shape=(400, 600)):
depthmap = np.zeros(shape, dtype=np.float64)
depthmap = depthmap+depth_grad
return depthmap
depthmap = make_depthmap()
plt.imshow(depthmap, cmap="gray")
In[4] #正規化
def normalize(depthmap):
return depthmap/255
def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
depthmap = normalize(depthmap)
if invert:
depthmap = 1 - depthmap
autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype)
for r in np.arange(autostereogram.shape[0]):
for c in np.arange(autostereogram.shape[1]):
if c < pattern.shape[1]:
autostereogram[r, c] = pattern[r % pattern.shape[0], c]
else:
shift = int(depthmap[r, c] * shift_amplitude * pattern.shape[1])
autostereogram[r, c] = autostereogram[r, c - pattern.shape[1] + shift]
return autostereogram
autostereogram = make_autostereogram(depthmap, pattern, 0.3)
plt.imshow(autostereogram, cmap='gray')
できました!
おお!諧調ごとに飛び出し具合が違いますね。
おや?
入力した深度マップは上から
8段階
16段階
256段階
の諧調があるので、上から
8段の階段
16段の階段
滑らかな坂
に見えるのかと予想していましたが、一番下、20段数段しか階段できていませんね。
計算してみたら丸められていたりするんでしょうか。
背景のパターンを128×64サイズで作っているから限界があるのか。背景のランダムドットノイズがそもそも64諧調しかないからダメなのか。。背景を写真でも作ってみましたがやっぱり滑らかな坂にはなりませんでした。
ふむ。この辺は宿題として残しておきます。(溜まる一方)
何はともあれ、諧調を変えることで飛び出し具合を変えることができることが分かりました!
次はカラー化に挑戦しようと思います。
ステレオグラムを作ろう_応用編1(背景を変更)
■好きな画像でステレオグラムを作りたい
●好きな画像で背景を作る
基本編ではランダムドットノイズを背景に使用していましたが、見ていて楽しいものを背景にしたいので、自分で用意した画像を背景にしてステレオグラムを作っていきます。
使用する画像はこちら。スイカジュースの写真です。
基本編1で使ったランダムドットノイズ作成のコードを書き換えてみました。
import numpy as np
import matplotlib.pyplot as plt
import cv2
pattern = cv2.imread('画像のPath/ファイル名.jpg')
plt.imshow(pattern, cmap= "gray")
グレースケールに変えたつもりでいるのに、グレースケールにならない不思議。
紫色になったのはcv2で画像を読み込んでいるので色の並びが逆になっているせいだとわかっていますが(変換をさぼりました)。。。実に気持ち悪い色になったものだ。
matplotlibでグレースケールにしようとしても効かなくて、cv2.cvtColorの方でグレースケールにしないと変わらないのかな?
ならこれは?
cv2でグレースケール化してmatplotlibの方のグレースケール化を削除してみました。
pattern = cv2.imread('画像のPath')
pattern = cv2.cvtColor(pattern, cv2.COLOR_BGR2GRAY)
plt.imshow(pattern)
わぁ。悪化した。
ならば!
cv2でグレースケール化もmatplotlibの方のグレースケール化も入れてみました。
pattern = cv2.imread('画像のPath')
pattern = cv2.cvtColor(pattern, cv2.COLOR_BGR2GRAY)
plt.imshow(pattern , cmap='gray')
ようやく成功です。
グレースケールの画像を表示させるだけでずいぶん苦労しましたが、以降のコードに変更はありません。出来上がった画像はこちら。↓
あらら。写真の縦128×横68はちょっと大きかったかもしれません。
でもちゃんと円が見えます。
見え方が変わるのかと思い、画像サイズを変えてみました。
さっきの半分縦64×横34です
見えますが、あまりに小さいと背景の画像が何なのか分からないので面白くなくなってしまいそうです。
これは画像によって微調整が必要ですね。
次は深度マップを好きな画像に変えてみたいと思います。