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

プログラミング

サイゼリアのテイクアウトが新しくなったので
ではないですが、またまた間違い探しに挑戦です。

解説動画はこちら




前回はこちら
前回の挑戦記事 


さて今回はopnecvを用いてみます。

画像の差分を用いて答えを導こうというのは同じです。

差分があれば黒く塗ってみます。

画像はサイゼリアさんの方を見ていただければと思います。
サイゼ間違い探し


さてどうなるか?
ソースコードはこちら

opencvとnumpyで差分をみて黒く塗っています。
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
img1 = cv2.imread('IMG/saize/saize1.png',0)
img2 = cv2.imread('IMG/saize/saize2.png',0) 
plt.figure(figsize=(20,10))
plt.imshow(np.where(img1 == img2, 1, 0))
plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
plt.tick_params(bottom=False,left=False,right=False,top=False)
plt.show()
download

おうふ、やっぱりちょっとは差がありますね。
左右の画像を完全一致させるのは難しいです。

ということですが、
黒いのが大きな領域は間違い部分である可能性が高いはずなので
見ていくと10個あるかもしれません。

うーんもう少しスマートにやる方法は無いものだろうか
そんなことを考えながら
サイゼのテイクアウトに舌鼓を打つ
今日この頃なのでした。

終・・・

暇ですよねwww

そんな時はお金のかからない方法で
遊びを見つけてみよーじゃないですか

自作でプログラム作ればタダです。

ということで迷路を作るプログラムを作ってみました。
解説動画はこちら


今回のプログラムでは穴掘り法というアルゴリズムを使用しています。

どんな感じかというと

1.縦横それぞれ奇数個サイズのマス作る

2.縦横それぞれ奇数座標のマスをランダムに選択する

3.方向をランダムに選択し2マス先のマスを調べて
まだ通路でなければ通路に変える

4.ランダムに選択した方向の2マス先が通路の場合はここで一旦終了

5.新たに縦横奇数座標のマスをランダムに選択し
通路を延ばせるマスが無くなるまで繰り返す

6.スタートとゴールをつけてあげる

ソースコードはこちら
import random
import sys
sys.setrecursionlimit(10**6)

# 穴掘り法で迷路を作る
def make(ny, nx):
    ar = list(range(4)) 
    random.shuffle(ar)
    for i in ar:
        if ny+dy[i][1]<1 or ny+dy[i][1]>=size[0]:
            continue
        if nx+dx[i][1]<1 or nx+dx[i][1]>=size[1]:
            continue
        if maze[ny+dy[i][1]][nx+dx[i][1]]=="□":
            continue
        for j in range(2):
            maze[ny+dy[i][j]][nx+dx[i][j]] = "□"
        make(ny+dy[i][1], nx+dx[i][1])

#height , width    Enter with odd number
size = (101, 51)

maze = [["■"]*size[1] for _ in range(size[0])]
dx,dy = [(1,2), (-1,-2), (0,0), (0,0)],[(0,0), (0,0), (1,2), (-1,-2)]
make(1, 1)
maze[1][1],maze[size[0]-2][size[1]-2] = "す","ご"

for i in maze:
    print(*i)
ちゃんと確認はしてませんが動くはずです。

sizeの所に奇数で縦横のサイズを入れてください。
横はデカすぎるとダメですが、縦は大きくても問題ないです。

こんな感じになるはずです。

スクリーンショット 2020-05-09 15.03.14


黒いのが壁で白抜きが道。
右下にゴールがあります。

でかいサイズで作ったら
PDFとかにでもして
印刷すれば即席巨大迷路の完成です。

どこまで大きなサイズができるかは知りませんが
色々遊べると思うので
動かして遊んでみてくださいませ。

それでは。




顔の黄金比などを判定するのに使う比率を用いて
美人具合をランキングづけしてみました。

優勝者は誰でしょうか?

解説動画はこちら




さてやり方ですが
opencvを使って顔のポイントを取り
各パーツの長さを測ります。
そこから比率を出していきます。

顔のポイントを見るコードはこんな感じになります。
(要opencv,dlibのインストール)
import os
import time
import numpy as np
import cv2
import dlib
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
%matplotlib inline

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("../shape_predictor_68_face_landmarks.dat")

image_path = 'img/hashikan.png'
image = cv2.imread(image_path, cv2.IMREAD_COLOR)
rects = detector(image, 1)
for rect in rects:
    landmarks = np.matrix([[p.x, p.y] for p in predictor(image, rect).parts()])
