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

Python

はいどうも

また錯視です。


動画はこちら



今回は
色違いに見えるボールを
描いてみましょう。

まずはライブラリを用意します。
from PIL import Image, ImageDraw, ImageFilter

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

次にソースはこちら


plt.figure(figsize=(16,9))
size ,c_y,c_v = (320, 320),(255, 241, 0),(170, 68, 153)
im1,im2 = Image.new("RGB", size, color=c_y),Image.new("RGB", size, color=c_v)
dst = Image.new('RGB', (im1.width + im2.width, im1.height))
dst.paste(im1, (0, 0))
dst.paste(im2, (im1.width, 0))
draw = ImageDraw.Draw(dst)
draw.ellipse(((  30,30,290,290)),fill=(0, 127, 127), outline=None)
draw.ellipse(((350,30,610,290)),fill=(0, 127, 127), outline=None)

r = 8
for x in range(0,320,12):
    for y in range(0,320,12):
        draw.ellipse((x,y,x+r,y+r),fill=c_v, outline=None)
for x in range(320,640,12):
    for y in range(0,320,12):
        draw.ellipse((x,y,x+r,y+r),fill=c_y, outline=None)
plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(dst))
plt.show()


実行していただくと
こんな感じの画像が出力されます。

ball

右と左の大きな円は
実は同じ色なんです!!!!!!

一同「えーーー、なんだってーー」

円が
同じ色に
みえん!!

なんちってね

背景の黄色と紫
その上に乗せた緑色の円

その上に小さな円を載せると
元の円の色が明るく見えたり
暗く見えたりするので

二つの円が違って見えるんだそうな

ソースの

r = 8

を小さくしてもらうと
上に重ねた円の大きさが変わり、
大きな円の色が同じであるということが
わかっていくと思います。

試しにやってみてください

それでは。



 


どーっもーー
AKBの錯視原りのでーーっす

ということで
今回は
「錯視」をやっていきたいと思います。



動画はこちら




さて 
錯視は色々な種類があり
今回紹介するのは
同じ長さや大きさのものだけど
歪んで見える感じの画像を作成していきます。

まずは必要なライブラリの読み込みです。
from PIL import Image, ImageDraw
import matplotlib.pyplot as plt
import numpy as np

%matplotlib inline



それでは有名どころの錯視はらいってみましょうーー

ミュラー・リヤー錯視

同じ大きさの線に少し手を加えると
長く見えたり短く見えたりするやつです。
plt.figure(figsize=(20,9))
size = (800, 400)
color1,color2,width = (150, 100, 220), (200, 120, 200),5

im = Image.new("RGB", size, color=(255, 255, 255))
draw = ImageDraw.Draw(im)

x1,x2,y1,y2 = size[0]//3,size[0]//3*2,size[1]//3,size[1]//3*2

