見出し画像

Pythonでヤバイわよ!を錬成する

ヤバイわよ!bot リスペクトです。詳しい説明はしません。このbotを見てください。

02月08日21時追記 項8.おまけ

1.画像とサイズを読み込む

画像処理ライブラリであるPillowを使う。流石に公式のヤバイわよ!の静止画を使うのもアレなのでTwitterのアイコン用に描いた画像を使う。

これをyabaiwayo.jpgとしてmain.pyと同じ階層に置いておく。
PillowのImageオブジェクトにはwidthとheightがあるので、そこから画像の幅と高さを取得する。
今のところのコードはこちら

# coding: utf-8
import os
from PIL import Image

imagefilename = "yabaiwayo.jpg"

curdir = os.path.dirname(os.path.abspath(__file__))

def get_image_size(src):
    w = src.width
    h = src.height
    return w,h

def main():
    try:
        im = Image.open(curdir + '/' + imagefilename)
        w, h = get_image_size(im)
        print('width: ',w)
        print('height:',h)
        
    except Exception as x:
        print(x)
        
if __name__ == "__main__":
    main()

実行結果

width:  1920
height: 1080

2.画像を4分割する

次にPillowのcrop()メソッドを使う。cropには切り出す領域を

box=(left, upper, right, lower)

で指定する。left,upperが切り出す際の左上の座標x,yに対応しており、right,lowerが右下の座標x,yに対応している。
画像を4分割するには、幅をw,高さをhとすると以下のような感じ

def split_quarter_image(src):
    w,h = get_image_size(src)
    
    i1 = src.crop((0 ,0 , w/2 , h/2))
    i2 = src.crop((w/2 ,0 , w , h/2))
    i3 = src.crop((0 ,h/2 , w/2 , h))
    i4 = src.crop((w/2 ,h/2 , w , h))

    return i1,i2,i3,i4

ゴリ押し。それぞれを画像として出力してみる。

ok、問題無さそう。

3.4つの画像を連結する

分割は出来たので次は連結する。まず横に2枚並べ、もう一度別の2枚で並べ、最後にその2枚を縦に並べるという方法でやろうと思う。
Pillowで画像の連結を行うには、Image.new()で背景を生成し、Image.pasteで貼り付けて…という流れ。
今回は分割した画像を再度連結するので、4枚の高さと幅は全て同じ前提。

# 横に連結
def link_image_h(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width + i2.width, i1.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(i1.width,0))
    
    return linkimage

# 縦に連結
def link_image_v(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width, i1.height + i2.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(0,i1.height))
    
    return linkimage

試しにテキトーに引数を渡してみる

def main():
    try:
        # イメージファイルを開く
        im = Image.open(curdir + '/' + imagefilename)
        i1,i2,i3,i4 = split_quarter_image(im)
        
        ii1 = link_image_h(i1,i4)
        ii2 = link_image_h(i3,i2)
        
        link_image_v(ii1,ii2).save(resultdir + '1432.jpg')
        
    except Exception as x:
        print(x)

それらしくなってきた。

4.画像を回転させる

次に画像を回転させる。Pillowには画像を回転させることができるrotate()というメソッドが用意されているので、それを使う。
Pillowには左右反転(flip())と上下反転(mirror())も用意されているが、ヤバイわよ!botは180度回転させているのでそれに従う。

# イメージを180度回転させる
def image_180_rotate(src):
    return src.rotate(180)

試しに左上部分を渡してみる。

ヤバイよね。

5.ランダム性をもたせる

最後に生成される画像にランダム性をもたせる。ヤバイわよ!botでは分割された左上,右上,左下,右下がそれぞれ重複選択有り、かつ180度回転の有無があり、配置箇所が4つある。PC用のパターンはここでは無視する。
そこで、今まで作った関数とランダム関数を組み合わせ、4分割されたうちの1枚をランダムで選び、さらに回転するかどうかもランダムで決めて1枚返させるようにする。

import random
# ランダムで1枚返す
def rand_one_image(src):
    i = random.randint(1,4)
    i1,i2,i3,i4 = split_quarter_image(src)
    if i == 1:
        return i1
    elif i == 2:
        return i2
    elif i == 3:
        return i3
    elif i == 4:
        return i4
    else:
        raise ValueError("何か起きました")