fig, ax = plt.subplots(figsize=(16,9))
frame = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
for d in rects:
    parts = predictor(frame, d).parts()
    ax.scatter([point.x for point in parts], [point.y for point in parts])
    for k, point in enumerate(parts):
        ax.text(point.x, point.y, k)
    ax.imshow(frame)
    plt.tick_params(labelbottom=False,labelleft=False,labelright=False,labeltop=False)
    plt.show()

1000nenn

顔は68ポイントの点を取ることができます。

今回のランキングは下記の方々10人の写真で行いました。
橋本環奈 さん
有村架純 さん 
石原さとみ さん 
新垣結衣 さん
広瀬すず さん 
波瑠 さん
綾瀬はるか さん
浜辺美波 さん
桜井日奈子 さん
沢尻エリカ様


顔のパーツから比率を出すコードはこちら
def fwhrs(parts):
    height = parts[8].y - parts[21].y
    width = parts[16].x - parts[0].x
    fwhr = width/height
    return round(fwhr, 3)

def heights(parts):
    top_height = parts[33].y - parts[21].y
    bottom_height = parts[8].y - parts[33].y
    return top_height,bottom_height

def widths(parts):
    left_face = parts[16].x - parts[45].x
    left_eye = parts[45].x - parts[42].x
    middle_face = parts[42].x - parts[39].x
    right_eye = parts[39].x - parts[36].x
    right_face =parts[36].x - parts[0].x
    return left_face, left_eye, middle_face, right_eye,right_face

def mouses(parts):
    top_mouse = parts[57].y - parts[33].y
    bottom_mouse = parts[8].y - parts[57].y
    return top_mouse, bottom_mouse

df = pd.DataFrame()
for file_name in os.listdir('img'):
    frame = cv2.imread('img/'+file_name)
    dets = detector(frame[:, :, ::-1])
    if len(dets) > 0:
        parts = predictor(frame, dets[0]).parts()
        fwhr = fwhrs(parts)  
        top_height,bottom_height = heights(parts)
        left_face, left_eye, middle_face, right_eye,right_face = widths(parts)
        top_mouse, bottom_mouse = mouses(parts)
        t_dict = {'name':[file_name.replace('.png','')],
                  'fwhr':[fwhr],
                  'top_height':[top_height],
                  'bottom_height':[bottom_height],
                  'left_face':[left_face],
                  'left_eye':[left_eye],
                  'middle_face':[middle_face],
                  'right_eye':[right_eye],
                  'right_face':[right_face],
                  'top_mouse':[top_mouse],
                  'bottom_mouse':[bottom_mouse]}
        tmp = pd.DataFrame(t_dict)
        df = pd.concat([df,tmp])

df['Height-Ratio'] = df['top_height']/df['bottom_height']
df['Width-Ratio1'] = df['left_face']/df['middle_face']
df['Width-Ratio2'] = df['left_eye']/df['middle_face']
df['Width-Ratio3'] = df['right_eye']/df['middle_face']
df['Width-Ratio4'] = df['right_face']/df['middle_face']
df['Mouse-Ratio'] = df['top_mouse']/df['bottom_mouse']

ratios = ['Height-Ratio','Width-Ratio1','Width-Ratio2','Width-Ratio3','Width-Ratio4','Mouse-Ratio','fwhr']
df[ratios].mean()

difs = list(df[ratios].mean())
df['DIFF1'] = abs(difs[0] - df['Height-Ratio'] )
df['DIFF2'] = abs(difs[1]- df['Width-Ratio1'] )
df['DIFF3'] = abs(difs[2]- df['Width-Ratio2'] )
df['DIFF4'] = abs(difs[3]- df['Width-Ratio3'] )
df['DIFF5'] = abs(difs[4]- df['Width-Ratio4'] )
df['DIFF6'] = abs(difs[5]- df['Mouse-Ratio'] )
df['DIFF7'] = abs(difs[6] - df['fwhr'] )
df['total']   = df['DIFF1'] + df['DIFF2'] + df['DIFF3'] + df['DIFF4'] + df['DIFF5'] + df['DIFF6'] + df['DIFF7']

columns = ['name','total','fwhr','Height-Ratio','Width-Ratio1','Width-Ratio2','Width-Ratio3','Width-Ratio4','Mouse-Ratio']
df[columns].sort_values('total')

顔のパーツの比率を出しまして
10人の平均を出しました。

その平均との乖離が一番少ない人が
美人だろうということでランキング付けしています。

結果は
nametotal
sawarizi0.274496
haru0.475337
gakky0.545178
ishiharasatomi0.561904
hashikan0.56951
arimura0.660029
sakurai0.728494
hamabeminami0.847156
ayase0.918146
hirose1.051217

ということで
意外な結果が出ました!!!

この10人の平均に一番近かったのは
この方
sawarizi

