大きくなったら大蛇に

Python始めたての初心者による学習ブログです

ステレオグラムの作り方_基本編3 (背景画像を深度マップの画像サイズに並べる)

Pythonステレオグラムを作りたい

 ステレオグラムの作り方_基本編2の続きになります。

 

③背景画像を深度マップの画像サイズに並べる

次はステレオグラム作成の肝の部分です。

128×64ピクセルの背景画像を600×400ピクセルの深度マップ画像と同じサイズになるように並べていきます。このとき、深度マップの画像データの白丸部分は、背景画像をずらして配置する必要があります。

 

では、参考サイトから拝借したコードで実行してみたいと思います。
<参考サイト>

Pythonでオリジナルのランダムドットステレオグラム(RDS)を作る。 - Qiita

Making Your Own Autostereograms using Python | Frolian's blog (flothesof.github.io)

 

In[4]

 def normalize(depthmap):
        return depthmap/255  

In[5]

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')

 

いやぁ、もう何をやっているのか全然分からないけど出来てしまいました。画像の中心に〇が浮かんでいるのが見えます。

あまりの分からなさに怖気づいてしまっていますが、頑張ってコードを読んでいきます。

 
In[4]

 def normalize(depthmap):
        return depthmap/255  

0~255の数字でできているdepthmapのデータを255で割る関数を作ってますね。
depthmapが0~1の値になるようにしているようです。
 
 
 In[5]

1、17、19、20行目

def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
      …
    return autostereogram
 
autostereogram = make_autostereogram(depthmap, pattern, 0.3)
plt.imshow(autostereogram, cmap='gray')

”make_autostereogram”という名前で何かしらの関数を作って、"autostereogram"で

それを実行し、その結果をpltの機能を使ってグレースケールで表示させているんですね。

 

2行目

    depthmap = normalize(depthmap)

前に定義したnormalizeという関数で正規化を実施。

 

4行目、5行目:

    if invert: 
        depthmap = 1 - depthmap 

if False…?ネガポジ変換?わからないのでパス。

 

6行目:

    autostereogram = np.zeros_like(depthmap, dtype=pattern.dtype) 

”autostereogram”で深度マップと同じピクセルサイズの600×400ピクセルの画像を

作ってます。中身のデータは”0”なので、黒一色の画面になっているってことですね。

 

8行目:

    for r in np.arange(autostereogram.shape[0]): 

np.arangeは等差の数列を返す関数です。

 <np.arange([start, ]stop, [step, ]dtype = None)>
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
start:生成する数列の最初の値。初期値は0
stop:生成する数列の最後の値。
step:1ステップ分の差。初期値は1
dtype:生成される数列のデータ型
 
戻り値:stepで指定した等差数列の配列
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
 また、
autostereogram.shape[0]は行(row・縦)の(ピクセル)数
autostereogram.shape[1]は列(col・横)のピクセル
autostereogram.shape[2]は(色の)チャンネル
 です。
 autostereogramの縦のピクセル数と同じだけ繰り返すと書いてあるので、つまり
『今から以下の事を400回繰り返します』、と宣言してます。
 
10行目

        for c in np.arange(autostereogram.shape[1]): 

これも8行目と同じです。autostereogramの横のピクセル数と同じだけ繰り返すと書いてあるので、『今から以下の事を600回繰り返します』、と宣言してます。

 
11行目

            if c < pattern.shape[1]: 

これは『autostereogramの横サイズがpatternの横サイズよりも小さいうちは』ですね

 

12行目

                autostereogram[r, c] = pattern[r % pattern.shape[0], c]

ここではrとcはそれぞれautostereogramの縦と横のピクセルの位置なので ”autostereogram[r, c]”は縦r、横cのポイントの画素の情報ということになります。

次に”pattern[r % pattern.shape[0], c]”ですがa%bは a をbで割った余りを表します。つまり”r % pattern.shape[0]”は rをpattern.shape[0]つまり128で割った余りの値が入ります。

・・・? 何してるのこれ。

例えば、

autostereogramの縦のピクセル数が65のとき

129÷128=1余り1

autostereogramの縦のピクセル数が100のとき

200÷128=1余り72

あ、なるほど!割ったときの余りが0~127に変化するのを利用して、patternを1枚貼ったら次に新しいものを貼るという繰り返しをしているんですね。すごい!頭いい!

 

13、14行目 

              else:
                shift = int(depthmap[r, c] * shift_amplitude * pattern.shape[1])

ええと。

それ以外ならshiftは〇〇に設定するって感じですね。ここが一番大事なところかな。

 

 depthmap:画像を白黒で作ってるので depthmap[r, c]の答えは"0"か"1"しかない

 shift_amplitude:初期値は0.1(defの中の初期値なので後で任意の値に変えられる)

 pattern.shape[1]:横のピクセル数64

 

ということは

  depthmapの黒い背景部分

    0×0.1×64=0

  depthmapの白い円の部分

    1×0.1×64=6.4 ⇒intなので整数部分の6

となって、白い円の部分に該当するピクセルのときだけshiftに値が入るんですね。 

今は画像を白黒でしか作っていませんけど、灰色だったら灰色のシフト量になるように書かれれるから、灰色を使ったらもっとリアルな奥行き感とか影とかが出せそうです。

 

15行目 

                   autostereogram[r, c] = autostereogram[r, c - pattern.shape[1] + shift]

さて、最後の難関。 問題は ”c - pattern.shape[1] + shift”の部分ですね。

  ●depthmapの黒い背景部分だとshift=0で

     c - 64 + 0

  例えばr=200,c=100なら

               autostereogram[r, c]= autostereogram[200, 46]

  autostereogram[200, 46]の部分には12行目のpatternの値が入っているので

  それが参照されるので、patternが連続しているように見える。

 

  ●depthmapの白い円の部分だとshift=6で、

    c - 64 + 6

  depthmapの黒い背景部分までは連続していたパターンが+6ピクセル分ずれて

  入ることになる。

 

ほぉぉ!

 それだけで立体的に見えるものなんですね。視覚って不思議。

 

ともあれ、これでステレオグラムの作り方の基本をマスターしました!!

ここからはこれをベースに好きな画像で作っていきたいと思います。