7
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Python matplotlibとPILで画像処理(vs ImageMagick)

Last updated at Posted at 2018-01-28

はじめに

通常は ImageMagick で処理しているものを,Python の matplotlib と PIL でプログラムを組んでやってみました.

ツインタワーの写真以外は,
こちら
の2軸棒グラフがネタになっています.

やってみた内容は以下の通り.

  • 画像に文字列を挿入
  • ファイルに格納された文字列を画像にする
  • 画像の余白削除・リサイズ・結合

作業環境は以下の通り.

  • MacBook Pro (Retina, 13-inch, Mid 2014)
  • macOS High Sierra
  • Python 3.6.4
  • ImageMagick 7.0.7-22

画像に文字列を挿入

テストに使っているのは,クアラルンプールにあるペトロナス・ツインタワーの写真です.
私は,夜のこの景色が大好きです.

なお,この写真はMacのPreviewでみると縦長の画像なのですが,ImagemagickでもPILでも読み込んでみると横長画像として認識されています.
そこで,ImageMagickでは,元画像はいじらず,書き込む文字列画像を90度回転させて書き込んでいます.

Pythonでは,読み込んだ画像を90度回転させてから,文字列の書き込みを行っています.また余白がついてくるので,最後に余白の削除を行っています.

ImageMagick

%%bash

flow=IMG_0694.JPG
fupp=_text.png
ffin=fig_KL_im.jpg
fknd=/System/Library/Fonts/Helvetica.ttc
convert -font $fknd -fill 'yellow' -background 'transparent' -pointsize 200 label:'Kuala Lumpur (KLCC)' $fupp
convert $fupp -rotate -90 $fupp
convert $flow $fupp -gravity southwest -geometry +40+40 -compose over -composite $ffin

Python

from PIL import Image, ImageChops
from matplotlib import pyplot as plt

def trim(im, border):
  bg = Image.new(im.mode, im.size, border)
  diff = ImageChops.difference(im, bg)
  bbox = diff.getbbox()
  if bbox:
    return im.crop(bbox)

flist=[
'IMG_0694.JPG'
]
fsz=40
for fn in flist:
    fig=fn
    img=Image.open(fig,'r')
    img=img.rotate(-90, expand=True)
    print(img.size)
    iw=800
    ih=int(img.size[1]/img.size[0]*iw)
    fig = plt.figure(figsize=(iw/100,ih/100),facecolor='w')
    plt.rcParams['font.family'] = 'Tahoma'
    plt.axis('off')
    img = img.resize((iw,ih))
    plt.text(20,20, 'Kuala Lumpur (KLCC)', rotation=0,color='yellow',fontsize=fsz,va='top', ha='left')
    plt.imshow(img)
    fnameF='fig_KL_py.jpg'
    plt.savefig(fnameF,dpi=150,bbox_inches='tight',pad_inches=0)
    plt.show()

    img=Image.open(fnameF,'r')
    img=trim(img,'#ffffff')
    img.save(fnameF, 'JPEG', quality=100, optimize=True)

ファイルに格納された文字列を画像にする

ImageMagick

%%bash

for fn in bar1
do
    fr=${fn}.txt
    fw=ft_${fn}.png
    
    convert -font /System/Library/Fonts/Menlo.ttc -pointsize 16 -interline-spacing 5 label:@$fr $fw
#    convert -font courier-new -pointsize 16 -interline-spacing 0 label:@$fr $fw
done

Python

import matplotlib.pyplot as plt

def DRAW(sp,fn):
    fsz=20
    w=fsz*len(sp[0])/100*0.5
    h=(fsz+10)*len(sp)/100
    fig = plt.figure(figsize=(w,h),facecolor='w')
    plt.rcParams['font.family'] = 'monospace'