draw.line([(x1,y1),(x2,y1)] , width = width, fill = color2)
draw.line([(x1,y1),(x1-x1//3,y1-y1//3)] , width = width, fill = color1)
draw.line([(x1,y1),(x1-x1//3,y1+y1//3)] , width = width, fill = color1)
draw.line([(x2,y1),(x2+x1//3,y1-y1//3)] , width = width, fill = color1)
draw.line([(x2,y1),(x2+x1//3,y1+y1//3)] , width = width, fill = color1)
draw.line([(x1,y2),(x2,y2)] , width = width, fill = color2)
draw.line([(x1,y2),(x1+x1//3,y2-y1//3)] , width = width, fill = color1)
draw.line([(x1,y2),(x1+x1//3,y2+y1//3)] , width = width, fill = color1)
draw.line([(x2,y2),(x2-x1//3,y2-y1//3)] , width = width, fill = color1)
draw.line([(x2,y2),(x2-x1//3,y2+y1//3)] , width = width, fill = color1)

plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(im))
plt.show()

1

こんな感じで、上下の真ん中の棒の長さは一緒です。
ただ上の棒の方がやや少しだけ長く見えます。


カフェウォール錯視

横に引いた線の近くに
交互に四角を配置すると
横の線が斜めになっているように
見えるというものです。

def draw_image(im):
    draw = ImageDraw.Draw(im)
    width = im.size[0]
    box_size = width//5
    half,margin = box_size//2,0
    for j in range(5):
        margin = half//2 if j%2==0 else 0
        for i in np.array(range(5)) * box_size :
            draw.rectangle(((i+margin,j*half),(i+half+margin ,j*half+half)) , outline = None, fill = (0,0,0))
            #pass
    for j in range(1,5):
        
        draw.line([(0,j*half),(size[0],j*half+1)] , width = 3, fill = (160,160,160))
    return im

plt.figure(figsize=(20,9))
size = (800,400)
im = Image.new("RGB", size , color=(255,255,255))

im = draw_image(im)
plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(im))
plt.show()


2

横線は斜めに傾いて見えますかね?


エビング錯視

同じ大きさの円を用意して
その周囲に大きい円と小さい円を配置します。

大きい円の中の円が小さく見えて
小さい円の中の円が大きく見えるという錯視です

plt.figure(figsize=(20,9))
size = (640, 320)
im = Image.new("RGB", size, color=(255, 255, 255))

draw = ImageDraw.Draw(im)
c1,c2 = np.array([200, 160]),np.array([500, 160])
r1,r2,r3 = 30,50,15
draw.ellipse(((tuple(c1 - r1)), (tuple(c1 + r1))),fill=(228, 127, 66), outline=None)
draw.ellipse(((tuple(c2 - r1)), (tuple(c2 + r1))),fill=(228, 127, 66), outline=None)
for i in np.radians(range(0,360,60)):
    x2,y2 = np.cos(i)* 120,np.sin(i)* 120
    draw.ellipse((tuple(np.array([x2, y2]) + c1 - r2), 
                  tuple(np.array([x2, y2]) + c1 + r2)),fill=(146, 164, 184), outline=None)
for i in np.radians(range(0,360,45)):
    x2,y2 = np.cos(i)* 60,np.sin(i)* 60
    draw.ellipse((tuple(np.array([x2, y2]) + c2 - r3), 
                  tuple(np.array([x2, y2]) + c2 + r3)),fill=(146, 164, 184), outline=None)
plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(im))
plt.show()
3

右のオレンジ円の方が
左のオレンジ円よりも
大きく見えませんか?


ヘリング錯視


中央から放射状に線を描き
それをまたがるように横線を描くと
横線が中央から出る線をまたぐ部分が
膨らんで見えるという錯視です。

plt.figure(figsize=(20,9))
size = (800, 400)
im = Image.new("RGB", size, color=(255, 255, 255))

draw = ImageDraw.Draw(im)
num = 24
times = size[0]//num
color = (150, 100, 220)
for i in range(num):
    draw.line([(i*times,0),(size[0]-i*times,size[1])] , width = 2, fill = (100,100,100))
draw.line([(0,size[1]//3 ),(size[0],size[1]//3 )] , width = 5, fill = color)
draw.line([(0,size[1]//3*2),(size[0],size[1]//3*2)] , width = 5, fill = color)

plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(im))
plt.show()
4

中央の横線部分が
膨らんで見えませんかね?



デルブーフ錯視
円の過小視、過大視


青い円の大きさは同じですが
その中や外に円を描くと
元の円の大きさが小さく見えたり
大きく見えたりします。

plt.figure(figsize=(20,9),dpi=300)
size = (640, 320)
im = Image.new("RGB", size, color=(255, 255, 255))

draw = ImageDraw.Draw(im)
color = (0, 200, 220)
draw.arc((150 , 100 , 250 , 200), start=0, end=360, fill=color)
draw.arc((160 , 110 , 240 , 190), start=0, end=360, fill=(0, 0, 0))
draw.arc((350 , 100 , 450 , 200), start=0, end=360, fill=color)
draw.arc((340 , 90   , 460 , 210), start=0, end=360, fill=(0, 0, 0))

plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.imshow(np.array(im))
plt.show()

5

青い円の大きさは一緒ですが
違和感を覚えませんか?


このような錯視は
まだまだ他にもたくさんあります。

今回は一旦PILライブラリで画像を作成して
それをmatplotlibで描画するという方法をとりました。

こうすると簡単に線を引いたりして
錯視画像を作成できます。

みなさまも錯視ができると
とっても錯xyじゃないですかー!!!

って言いたいだけのネタでした。

はいどうも今晩は
乙pyです。

本日はまず
Youtube登録者数が
100人を突破いたしましたーーーーーーー

きゃー
うれスィー

こんな底辺YouTuberですが
登録者数1000人、1万人と目指して
今後とも頑張って行きたいと思います。

目標は
日本国民全員が
プログラミングできるようになること
プログラミングたーのしーって
思えるようになることを目指しておりますので
引き続き皆さま動画の方を
よろしくお願いいたします。

動画はこちら




今回は算数チャレンジです。
算数チャレンジとは?
140114nexus7_cm_pazzle


昔GoogleのCMでこんなのが有りましたね。
四つの数字を用いて
組み替えて10になるような計算方法を
考えましょうと言うもの。

1 1 5 8 
これに
+ー*/
で答えを10にしましょう。

・・・

実際これやってみると
意外と大変なものです。


これを自力で解くのは
結構頭を使うので
頭を使わないために
プログラムで解く方法を考えてみましょう(笑)。

まず考えるべきは
プログラムで使う部品です。

4つの数字
+-*/の記号

これだけだと
実は解けないんです。

計算では優先順位があるので
先に足すとかしたい場合は
カッコが必要になります。

このカッコ() を用いることができないと
算数の問題を解けません。

と言うことで
部品を揃えて行きましょう。

言語はPythonを用います。
Python言語では
分数の計算を行うことができる
Fractionと言うライブラリがあります。

これを用いると
通常は1/7など小数点になってしまい
計算が合わなくなってしまうのを
分数扱いできるので
正しく答えを求めることができます。

また、4つの数字は
色々組み替える必要があるので
この組み替えを行うために
itertoolsライブラリを用います。

まずはこの二つをインポートしておきます。
from fractions import Fraction
import itertools

次に
そう考えていくかと言うと
数式を作っていくことを考えます。

1+2+3+4

こんな感じで4つの数字と
記号を三つ組み合わせる式になるはずです。

加えてこれにカッコ()を付け足す形になるので
このかっこのパターンを含めた数式文字列の
パターンを用意してあげます。
pattern = [
    '%s%s%s%s%s%s%s',
    '(%s%s%s)%s%s%s%s',
    '(%s%s%s%s%s)%s%s',
    '%s%s(%s%s%s)%s%s',
    '%s%s(%s%s%s%s%s)',
    '%s%s%s%s(%s%s%s)',
    '(%s%s%s)%s(%s%s%s)'
]
このように
かっこのパターンを用意してあげます。

次に
数式をどう組み立てるかと言うと
このパターンの%sの部分に
数字と記号を当てはめて行きます。

for x, y, z in itertools.product('+-*/',repeat=3)


これで記号の全通りの組み合わせを作ることができます。
itertools.productはその文字数分だけ繰り返しが行われます。
repeat=3なので3文字分の記号の組み合わせを作成します。


QUESTION = '1158

for a, b, c, d in itertools.permutations(QUESTION,4)

文字の部分は
こんな感じになります。
permutationsで数字の順列を作成します。

この7つの文字を
先ほどのパターンに当てはめます。

f = p % (fa, x, fb, y, fc, z, fd)


これでfに数式が当てはまりました。
あとはこれを計算するのですが
この変数fの値は文字列なので
計算はできません。

Pythonでは
文字を数式として評価できる
eval()と言う関数があります。

これを用いると数式として計算ができるので
作成した文字を数式として扱って
計算した結果、10になったら
答えとして、結果を保存します。

結果はsetに格納して重複を排除しました。

プログラムを組み合わせると
こんな感じになります。

from fractions import Fraction
import itertools

pattren = [
'%s%s%s%s%s%s%s',
'(%s%s%s)%s%s%s%s',
'(%s%s%s%s%s)%s%s',
'%s%s(%s%s%s)%s%s',
'%s%s(%s%s%s%s%s)',
'%s%s%s%s(%s%s%s)',
'(%s%s%s)%s(%s%s%s)',
]
QUESTION = '1158'
result_set = set()
for x, y, z in itertools.product('+-*/',repeat=3):
    for a, b, c, d in itertools.permutations(QUESTION,4):
        fa, fb, fc, fd = ['Fraction(%s)' % n for n in [a, b, c, d]]
        for p in pattren:
            f = p % (fa, x, fb, y, fc, z, fd)
            try:
                result = eval(f)
            except ZeroDivisionError:
                continue
            if result == 10.0:
                result_set.add (p % (a, x, b, y, c, z, d))
for s in result_set:
    print(s)

この答えは
動画でご覧くださいませ。

さて
いかがでしょうか?

お子さんがいらっしゃる家庭であれば
宿題でこんな問題を
色々やらされことがあるかもしれませんが

このプログラムであれば
QUESTIONの部分を変えてもらえば
いろんな数字の答えを求めることができます。

是非ご活用ください。


それでは









ピースの角度は30度でおなじみの
美人Youtuberゆきりぬさん

いつも動画みてまーーーす。

今日は
動画の冒頭でいつもやっている
決めポーズ

ピーズの角度が何度なのかを
Pythonプログラムで検証してみました。


解説動画はこちら


さて
まずは角度の元になる画像を用意します。
yukirinu2

この肘の先あたりから
ピースの先端までの角度を
求めたいと思います。

どうやって求めるかというと
rad
2点の座標を決めて
その間の角度を求めるようにします。

コードはこんな感じになりました。
%matplotlib notebook
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import math

def onclick(event):
    tx = 'x=%f, y=%f' % (event.xdata, event.ydata)
    text.set_text(tx)

fig = plt.figure()
ax = fig.add_subplot(111)
im = Image.open("yukikinu1.png")
im_list = np.asarray(im)
plt.imshow(im_list)

text=ax.text(0,0, "", va="bottom", ha="left")
cid = fig.canvas.mpl_connect('button_press_event', onclick)

まず画像を用意してから
このコードを実行すると
jupyter notebook上に画像が表示されます。

あとは画像のピースの部分をクリックしてあげると
スクリーンショット 2019-05-03 16.04.17


このようにx,y座標が表示されます。

あとはこの座標を使って
角度を求めていきます。
x, y = 504,im.height-231
radian = math.atan2(y - 0, x - 0)
print(math.degrees(radian))

ちょっと残念なのは
y座標は上からの数値になってしまっているので
画像の高さから引いてあげます。

肘のあたりを0,0として
ピースの先端を504,画像の高さ-231とした際に
math.atan2(y - 0 , x - 0)で
ラジアンが求められるので
それをmath.degrees(ラジアン)
で角度に変換すると・・・

だいたい36度になりました。
四捨五入して40度くらいですね

ということで
ピースの角度は40度でした!!!!

このようにPythonプログラムを使うと
2点を使った角度が簡単に求められます。

プログラミングを覚えていない方は
ぜひ参考にしてみてください。

それでは

今回はヒマなので
なーんか面白いことないかーとか
思っていましたら

東の方に
有名な大学が有るらしいんですよ。


東京大学って知ってます?

自分は行ったことないんで
よく知らないんですけど
有名大学みたいなので
数学の問題を解いてみることにしました。

解説動画はこちら



2003年の東大の入試問題より
 
円周率が 3.05 より大きいことを証明せよ。


さて
どう解きましょうかねー

とりあえず
円周の長さ > 内接X角形の外周

になるはずなので
この内接する多角形の外周を求めて
それが3.05よりも大きければ

総じて
円周率> 3.05 
となるのではないかと思います。

まずは円を描いてみましょう。

Pythonのライブラリを用いて
円を描いてみます。

# ライブラリの読み込み
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline


描画用のライブラリとして
matplotlibを読み込んでおきます。

# 半径5の円を描く
plt.figure(figsize=(2,2),dpi=300)
r = 5
x = [np.sin(np.radians(_x))*r for _x in np.linspace(-180,180,361)]
y = [np.cos(np.radians(_y))*r for _y in np.linspace(-180,180,361)]
plt.plot(x,y)

plt.xticks([i for i in range(-r,r+1)])
plt.yticks([i for i in range(-r,r+1)])
plt.axes().set_aspect('equal','datalim')
plt.show()
en1
円を描くにはx,y座標が必要ですが
その点を求めるのにnumpyを使います。

numpy.linspaceで等間隔の配列が作成できます。

あとはx,y座標の点を求めるのに
numpy.sin , numpy.cos を使います。
sin , cos に渡せるのはradianでないといけないので
一旦numpy.radiansで変換します。

これで円を描くことができます。


次にこの円に内接する多角形を描いてみましょう。
今回は12角形を描くこととします。

わかりやすくするために
三角形の辺の長さが3:4:5になるという法則を用いて
座標を決めていきます。

一番長い5の辺は円に接する先端ですね。
あとはx,yの座標は3か4になります。

一番上をx=0,y=5として座標点をプロットしてあげます。
# 内接する12角形を描画
plt.figure(figsize=(2,2),dpi=300)
r = 5
x = [np.sin(np.radians(_x))*r for _x in np.linspace(-180,180,361)]
y = [np.cos(np.radians(_y))*r for _y in np.linspace(-180,180,361)]
plt.plot(x,y)

x2 = [0,3,4,5,4,3,0,-3,-4,-5,-4,-3,0]
y2 = [5,4,3,0,-3,-4,-5,-4,-3,0,3,4,5]
plt.plot(x2,y2)

plt.xticks([i for i in range(-r,r+1)])
plt.yticks([i for i in range(-r,r+1)])
plt.axes().set_aspect('equal','datalim')
plt.show()
en2
はいこれで円に接する12角形が描けました。

あとはこの辺の長さを求めて
あげれば良いということになります。

辺の長さを求めるにはどうすれば良いでしょうか?

これはnumpyを使って
ユークリッド距離を求めることで
辺の長さを計算することができます。

numpy.linalg.norm(座標a - 座標b)

これで2点のユークリッド距離を求めることができます。

12角形のうち
全部を求める必要はなく

右上部分の4点を用いて
3辺の長さを計算してみましょう。

x,y座標はそれぞれ
0,5
3,4
4,3
5,0
となるので
そのうち2点を使って計算します。
l = np.array([[0,5],[3,4],[4,3],[5,0]])
c1 = np.linalg.norm(l[0]-l[1])
c2 = np.linalg.norm(l[1]-l[2])
c3 = np.linalg.norm(l[2]-l[3])
ans1 = 4 *(c1+c2+c3)
print(ans1)

30.9550755308

さてこれで多角形の辺の長さが計算できました。

問題文は3.05より大きいことを証明せよなので
比率を合わせます。

この円は半径5の円なので直径は10です。
なので10倍します。
30.5


10倍した30.5よりも
12角形の外周は30.95のため大きくなり

必然的にそれよりも円周は大きいので

円周率>3.05

になるはずです。

さて
描画などについては
Pythonのライブラリを用いると簡単に
描くことができ
また座標間の距離なども
簡単に計算することができます。

数学の問題では
このnumpyとmatplotlibライブラリを使って
いろいろ問題に応用することができます。

数学的な可視化や
その計算については
numpyやmatplotlibライブラリを
用いることが多いです。

単純な計算については
通常のPythonプログラムだけでも
行うことができます。

問題を読み間違わなければ
このくらいの計算は
プログラミングで簡単に行うことができるので

プログラミングを覚えていない方
これから覚えたい方は
ぜひPythonを覚えてみてください。

Pythonについては無料の動画講座を用意しています。
乙py式5時間で学ぶプログラミング基礎(python編)

興味のある方はぜひこちらをご参照くださいませ。

それでは。

このページのトップヘ