VOOZH about

URL: https://note.com/leftbank/n/n5e3c2629438f

⇱ Christmas Tree Illusion|leftbank


👁 見出し画像

Christmas Tree Illusion

👁 leftbank

Motivation


河原先生がツイットされてたのを見てウズウズ。

BGMのつもりで流していたら、左のツリーの動きが、(1)全体が右時計回り、(2)全体が反時計回り、(3)一つの繋がりが時計回りもう一つが反時計回りの三種類に、時々切り替わって見えた。(1)(2)は、錯視のデモでよく見かけるけれど、(3)は見かけたことがなかったhttps://t.co/4AwIGomiXC

— Hideki Kawahara: WAS (Work@Sapporo) (@hidekikawahara) November 25, 2021

元動画は削除されてもう見られないようなのですが、回転するクリスマスツリー模様が、意図はしていないのでしょうが回転方向が、時計回り、反時計回り、両方の3パターンに切り替わって見える錯視が起こっていました。

MATLABで作ろう!

これはMATLABで作ってみるしかない!

関数としては単なるスパイラルなので、高さ方向に半径を変えながら円を3Dプロットして行けば良さそうだということがすぐ分かります。

回転は、開始角を変えていけば良いですね。

「すぐできそう!」と思ったのですが、「それっぽく」見える調整には試行錯誤が必要でした。(^-^;

シミュレーション結果

早速結果を。

👁 Image
Christmas Tree Illusion
You'll see three rotation patterns: clockwise, counterclockwise, and both.
If you look up and down or look away for a moment, you get the opposite rotation, and if you look at the one that looks like it's going around backwards, you get both rotations mixed up.

上から見るとこのようにずっと時計回りに回しているだけなのですが、YouTubeのヤツと同じ錯視が起こります。

👁 Image
Top View
こちらは錯視が起こらない

コツとしては、目線を上下すると反転しやすく、裏で回ってるように見える☆を注視するとそれが前に出てきて両回転入り乱れるようです。

MATLABコード 1

we = true; % file write enable
N = 4;

filename = ['illusionTree' num2str(N) '.gif']
close all
f = figure(1);
f.Color = [1 1 1];

th0 = 0:pi/20:2*pi*1.5;
h = th0;
maxh = max(h);

for off = 0:pi/100:2*pi-pi/100
 th = th0 - off;
 x = h .* sin(-th);
 y = h .* cos(-th);

 plot3(x,y,-h,'b-p','MarkerIndices',1:4:length(h),'MarkerSize',10);

 xlim([-1.8*maxh 1.8*maxh])
 ylim([-1.8*maxh 1.8*maxh])
 zlim([-maxh 0.5])
 view(0,0)
 axis off
 hold on

 plot3(x,y,-h,'b*','MarkerIndices',3:4:length(h),'MarkerSize',8);

 for k = 2:N
 th = th + 2*pi/N;
 x = h .* sin(-th);
 y = h .* cos(-th);
 plot3(x,y,-h,'b-p','MarkerIndices',1:4:length(h),'MarkerSize',10);
 plot3(x,y,-h,'b*','MarkerIndices',3:4:length(h),'MarkerSize',8);
 end

 hold off

 drawnow

 if we
 frame = getframe(gca); % take image only
 gr = frame2im(frame);
 [bA,map] = rgb2ind(gr,256);
 if (off==0)
 imwrite(bA,map,filename,'gif','LoopCount',Inf,'DelayTime',1/20);
 else
 imwrite(bA,map,filename,'gif','WriteMode','append','DelayTime',1/20);
 end
 end
end

描画点はある程度多くないと当然滑らかな円になりませんが、その全てにマーカーを表示してしまうと密になりすぎてしまいます。そのような場合、'MarkerIndices' オプションでマーカーの間隔を開けることができます。

plot3(x,y,-h,'b-p','MarkerIndices',1:4:length(h),'MarkerSize',10);
plot3(x,y,-h,'b*','MarkerIndices',3:4:length(h),'MarkerSize',8);

4点おきに☆、その間に*を表示させています。


ライン数を変えてみる

コードにあるとおり、変数 N でラインの本数も変えられます。

👁 Image
2ラインバージョン
👁 Image
3ラインバージョン
👁 Image
6ラインバージョン
👁 Image
8ラインバージョン

最初は2ラインバージョンが一番錯視が起きやすかったのですが、慣れるとどれでもいけますね。(-_☆)

高速化検討

マーカーを入れるととても遅くなるようで、リアルタイム動作はしなくなります。

高速化のため、あらかじめ計算結果を配列に入れてみましょう

オーナメントライン一本ずつのグラフィックハンドルを保存して、2回目以降は plot3() を使わず描画済み座標データである .XData/.YDataプロパティを直接更新します。z は変わらないので更新不要です。

グラフィックハンドル配列は zeros/onesではなく、gobjects() で初期化する必要があります。

ついでに回転は、表示のみの時は 2π、書き込み時はファイルサイズ削減のため 2π/N 分だけ書くようにしています。2π/N で、また全く同じ座標データに戻るからです。

MATLABコード 2

we = true; % file write enable
M = true; % draw maker
N = 4;

filename = ['illusionTree2_' num2str(N) '.gif']
close all
f = figure(1);
f.Color = [1 1 1];

th0 = 0:pi/20:2*pi*1.5;
h = th0;
maxh = max(h);

dAz = pi/100;
maxAz = 2*pi;
if we; maxAz = maxAz/N; end
n = ceil(maxAz / dAz);
maxAz = maxAz - dAz;

x = zeros(length(h),n,N);
y = zeros(length(h),n,N);

for off = 1:n
 az = off * dAz - dAz;
 th = th0 - az;
 for k = 1:N
 x(:,k,off) = h .* sin(-th);
 y(:,k,off) = h .* cos(-th);
 th = th + 2*pi/N;
 end
end

H = gobjects(N,2);
for off = 1:n
 for k = 1:N
 if (off == 1)
 if M
 H(k,1) = plot3(x(:,k,off),y(:,k,off),-h,'b-p','MarkerIndices',1:4:length(h),'MarkerSize',10);
 else
 H(k,1) = plot3(x(:,k,off),y(:,k,off),-h,'b-');
 end
 if (k == 1)
 xlim([-1.8*maxh 1.8*maxh])
 ylim([-1.8*maxh 1.8*maxh])
 zlim([-maxh 0.5])
 view(0,0)
 axis off
 hold on
 end
 if M
 H(k,2) = plot3(x(:,k,off),y(:,k,off),-h,'b*','MarkerIndices',3:4:length(h),'MarkerSize',8);
 end
 else
 H(k,1).XData = x(:,k,off);
 H(k,1).YData = y(:,k,off);
 if M
 H(k,2).XData = x(:,k,off);
 H(k,2).YData = y(:,k,off);
 end
 end
 end
 if (off == 1); hold off; end
 drawnow

 if we
 frame = getframe(gca); % take image only
 gr = frame2im(frame);
 [bA,map] = rgb2ind(gr,256);
 if (off==1)
 imwrite(bA,map,filename,'gif','LoopCount',Inf,'DelayTime',1/20);
 else
 imwrite(bA,map,filename,'gif','WriteMode','append','DelayTime',1/20);
 end
 end
end

Consideration

結果は・・、微妙にしか速くならない・・。

どうやらやはり、マーカーの描画がネックのようですね。(;¬_¬)

ライブスクリプトであればあとから実行結果を再生スピードを変えて再生・巻き戻しもできるので、ライブスクリプトで試すのが良いかと思います。ライブスクリプトファイルはMATLABでないと読めないので公開時は通常のスクリプトにしていますが、実際にはライブスクリプトで作ることが多いです。

ライブスクリプトにするには、新規ライブスクリプトを作って、上記コードを貼り付け、最初の設定辺りを「コントロール」で置き換えてください。

👁 Image
ライブスクリプトの例

ライブスクリプトは結果をビデオやアニメーションGIFにも保存できますがFPSが指定できないので、スクリプト中でFPSを指定してファイル出力をしています。

回転錯視は日本人Webデザイナーの方が作られた「シルエット錯視」が有名ですが、こんな簡単なものでもできるのが意外でした。

ほんと認識の仕組みは不思議で面白いですね。(u_u)


それでは、少し早いですが、良いクリスマスをお過ごしください。🎄


タイトル画像モデル:高杉レナ(クレアトゥール)


いいなと思ったら応援しよう!