#    plt.rcParams['font.family'] = 'Courier New'
#    plt.rcParams['font.family'] = 'Ricty Diminished'
    xmin=0
    xmax=float(len(sp[1]))
    ymin=0
    ymax=float(len(sp))
    plt.xlim(xmin,xmax)
    plt.ylim(ymax,ymin)
    plt.axis('off')
    for i,strp in enumerate(sp):
        plt.text(1,i+1,strp,ha='left',va='top')
    plt.tight_layout()
    fnameF='ftpy_'+fn+'.png'
    plt.savefig(fnameF, dpi=100, bbox_inches="tight", pad_inches=0)
    plt.show()


flist=[
'bar1'
]
for fn in flist:
    fnameR=fn+'.txt'
    fr=open(fnameR,'r')
    lines=fr.readlines()
    fr.close()
    sp=[]
    for text in lines:
        sp=sp+[text.replace('\n','')]
    DRAW(sp,fn)

画像の余白削除・リサイズ・結合

事前に準備された数表の画像 ft_bar1.png と棒グラフの画像 fig_bar1.png を縦に結合して,新しい画像 fig_bar1_b.png を作ります.

ImageMagick

for fn in bar1
do
    f1=ft_${fn}.png
    f2=fig_${fn}.png
    f3=fig_${fn}_a.png
    convert -trim -resize 760x -gravity center -background white -extent 800x200 $f1 _$f1
    convert -trim -resize 760x -gravity center -background white -extent 800x800 $f2 _$f2
    convert -append _$f1 _$f2 $f3
done
rm _*

Python

プログラム作成にあたり,以下のサイトを参考にしました(というか関数をいただきました)

以下のPythonプログラムにおいての関数の機能以下の通り.

  • trim:余白削除
  • resz:リサイズ
  • marg:余白追加
from PIL import Image, ImageChops

def trim(im, border):
  bg = Image.new(im.mode, im.size, border)
  diff = ImageChops.difference(im, bg)
  bbox = diff.getbbox()
  if bbox:
    return im.crop(bbox)

def resz(im,ix):
    iw=im.size[0]
    ih=im.size[1]
    im_res = img_new.resize((int(ix),int(ih/iw*ix)), Image.LANCZOS)
    return im_res

def marg(im, top, right, bottom, left, color):
    width, height = im.size
    new_width = width + right + left
    new_height = height + top + bottom
    result = Image.new(im.mode, (new_width, new_height), color)
    result.paste(im, (left, top))
    return result

# 上側画像を横幅800pxで作成(余白含む)
ix=760
fig='ftpy_bar1.png'
img_org=Image.open(fig,'r')
img_new=trim(img_org,'#ffffff')
img_res=resz(img_new,ix)
img_fin=marg(img_res, 15, 20, 15, 20, '#ffffff')
print(img_org.format,img_org.size, img_org.mode)
print(img_new.format,img_new.size, img_new.mode)
print(img_res.format,img_res.size, img_res.mode)
print(img_fin.format,img_fin.size, img_fin.mode)
img1=img_fin

# 下側画像を横幅800pxで作成(余白含む)
ix=760
fig='fig_bar1.png'
img_org=Image.open(fig,'r')
img_new=trim(img_org,'#ffffff')
img_res=resz(img_new,ix)
img_fin=marg(img_res, 20, 20, 20, 20, '#ffffff')
print(img_org.format,img_org.size, img_org.mode)
print(img_new.format,img_new.size, img_new.mode)
print(img_res.format,img_res.size, img_res.mode)
print(img_fin.format,img_fin.size, img_fin.mode)
img2=img_fin

# 上下で画像を結合(Image.newで台紙を作成しそこに2枚の画像をpasteで貼り込む)
new_width=img1.size[0]
new_height=img1.size[1]+img2.size[1]
img3=Image.new('RGBA', (new_width, new_height), '#ffffff')
img3.paste(img1,(0,0))
img3.paste(img2,(0,img1.size[1]))
img3.save('fig_bar1_b.png', 'PNG', quality=100, optimize=True)

img3.show()

以 上

7
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?