思いっきしファイル名間違えたのですが
各パーツの整い方が一番平均に近いということで
選ばれました。

今さらですが、このやり方だと
単純に平均に近いかどうかだけなので
美人かどうかの判断にはならないですよねーー

やはり各パーツの比率とかをもっと細かくとって
機械学習で絶対的な美人度を点数化する奴を
作らないとアレですよね。

絶対美人は誰なんだろうか
日本人全員にアンケートとってみたい!!


動画で動いている人を静止画の人と入れ替えるモデルが
公開されているのでご紹介です。


解説動画はこちら




コードなどはこちら
First Order Motion Model for Image Animation 

動画で動いている人を静止画に置き換えるようです。

いろんなサンプルが置いてありますね。
スクリーンショット 2020-04-26 15.20.22

GoogleColabで動くコードもあります。
自分のドライブにコピーして
上から実行していけば試すこともできますね。
スクリーンショット 2020-04-26 15.25.22


コードの中で
source_image = imageio.imread('/content/gdrive/My Drive/first-order-motion-model/02.png')
driving_video = imageio.mimread('/content/gdrive/My Drive/first-order-motion-model/04.mp4')

とあるので、ここのpngとmp4を変えてあげれば
自分の好きな動画を作る事が出来ると思います。

変換後のサイズがあまり大きくないので
256x256くらいの画像、動画が良いだろうと思います。

感触としては
・髪が顔に被らない
・背景なし
・メガネなし
にしてあげると上手くいくかなと思います。

単純に静止画を入れ替えるのと変わらないわけで
画像同士が似ている方が上手くいきやすいですね。

興味がある方は試してみてはどうでしょうか。

今日はこれまでです
それでは

リモートワーク進んでいますか?
家族がいたりすると、仕事中に
とあるランキングを確認するのも
躊躇してしまうかもしれません。

そんな方々に朗報です。
今日はそんな悩みを解消する
プログラムのご紹介です。


解説動画はこちら




コードはこちら
import requests
from bs4 import BeautifulSoup
import time

# 月間ランクページのURL
base_url = 'https://www.dmm.co.jp/digital/videoa/-/ranking/=/term=monthly/type=actress/page={0}/'
domain = 'https://www.dmm.co.jp'

def get_data(response,result):
    soup = BeautifulSoup(response.content,'lxml')
    div = soup.find('div',class_='area-rank')
    tds = div.find_all('td')
    for td in tds:
        span = td.find('span',class_='rank')
        rank = int(span.text) if span is not None else 0
        img = td.find('img')
        src = img.get('src') if img is not None else ''
        p = td.find('p')
        name = p.text if p is not None else ''
        link = domain + p.a.get('href') if p is not None else ''
        data = td.find('div',class_='data')
        num = int(data.text.split('出演作品数:')[1]) if data is not None else 0
        tmp = [rank,name,link,num,src]
        result.append(tmp)
    return result

result_list = []
for i in range(1,6):
    url = base_url.format(i)
    #print(url)
    res = requests.get(url)
    time.sleep(5)
    result_list = get_data(res,result_list)

このコードのざっくり解説をすると
サイトにアクセスしてHTMLを取得し
文字データの取得を行います。

そして取れたデータを出力してみると

# ランクで出力
for rank,name,link,num,src in sorted(result_list,reverse=False,key=lambda x:x[0]):
    print('{0:03}\t{1}\t{2}'.format(rank,name,num))

001	深田えいみ	291
002	美谷朱里	629
003	波多野結衣	2692
004	蓮実クレア	1207
005	枢木あおい	495
006	篠田ゆう	1178
007	稲場るか	234
008	あおいれな	822
009	上原亜衣	1193
010	跡美しゅり	635
011	今井夏帆	211
012	八乃つばさ	446
013	星奈あい	644
014	美園和花	121
015	大槻ひびき	1820
016	三上悠亜	144
017	葵つかさ	346
018	宮沢ちはる	129
019	大浦真奈美	243
020	AIKA	901

こんな感じになります。
ブラウザーの履歴には残らず、文字だけ出るので
家族にバレずに安全にランキングを確認する事が出来ます。


逆に
顔を見ないと分かりま10という人は
こちらのコードぞ実行してもらえば
HTMLとしてJupyterNotebook上で
ランキングを確認する事ができます。
from IPython.display import HTML
h_text = ''
for rank,name,link,num,src in result_list:
    if rank>20:
        break
    text = ''
    h_text+= text.format(rank,name,num,src)
h_text += '
{0:03}{1}{2}本
' HTML(h_text)

という感じで、仕事には
全くもって役に立たないプログラムです。

皆さんも気分転換い試してみては
いかがでしょうか?

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



このページのトップヘ