# 回転したりしなかったりする
def rand_rotate_image(src):
    i = random.randint(1,2)
    if i == 1:
        return image_180_rotate(src)
    elif i == 2:
        return src
    else:
        raise ValueError("何か起きました")

# ヤバイわよ!のパーツを1つ返す
def rand_yabai_image(src):
    return rand_rotate_image(rand_one_image(src))

試しに1枚呼び出してみる。

def main():
    try:
        # イメージファイルを開く
        im = Image.open(curdir + '/' + imagefilename)
        rand_yabai_image(im).save(resultdir + 'yabai.jpg')
        
    except Exception as x:
        print(x)

何回か実行してみたが、毎回違う結果になってたので問題無し

6.ヤバイわよ!

後は合成するだけ。出力先はmain.pyと同階層にあるresultフォルダ。出力ファイル名は日付にしておきます。

def main():
    try:
        yabaiwayo_time = datetime.now().strftime('%Y%m%d%H%M%S')
        # イメージファイルを開く
        im = Image.open(curdir + '/' + imagefilename)
        im_tmp1 = link_image_h(rand_yabai_image(im),rand_yabai_image(im))
        im_tmp2 = link_image_h(rand_yabai_image(im),rand_yabai_image(im))
        link_image_v(im_tmp1,im_tmp2).save(resultdir + yabaiwayo_time + '.jpg')
        
    except Exception as x:
        print(x)

実行結果(3回分)

ヤバイわよ!

7.まとめ

まとめって言っても書くこと何も無いのでコード全文とGitHubリンクでも載せておきます。

YABAIwayo - akaness1git GitHub

# coding: utf-8
import os
import random
from datetime import datetime
from PIL import Image

imagefilename = "yabaiwayo.jpg"

curdir = os.path.dirname(os.path.abspath(__file__))
resultdir = curdir + "/result/"

# 横に連結
def link_image_h(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width + i2.width, i1.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(i1.width,0))
    
    return linkimage

# 縦に連結
def link_image_v(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width, i1.height + i2.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(0,i1.height))
    
    return linkimage

# イメージを180度回転させる
def image_180_rotate(src):
    return src.rotate(180)

# 読み込んだイメージの幅と高さを返す
def get_image_size(src):
    w = src.width
    h = src.height
    return w,h

# 読み込んだイメージを4分割する
def split_quarter_image(src):
    w,h = get_image_size(src)
    
    i1 = src.crop((0 ,0 , w/2 , h/2))
    i2 = src.crop((w/2 ,0 , w , h/2))
    i3 = src.crop((0 ,h/2 , w/2 , h))
    i4 = src.crop((w/2 ,h/2 , w , h))

    return i1,i2,i3,i4

# ランダムで1枚返す
def rand_one_image(src):
    i = random.randint(1,4)
    i1,i2,i3,i4 = split_quarter_image(src)
    if i == 1:
        return i1
    elif i == 2:
        return i2
    elif i == 3:
        return i3
    elif i == 4:
        return i4
    else:
        raise ValueError("何か起きました")

# 回転したりしなかったりする
def rand_rotate_image(src):
    i = random.randint(1,2)
    if i == 1:
        return image_180_rotate(src)
    elif i == 2:
        return src
    else:
        raise ValueError("何か起きました")

# ヤバイわよ!のパーツを1つ返す
def rand_yabai_image(src):
    return rand_rotate_image(rand_one_image(src))
    
def main():
    try:
        yabaiwayo_time = datetime.now().strftime('%Y%m%d%H%M%S')
        # イメージファイルを開く
        im = Image.open(curdir + '/' + imagefilename)
        im_tmp1 = link_image_h(rand_yabai_image(im),rand_yabai_image(im))
        im_tmp2 = link_image_h(rand_yabai_image(im),rand_yabai_image(im))
        link_image_v(im_tmp1,im_tmp2).save(resultdir + yabaiwayo_time + '.jpg')
        
    except Exception as x:
        print(x)
        
if __name__ == "__main__":
    main()

8.おまけ

Twitterで64分割が欲しいとの声(意味不明)があったので改良しました。めちゃくちゃバグりそうな書き方してるけど動くんでもうこれで良いです。

