重ね合わせ漢字クイズを作ってみる 〜漢字シャッフルクイズ作成プログラムからの組み替え その2〜

  • URLをコピーしました!
目次

重ね合わせ漢字クイズ

前回、漢字シャッフルクイズ作成プログラムから組み替えて、英単語バラバラクイズを作成しました。

今回は同様にしてさらに違うクイズ作成プログラムを作ってみたいと思います。

今回作成するのは重ね合わせ漢字クイズ!

どういうものかというとこんな感じで二つの漢字からなる熟語を当てるクイズです。

つまりプログラムとしては、それぞれ一つずつの漢字の画像を作成し、それを重ね合わせ、最後に宣伝用バナーを結合させるという流れになります。

それでは始めていきましょう。

プログラム全体

まずは作成したプログラム全体をお見せします。

default_dir = './'

import random
import json
from matplotlib import pyplot as plt
import matplotlib.font_manager as fm
import datetime
import os
from PIL import Image
import random
import tweepy
import csv

def question_choice(question_json, question_log):
    with open(question_log, 'r') as f_in:
        reader = csv.reader(f_in)
        
        for row in reader:
            prev_question = row[1]
    
    with open(question_json, 'r') as f_in:
        question_list = json.load(f_in)

    question = question_list[random.choice(list(question_list))]
    
    return question, prev_question

def font_choice(fonts_json, default_dir):
    with open(fonts_json, 'r') as f_in:
        fonts_list = json.load(f_in)
    
    font_name = random.choice(list(fonts_list))
    font_path = os.path.join(default_dir, fonts_list[font_name])
    
    return font_name, font_path

def log_write(question_log, timenow, question, font_name):
    with open(question_log, 'a') as f_in:
        row = f'{timenow},{question[0]}{question[1]},{font_name}\n'
        f_in.write(row)

def fig_make(output_original_path, font_path, question):
    fp = fm.FontProperties(fname=font_path)
    
    fig = plt.figure(figsize=(6,6))
    plt.clf()

    plt.text(0.5, 0.4, question, horizontalalignment='center', verticalalignment='center', fontsize=400, fontproperties=fp)

    plt.axis('off')
    plt.savefig(output_original_path, facecolor="white", pad_inches = 0)
    
def banner_make(output_banner_path, font_path):
    fp = fm.FontProperties(fname=font_path)
    
    fig = plt.figure(figsize=(6,0.6))
    plt.clf()

    plt.text(0,0.3, "3PySci https://3pysci.com", fontsize=20, fontproperties=fp)

    plt.axis('off')
    plt.savefig(output_banner_path, facecolor="white", pad_inches = 0)

def overlap_image(output_original_path1, output_original_path2, output_question_path, output_banner_path):
    
    im1 = Image.open(output_original_path1)
    im2 = Image.open(output_original_path2)
    banner_im = Image.open(output_banner_path)
    
    im1_width = im1.size[0]
    im1_height = im1.size[1]
    banner_im_height = banner_im.size[1]
    
    mask = Image.new("L", (im1_width, im1_height), 128)
    overlap_im = Image.composite(im1, im2, mask)
    
    new_im = Image.new('RGB', (im1_width, im1_height + banner_im_height))
    
    new_im.paste(overlap_im, (0, 0))
    new_im.paste(banner_im, (0, im1_height))
    
    new_im.save(output_question_path)
    
def applytotwitter(settings_json, output_question_path, prev_question):
    
    text = f'前回の答えは「{prev_question}」でした。\nこの重なり合った2文字の熟語はなんでしょう?😆\n#分かったらRT\n#脳トレ\n#クイズ\n#パズル\n#Python\n#プログラミング\n\n重ね合わせ漢字メーカーはこちら→https://3pysci-app.com/OverlapKanji/'
    
    with open(settings_json, 'r') as f_in:
        settings = json.load(f_in)

    auth = tweepy.OAuthHandler(settings['consumer_key'], settings['consumer_secret'])
    auth.set_access_token(settings['access_token'], settings['access_token_secret'])

    api = tweepy.API(auth, wait_on_rate_limit = True)

    api.update_with_media(status = text, filename = output_question_path)

def main():
    question_json = os.path.join(default_dir, 'question.json')
    fonts_json = os.path.join(default_dir, 'fonts.json')
    settings_json = os.path.join(default_dir, 'settings.json')
    question_log = os.path.join(default_dir, 'question_log.txt')
    
    timenow = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    
    question_dir = os.path.join(default_dir, 'question')
    
    if os.path.exists(question_dir) == False:
        os.mkdir(question_dir)
    
    output_dir = os.path.join(question_dir, timenow)
    os.mkdir(output_dir)
    
    output_original_name1 = timenow + '_1.png'
    output_original_path1 = os.path.join(output_dir, output_original_name1)
    
    output_original_name2 = timenow + '_2.png'
    output_original_path2 = os.path.join(output_dir, output_original_name2)
    
    output_banner_name = 'banner_' + timenow + '.png'
    output_banner_path = os.path.join(output_dir, output_banner_name)
    
    output_question_name = 'question_' + timenow + '.png'
    output_question_path = os.path.join(output_dir, output_question_name)
    
    question, prev_question = question_choice(question_json, question_log)
    font_name, font_path = font_choice(fonts_json, default_dir)
    log_write(question_log, timenow, question, font_name)
    fig_make(output_original_path1, font_path, question[0])
    fig_make(output_original_path2, font_path, question[1])
    banner_make(output_banner_path, font_path)
    overlap_image(output_original_path1, output_original_path2, output_question_path, output_banner_path)
    applytotwitter(settings_json, output_question_path, prev_question)

