"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

物体検出ログの位置情報を使って、画像をきりとって保存する/yolo3・tendorflow・keras・python PIL

keras-yolo3を利用して物体検出をした時に、コンソールログに面白い情報が出力されるのに気づいたので、それを使って検出した画像の切り取りをやってみます。

f:id:arakan_no_boku:20190316225326j:plain

 

出力されるコンソールログ

 

keras-yolo3で物体検出する方法は前回を参照ください。

arakan-pgm-ai.hatenablog.com

 

今回はその実行時にコンソールに表示されるログについて扱います。

例えば、こんな情報です。

Input image filename:sample.jpg
(416, 416, 3)
Found 11 boxes for img
diningtable 0.97 (38, 7) (777, 471)
cake 0.71 (318, 224) (493, 398)
knife 0.57 (657, 256) (755, 455)
knife 0.96 (696, 248) (794, 472)
knife 0.98 (617, 254) (686, 477)
fork 0.50 (60, 292) (95, 436)
fork 0.76 (84, 279) (135, 505)
fork 0.93 (20, 297) (71, 504)
wine glass 0.59 (1, 0) (72, 81)
wine glass 0.98 (458, 5) (586, 206)
wine glass 0.99 (528, 10) (681, 253)
1.1462113127001103

「Found 11 boxes for img」に続く行に、検出した画像の情報がでてます。

例えば「cake 0.71 (318, 224) (493, 398)」なら。

  • cake:検出したものの名称
  • 0.71:一致確率
  • (318,224)(493,398):検出した画像の位置情報

です。

そして、この位置情報は「left, top, right, bottom」の順で並んでいるみたいです。

これは使えます。

 

画像を切り取るcrop()

 

画像を切り取るだけなら、Pythonの画像処理ライブラリPillow(PIL)のImageモジュールにあるメソッドcrop()でできます。

im.crop*1

 みたいな感じですね。

上記のログの一部分「cake 0.71 (318, 224) (493, 398)」を利用して、切り抜きをするのであれば、こんなコーディングになります。

    im = Image.open('./sample.jpg')
    croped = im.crop((318, 224, 493, 398))
    croped.save('./' + 'cake.jpg')

見ての通り、 ログの情報をソースにそのまま打ち込んでいるだけです。

でもこれだけで。

f:id:arakan_no_boku:20190314001042j:plain

上記の画像から、cakeと誤認識している「ナフキン」の画像が切り取れてます。

f:id:arakan_no_boku:20190317130617j:plain



もうちょっとだけ汎用的にしてみます

 

上記のやり方で、手作業でちょこちょこやれば切り取れますが、いまいちスマートではないです。

やっぱり、11個検出されてた画像を全部切り出すのに、11回手作業というのはねえ。

それで、もう少し汎用的にソースを書き直してみます。

from PIL import Image
import re

logstr='''diningtable 0.97 (38, 7) (777, 471)
cake 0.71 (318, 224) (493, 398)
knife 0.57 (657, 256) (755, 455)
knife 0.96 (696, 248) (794, 472)
knife 0.98 (617, 254) (686, 477)
fork 0.50 (60, 292) (95, 436)
fork 0.76 (84, 279) (135, 505)
fork 0.93 (20, 297) (71, 504)
wine glass 0.59 (1, 0) (72, 81)
wine glass 0.98 (458, 5) (586, 206)
wine glass 0.99 (528, 10) (681, 253)
'''
#元画像を開く
im = Image.open('./sample.jpg')
#ヒアドキュメントを改行で分割
list_str = logstr.splitlines()
cnt = 0
#一行ずつ処理
for s in list_str:
    cnt += 1
    #空白以外の余分な文字「(),」を消す
    rs = re.sub('[\(\)\,]','',s)
    #空白で分割する
    ls = re.split('[\s]',rs)
    ol = []
    nm = ""
    for x in ls:
        #数字はそのまま処理する
        if(x.isalpha()):
            nm = nm + x
        #数字のみで構成されていないものは名称とみなして連結する
        else:
            ol.append(x)
    ol.append(nm)
    #画像を切り取って保存する
    croped = im.crop((int(ol[1]), int(ol[2]),int(ol[3]),int(ol[4])))
    croped.save('./' + str(cnt) + '_' + ol[5] + '.jpg')

ソースの補足説明です。

まず、ログの検出結果部分だけを「改行ごと」、ヒアドキュメントに貼り付けて、変数にセットしています。

logstr = '''diningtable 0.97 (38, 7) (777, 471)
cake 0.71 (318, 224) (493, 398)
knife 0.57 (657, 256) (755, 455)
knife 0.96 (696, 248) (794, 472)
knife 0.98 (617, 254) (686, 477)
fork 0.50 (60, 292) (95, 436)
fork 0.76 (84, 279) (135, 505)
fork 0.93 (20, 297) (71, 504)
wine glass 0.59 (1, 0) (72, 81)
wine glass 0.98 (458, 5) (586, 206)
wine glass 0.99 (528, 10) (681, 253)
'''

 ログをコピーしてきて、貼り付けるだけ・・にするためです。

Pythonのヒアドキュメントはこういう時に、超便利でいいですね。

それを改行コードで分割して1行ずつのリストにして、1行分ずつ処理をするわけです。

list_str = logstr.splitlines()

各行は、基本空白で区切られてますが、余分な情報があります。

「(」と「)」と「,」 です。

なので、それらを除去してから、空白で分割するという2手間かけてます。

#空白以外の余分な文字「(),」を消す
rs = re.sub('[\(\)\,]','',s)
#空白で分割する
ls = re.split('[\s]',rs)

あとは、結果のリストに追加していって、crop()メソッドで処理するだけです。

ただ、名称が「wine glass」のように空白区切りのものがあるので、数字だけで構成されていないものは、名前とみなして連結しているわけです。

for x in ls:
    #数字はそのまま処理する
    if(x.isalpha()):
        nm = nm + x
        #数字のみで構成されていないものは名称とみなして連結する
    else:
        ol.append(x)
        ol.append(nm)

まあ、こんなもんですね。

現在のkeras-yolo3のログの仕様にあわせたオーダーメードみたいな処理ですけど、いちおう機能します。

きりとった画像をEXCELにならべてみました。

f:id:arakan_no_boku:20190317134232j:plain

まあまあじゃないですかね。

ではでは。

*1:left, top, right, bottom