split_level に好きなレベルを渡そう!6以上でも動くだろうけど画像の大きさを考えるんだぞ、いいな?
65536分割までは確認してます。

split_level = 1
# 分割レベル
# 1.....4分割
# 2....16分割
# 3....64分割
# 4...256分割
# 5..1024分割

以下、改良版コード全文

# coding: utf-8
import os
import random
from datetime import datetime
from PIL import Image

split_level = 1
# 分割レベル
# 1.....4分割
# 2....16分割
# 3....64分割
# 4...256分割
# 5..1024分割

imagefilename = "yabaiwayo.jpg"

curdir = os.path.dirname(os.path.abspath(__file__))
resultdir = curdir + "/result/"

# 横に連結
def link_image_h(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width + i2.width, i1.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(i1.width,0))
    
    return linkimage

# 縦に連結
def link_image_v(i1 ,i2):
    linkimage = Image.new('RGB',(i1.width, i1.height + i2.height))
    linkimage.paste(i1,(0,0))
    linkimage.paste(i2,(0,i1.height))
    
    return linkimage

# イメージを180度回転させる
def image_180_rotate(src):
    return src.rotate(180)

# 読み込んだイメージの幅と高さを返す
def get_image_size(src):
    w = src.width
    h = src.height
    return w,h

# 読み込んだイメージを4分割する
def split_quarter_image(src):
    w,h = get_image_size(src)
    
    i1 = src.crop((0 ,0 , w/2 , h/2))
    i2 = src.crop((w/2 ,0 , w , h/2))
    i3 = src.crop((0 ,h/2 , w/2 , h))
    i4 = src.crop((w/2 ,h/2 , w , h))

    return i1,i2,i3,i4

# ランダムで1枚返す
def rand_one_image(src):
    i = random.randint(1,4)
    i1,i2,i3,i4 = split_quarter_image(src)
    if i == 1:
        return i1
    elif i == 2:
        return i2
    elif i == 3:
        return i3
    elif i == 4:
        return i4
    else:
        raise ValueError("何か起きました")

# 回転したりしなかったりする
def rand_rotate_image(src):
    i = random.randint(1,2)
    if i == 1:
        return image_180_rotate(src)
    elif i == 2:
        return src
    else:
        raise ValueError("何か起きました")

# ヤバイわよ!のパーツを1つ返す
def rand_yabai_image(src):
    return rand_rotate_image(rand_one_image(src))

# n分割用
def rand_split_yabai_image(src,split_level):
    split_level = split_level - 1
    if split_level < 0:
        return src
    image_tmp = rand_yabai_image(src)
    
    return rand_split_yabai_image(image_tmp,split_level)

# n分割出力用
def n_split(src,split_level):
    if len(src) == 1:
        return src[0]
    else:
        image_list_tmp = []
        for i in range(4 ** (split_level - 2)):
            j = i*4
            im_tmp1 = link_image_h(src[j],src[j+1])
            im_tmp2 = link_image_h(src[j+2],src[j+3])
            image_list_tmp.append(link_image_v(im_tmp1,im_tmp2))
        return n_split(image_list_tmp,split_level - 1)

def main():
    try:
        image_list = []
        split_num = 4 ** split_level
        split_roop = 4 ** (split_level - 1)
        print(str(split_num) + "分割スタート!")
        yabaiwayo_time = datetime.now().strftime('%Y%m%d%H%M%S')
        # イメージファイルを開く
        im = Image.open(curdir + '/' + imagefilename)
        for i in range(split_roop):
            im_tmp1 = link_image_h(rand_split_yabai_image(im,split_level),rand_split_yabai_image(im,split_level))
            im_tmp2 = link_image_h(rand_split_yabai_image(im,split_level),rand_split_yabai_image(im,split_level))
            image_list.append(link_image_v(im_tmp1,im_tmp2))

        n_split(image_list,split_level).save(resultdir + str(split_num) + 'x_' + yabaiwayo_time + '.jpg')
        
        print("End")
        
    except Exception as x:
        print(x)
        
if __name__ == "__main__":
    main()
    

この記事が気に入ったらサポートをしてみませんか?