if __name__ == '__main__':
    main()

ほとんどが前のプログラムからの流用です。

完全に新しく作ったのは、「overlap_image関数」くらいでしょうか。

こちらは後ほど解説します。

他の関数はこんな感じでほとんど「漢字シャッフルクイズ」から移植しています。

question_choice漢字シャッフルクイズよりそのまま移植
font_choice漢字シャッフルクイズよりそのまま移植
log_write漢字シャッフルクイズよりから内容を多少変更
fig_make漢字シャッフルクイズよりそのまま移植
banner_make漢字シャッフルクイズよりそのまま移植
divide_image削除
shuffle_image削除
add_banner削除
applytotwitter内容を多少変更

プログラムとしては問題を記載した「question.json」より二つの漢字を取得し、それを「fig_make関数」を2回使うことによりそれぞれ画像化し、「overlap_image関数」で重ね合わせの画像を作っています。

question.json

問題を記載したquestion.jsonはこんな感じです。

{
    "1":["問","題"],
    "2":["時","間"],
    "3":["天","才"],
    "4":["物","語"],
    "5":["編","集"]
}

問題となる熟語をリストとして記載しています。

overlap_image関数

今回新しく作成したoverlap_image関数です。

def overlap_image(output_original_path1, output_original_path2, output_question_path, output_banner_path):
    
    im1 = Image.open(output_original_path1)
    im2 = Image.open(output_original_path2)
    banner_im = Image.open(output_banner_path)
    
    im1_width = im1.size[0]
    im1_height = im1.size[1]
    banner_im_height = banner_im.size[1]
    
    mask = Image.new("L", (im1_width, im1_height), 128)
    overlap_im = Image.composite(im1, im2, mask)
    
    new_im = Image.new('RGB', (im1_width, im1_height + banner_im_height))
    
    new_im.paste(overlap_im, (0, 0))
    new_im.paste(banner_im, (0, im1_height))
    
    new_im.save(output_question_path)

まず漢字二つの画像と宣伝用バナーの画像をそれぞれ読み込み、漢字の画像の縦横のサイズとバナーの縦のサイズを取得します。

    im1 = Image.open(output_original_path1)
    im2 = Image.open(output_original_path2)
    banner_im = Image.open(output_banner_path)

    im1_width = im1.size[0]
    im1_height = im1.size[1]
    banner_im_height = banner_im.size[1]

漢字の画像は2つありますが、どちらも同じサイズですし、バナーの横のサイズは漢字の画像の横のサイズと同じなので、取得していません。

次が2枚の画像を同じ比率で重ね合わせる部分ですが、なかなか理解が難しい部分です。

    mask = Image.new("L", (im1_width, im1_height), 128)
    overlap_im = Image.composite(im1, im2, mask)

まずこの2行目の「Image.composite(im1, im2, mask)」は「.composite(画像1, 画像2, マスク画像)」です。

つまり画像1、画像2をマスク画像に合わせて合成するというわけです。

そしてマスク画像を作成しているのが1行目の「Image.new(“L”, (im1_width, im1_height), 128)」です。

最初の引数がモードで、「1」とすると1bit画像、つまり2色の画像に、「L」にすると8bitグレースケール、「RGBA」にするとカラー画像(透明度含む)になります。

また最後の数字は「階調」らしいのですが、今回の場合、2枚の画像をどんな比率で表示するかということに影響します。

ちなみに今回の例ではモードを”L”、つまり8bitグレースケールなので、最後の階調は0〜255までの256階調。

その中の128ということは、階調は半分。

つまり、2枚の画像を同じ比率で重ね合わせるということになります。

この画像の重ね合わせに関しては、また別の機会で詳しく試してみたいと思います。

そしてそのように重ね合わせた画像に宣伝用バナーを結合して完成です。

    new_im = Image.new('RGB', (im1_width, im1_height + banner_im_height))
    
    new_im.paste(overlap_im, (0, 0))
    new_im.paste(banner_im, (0, im1_height))

あとは全体を合うように修正して完成です。

今までプログラムは単体のものを作って作りっぱなしだったのですが、こうやってプログラムを使いまわして効率的に新しいプログラムを作成できるとなんだかどんどんと新しいことをとやりたくなりますね。

と言いつつもクイズのネタが今は浮かんでいない状態。

ただこのクイズプログラム、そのまま自分だけクイズを作るのに使うのはもったいない。

せっかくDjangoでウェブアプリを作り、公開する体制が整っているので、これまで作ってきたクイズ作成プログラムも改変してDjangoでアプリとして公開したいと思います。

しかしこれまで3PySci-Appとして何となくデザインしたウェブサイトでアプリを公開してきたのですが、ここで一回、本気でアプリのページ作りに取り組んでみようかと思います。

そこで次回は新たな武器としてBootstrapのデザインを行うためのソフト「Bootstrap Studio」を導入していきたいと思います。

ではでは今回はこんな感じで。

よかったらシェアしてね!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる