plant-raspberrypi3のブログ

ラズベリーパイ3とPythonに挑戦して、植物を愛でたり画像を加工したりします。最近はscikit-imageの勉強してます。

コンタクトシート風シートの作成プログラム (決定版)

こんにちは。らずべりーです。 最近めちゃ寒いですね。

コンタクトシート風シート(Adobeさんに気を遣ってぼやかしてみた)の作成プログラムを仕上げてみました。

これまでの経緯

以前書いたコードは画像20枚までのシートを1枚だけ作成するプログラムでした。

plant-raspberrypi3.hatenablog.com

また、テキストを画像にするときにフォントを指定する方法についても書いていました。

plant-raspberrypi3.hatenablog.com

今回はこれらを組み合わせて、画像何枚でも20枚ごとに1枚ずつのシートを作成するためのプログラムを完成させました。これで、撮った画像をまとめて確認&印刷できます(^ ^)ノ

今回、みんなのPythonを参考に、ジェネレータ関数というものをはじめて使ってみました。
みんなのPythonさんには日頃から大変お世話になっております。

非常にわかりやすい入門本なので、すごくすごくおすすめです!!(宣伝)

www.amazon.co.jp

使用する素材

以下、一例です。(ちっちゃいです。)

f:id:plant-raspberrypi3:20171019144118p:plain

今回は古い文献の画像から"The"の文字だけ取り出したものを使用します。個々の文献の内容は含まれず、一般的な字体であるため、特に引用はしません。(すみません。)

将来的に文字認識の機械学習(OCRとか?)をして遊ぶための準備的な。。。

実行環境

macOS Sierra
Python 3.6.1
Pillow 4.3.0
Jupyter lab v0.27.0
あとはNumpyとか。

コード概要

  1. フォルダパスを指定してファイル名と画像ファイルをバルクで読み出す関数
  2. 画像をコンタクトシート風シート用にリサイズする関数
  3. ファイル名の画像を生成(Helvetica,16pt)する関数
  4. 20個のデータから4列6行のコンタクトシート風シートを1つ作成する関数
  5. 20個ごとに1つのコンタクトシート風シートを作成するジェネレータ関数
  6. 上記全ての関数を組み合わせて、画像のフォルダパスからコンタクトシート風シートを自動生成して保存する関数
  7. 実行

*補足:始める前に、モジュールのインポートをしてください。import os import numpy as np from PIL import Image, ImageFont, ImageDrawの3つが必要です。

実際の手順

1. フォルダパスを指定してファイル名と画像ファイルをバルクで読み出す

def png_bulk_read(path1,format=".png"):
    os.chdir(path1)
    all_files = os.listdir(path1)
    file_names = [i for i in all_files if i.endswith(format)]
    png_files = [Image.open(i) for i in file_names]
    return file_names, png_files

2. 画像をコンタクトシート風シート用にリサイズ

def bulk_fig_resize(im_series,scale=200):
    im_series_resize = []
    for i in range(len(im_series)):
        width = np.array(im_series[i]).shape[0]
        length = np.array(im_series[i]).shape[1]
        if width < length:
            img_i = im_series[i]
            s_int1 = int(scale*width/length)
            im_series_resize.append(img_i.resize((scale,s_int1)))
        else:
            img_i = im_series[i]
            s_int2 = int(scale*length/width)
            im_series_resize.append(img_i.resize((s_int2,scale)))
    return im_series_resize

ifの後のim_series_resize.appendあたりが崩れてしまいました。
Markdown記法に慣れていないためです、すみません。
ifより1つ後ろにインデントが正解です。

201710/19 18:30ごろ修正しました。

3. ファイル名の画像を生成(Helvetica,16pt)

def file_name_figs(file_names):
    file_name_fig_list = []
    for i in file_names:
        img_text = Image.new('RGB', (240, 20), (255,255,255))
        draw = ImageDraw.Draw(img_text)
        fontpath = "/System/Library/Fonts/Helvetica.dfont"
        font = ImageFont.truetype(fontpath, 16)
        draw.text((0, 0), i, font=font,fill='#000')
        file_name_fig_list.append(img_text)
    return file_name_fig_list

4. 20個のデータから4列6行のコンタクトシート風シートを1つ作成

def create_csheet(im_series_resize,text_fig_list):
    fig_width = 240
    fig_length = 265
    if len(im_series_resize) <= 20:
        canvas = Image.new('RGB', (1000, 1350), (255, 255, 255))
        for i in range(len(im_series_resize)):
            tmp_canvas = Image.new("RGB",(fig_width,fig_length),(255,255,255))
            tmp_canvas.paste(text_fig_list[i],(0,0))
            try:
                img_i = im_series_resize[i]
                tmp_canvas.paste(img_i,(0,20), img_i.split()[3])
            except IndexError:
                img_i = im_series_resize[i]
                tmp_canvas.paste(img_i,(0,20))
            canvas.paste(tmp_canvas, (10+int(i%4)*fig_width,10+int(i/4)*fig_length))
    else:
        print("Error")
        canvas = 0
    return canvas

5. 20個ごとに1つのコンタクトシート風シートを作成するジェネレータ関数

def generate_csheet(im_series_resize,text_fig_list):
    while True:
        if len(im_series_resize) < 1:
            break
        elif len(im_series_resize) < 20:
            yield create_csheet(im_series_resize,text_fig_list)
            break
        else:
            im_list = im_series_resize[:20]
            text_list = text_fig_list[:20]
            im_series_resize = im_series_resize[20:]
            text_fig_list = text_fig_list[20:]
            yield create_csheet(im_list,text_list)

6. 画像のフォルダパスからコンタクトシート風シートを自動生成して保存

def csheet_create_from_folder(folder_path):
    file_names, png_files0 = png_bulk_read(folder_path)
    png_files = bulk_fig_resize(png_files0)
    file_figs = file_name_figs(file_names)
    cs_generater = generate_csheet(png_files,file_figs)
    cs_list = []
    while True:
        try:
            cs_list.append(next(cs_generater))
        except StopIteration:
            break
    for i in range(len(cs_list)):
        cs_list[i].save("csheet_{}.png".format(i),"PNG",quality=100, optimize=True)

7. 実行

上記の全ての関数をcsheet_module.pyという名前で保存し、モジュールとして呼び出して実行します。

import csheet_module as cs
folder_path = "/usr/local/scanned_pdf/the"
cs.csheet_create_from_folder(folder_path)

結果

27枚の画像が2枚のコンタクトシート風シートのpngファイルとして保存されました。

1枚目

f:id:plant-raspberrypi3:20171019145457p:plain

2枚目

f:id:plant-raspberrypi3:20171019145527p:plain

完成!!! (^ ^)ノ