乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

画像

見えたら天才
そんな画像があります。

ステレオグラムと言う
立体視画像です。

今回はそれを作っていきます。
解説動画はこちら



さてまずこの立体視というものですが
立体的な視覚を得る方法のことで
画像を立体的に見ることになります。

この立体的に見える画像のことを
ステレオグラム(英: stereogram)
立体画、立体図と呼んでいます。

立体的な印象をもつように描かれた
平面に描かれた図や絵あるいは写真
のことです。

こんなドット絵を見たことないでしょうか?
4つのドットの中二つが重ね合わさるように見ると
立体的に浮かび上がるように見えると思います。
download


コツとしては
右目で左側を見て、左目で右側を見るイメージ
うまく行くと点が浮かび上がってくると思います。

スマホだと厳しいかもしれないので
タブレットやPCで見てみると良いでしょう。


それではここからステレオグラムを
作っていきましょう。

今回作るやつは
ランダム・ドット・ステレオグラム
(英: Random dot stereogram, RDS)

一見ノイズのようにしか見えない画像が
うまく焦点を合わせると
立体が浮かび上がってくる画像です。

レーダー技術者から知覚研究に転じた
ユレス・ベーラさんによって
考案された手法だそうです。

今回はこちらのサイトの手法をそのまま
お借りしています。

参考



まずは背景となるドット画像の用意です。

ライブラリはopencvなどを使用します。
インストールしていないと動かないので
無い方はインストールしてください。
import numpy as np
import matplotlib.pyplot as plt
import cv2
%matplotlib inline

numpyを用いて背景ドット画像を作る関数です。
def make_dots(shape=(16, 16), levels=64):
    return np.random.randint(0, levels - 1, shape) / levels

dots = make_dots(shape=(64, 64))
plt.figure(figsize=(8,8))
plt.imshow(dots, cmap='gray')
plt.show()
dots

最初は円形の画像を浮かび上がらせる
ステレオグラムを作りましょう。

円形画像を作ります。
def make_img(shape=(400, 600)):
    img = np.zeros(shape, dtype=np.float)
    cv2.circle(img, (int(shape[1]/2), int(shape[0]/2)), 100, (255 ,255, 255), -1)
    return img

img = make_img()
plt.figure(figsize=(8,8))
plt.imshow(img, cmap='gray')
plt.show()

dotimg

ステレオグラムを作成する関数です。
こちらは参考サイトのものをそのまま転記しています。
def normalize(depthmap):
    "Normalizes values of depthmap to [0, 1] range."
    if depthmap.max() > depthmap.min():
        return (depthmap - depthmap.min()) / (depthmap.max() - depthmap.min())
    else:
        return depthmap

def make_autostereogram(depthmap, pattern, shift_amplitude=0.1, invert=False):
    "Creates an autostereogram from depthmap and pattern."
    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

最後に実行です。
このコードで円形ステレオグラムが
作成できると思います。
img = make_img()
autostereogram = make_autostereogram(img, dots)
plt.figure(figsize=(8,8))
plt.imshow(autostereogram, cmap='gray')
plt.show()
en

さて、注視すると円が浮かび上がってきませんでしょうか?

目安が無いので難易度は高いですが
見えない方は4つのドットで練習すると
見えるようになるかもしれません。

続いて文字を立体画像にしてみましょう。
まずは文字です。

text=の部分
引数で指定して変えれば他の文字にできます。
def make_text_img(shape=(400, 600), text='p y'):
    img = np.zeros(shape, dtype=np.float)
    font = cv2.FONT_HERSHEY_SIMPLEX
    cv2.putText(img, text, (100, 250), font, 5, (255,255,255), 30, cv2.LINE_AA)
    return img

text_img = make_text_img()
plt.figure(figsize=(8,8))
plt.imshow(text_img, cmap='gray')
plt.show()
py_text

これをステレオグラムにします。
autostereogram = make_autostereogram(text_img, dots)
plt.figure(figsize=(8,8))
plt.imshow(autostereogram, cmap='gray')
plt.show()
py

さてPYの文字が浮かび上がってきませんでしょうか?


最後にクイズです。
これは何と書いてあるでしょうか?

心が汚れている方は読めるはずですwwwwwww
sex


見えた方は動画のコメント欄にでも
コメントしていただけると嬉しいです。

見えたときは興奮、感動すること
間違いない!!!

気合と根性と集中力があれば
見えます。

頑張ってくださいね。
それでは。



今回は久しぶりに
画像加工で遊んでみました。

解説動画はこちら



ソースコードはこちら
import numpy as np 
import cv2
import math
from ipywidgets import interact, IntSlider , Select
import matplotlib.pyplot as plt
%matplotlib inline

x1 = IntSlider(value=1, min=1, max=20, step=1, description='x:',)
y1 = IntSlider(value=1, min=1, max=20, step=1, description='y:',)
files = ['kurochan.jpg','nadaru.png','inachan.jpg','ayase.jpg','gakky.jpg']
selected = Select(description='画像', options=files, rows=5,)

def show_plot(col1, col2 , col3):
    img = cv2.imread('img/' + col3)
    (h, w, c) = img.shape
    flex_x = np.zeros((h,w),np.float32)
    flex_y = np.zeros((h,w),np.float32)
    for y in range(h):
        for x in range(w):
            flex_x[y,x] = x + math.sin(x/30) * col1
            flex_y[y,x] = y + math.cos(y/30) * col2
    dst = cv2.remap(img,flex_x,flex_y,cv2.INTER_LINEAR)
    dst = cv2.cvtColor(dst , cv2.COLOR_BGR2RGB)
    plt.figure(figsize=(10,10))
    plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
    plt.imshow(dst)
    plt.show()

interact(show_plot, col1=x1, col2=y1 , col3 = selected)

実行していただくと
スクリーンショット 2020-11-14 16.04.16

こんな感じでメニューが出るようになっています。
このプログラムの直下にあるimgフォルダの中の
画像を参照するようにしているので
画像を用いる際はfiles変数の右の
ファイル名などを変更して下さい。

実行後は画像名をクリックすると
画像が切り替わります。

x,yは横、縦方向の画像の歪み度を変更します。
大きい数値の方が歪むようになります。

どんな感じになるかと言うと
download
download-1
download-2

かなり別人になるかなーと思いますが
若干元の人の特徴が残っているのが
面白いかなーと思います。

是非遊んでみて下さい。

今回はこれまでです
それでは。

次期総理を決める戦いの真っ最中ということで
スガさんをムキムキにしてみました。

解説動画はこちら



官房長官たるもの
強くなければならないですからね!!

opencvを用いれば画像の加工とかできますので
やりたい方は頑張ってみてくださいね。

ディープフェイクレベル1の問題です。
つまり、誰でも出来てしまうような
レベルの問題だということですね。


プログラムを作ってやってみた結果
良い出来の一部をお送りしたいと思います。

往年の映画スターに合成
スクリーンショット 2020-09-06 15.03.51

一国の総理大臣として
力で問題を解決してくれそうな顔つきですねーー

スクリーンショット 2020-09-06 15.04.01

こちらも往年の映画スターに合成
東南アジアの問題を現地に乗り込んで
解決してくれそうな趣があります。

せっかくだから
毛を生やしてみましょう。

スクリーンショット 2020-09-06 15.04.40


全然生えませんでしたーーーー
誠にすいまメーーんwww

お盆でも暇なので
色々な歴史上の人物を
全部クロちゃんに変えてみました。

解説動画はこちら


 
色々試してみました。

・幕末の人
・絵
・外人
・大統領

全部行けちゃいましたねーー

さっすがクロちゃん
めちゃくちゃ素材として優秀です。

何に合成しても
違和感なし!!

出来上がったやつを
1つ2つ載せておきますで。

リョーマ
download-12


ペリ井さん
download-5


ザビ
download-6


大統領とかのやつは
色々怒られそうな感じしますよね(笑)ー

他にも色々ありますんで
残りは動画の方を
見ていただければと思います。

それでは!!

GOTOキャンペーンと言うことで
各都道府県の標章の中で

ケツに入れたら痛そうな奴を
プログラムで探してみました。

解説動画はこちら





まずは画像ですが

県章一覧

この画像を使ってみます。
Japanese_Prefectural_Emblem

これが県の標章だそうです。
そんなものがあるとは知りませんでしたが
これをケツに入れるには
ケツの穴の大きさが間に合わないので
仮想で考えます。


どうやってケツに入れたら
痛いかどうかを考えればよいでしょうか?

画像の輪郭から角度を求めてあげて
その角度が少ないやつが痛そうですよね。

と言うわけで
この画像を縦横で切り分けて保存しました。
(6x8画像)

1県ずつ
輪郭を求めてみます。

輪郭を求めるコードは次の通りで
opencvを用いています。

%matplotlib inline
import cv2
import numpy as np
import matplotlib.pyplot as plt

file_path = 'img/5_7.png'
img = cv2.imread(file_path)

# 領域抽出
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, binarized = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(binarized, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 領域描画
line_color , line_size = (0, 255, 0),1
plt.figure(figsize=(16,9))
cv2.drawContours(img, contours, -1, line_color , line_size)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
download

こんな形で輪郭が抽出されます。
findContoursで輪郭を求めることが出来ます。

輪郭を描画するには各点の座標がなければ
出来ないので、複数の座標が取得できています。

あとは3点があれば角度の計算ができますよね。
download-3

角度を求めて、その平均を各県で計算します。

次のようなコードで角度の計算をしています。

res = {}
for x in range(6):
    for y in range(8):
        file_path = 'img/{0}_{1}.png'.format(x,y)
        img = cv2.imread(file_path)
        img = img[10:140,10:145]

        # 領域抽出
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        _, binarized = cv2.threshold(gray_img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
        contours, _ = cv2.findContours(binarized, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

        tmp = []
        for i in range(len(contours[0])-2):
            a,b,c = contours[0][i][0],contours[0][i+1][0],contours[0][i+2][0]
            ba = [abs(a[0]-b[0]),abs(a[1]-b[1])]
            bc = [abs(c[0]-b[0]),abs(c[1]-b[1])]
            cos_s = (ba[0]*bc[0] +  ba[1]*bc[1]) / (np.sqrt(ba[0]**2 + bc[0]**2) * np.sqrt(ba[1]**2 + bc[1]**2))
            
            dig = np.degrees(np.arccos(cos_s))
            if dig>5:
                tmp.append(dig)
        
        if not np.isnan(np.mean(tmp)):
            res[file_path]=np.mean(tmp)

さて
これで全県の県章の
平均角度が求まりました。

あとはこれのいっちゃんちっさい奴が
ケツに入れたら痛い奴のはずです。

結果は・・・

download-1

デーーん

第一回
ケツに入れたら痛そうな県章選手権の覇者は
千葉県に決まりました!!!!!


千葉県人として
誇り高いですねーーー
素晴らしい

森田さーーん
見てますかーーwwww

と言うわけで
無事、千葉県が
ケツに入れたら痛いそうでした。

今回はこれまでです。

それでは。

このページのトップヘ