#!
# coding: utf-8
# Copyright (C) 2015, 2017 TOPS SYSTEMS
### @file dnn2pic.py
### @brief DNN results to picture utility
###
### DNNログファイルから情報を取り出して
### ファイルから読み込んだ別画像に重ねた画像ファイルにして出力する
### Contact: izumida@topscom.co.jp
###
### @author: M.Izumida
### @date: January 4, 2017
###
# Original: dump2pic.py April 21, 2015
# dnn2pic.py v01r01 January 4, 2017
# Written for Python 2.7 (NOT FOR 3.x)
#=======================================================================
# インポート宣言
import sys
import re
import argparse
import os
from datetime import datetime
from PIL import Image, ImageDraw
#=======================================================================
# バージョン文字列
versionSTR = "dnn2pic.py v01r01 Tops Systems (pgm by mpi)"
#=======================================================================
# 共通サブルーチン
#-------------------------------------------------------------------
def errPrint(mes):
"""errPrint.
エラー出力へのメッセージ表示
後の始末はその後で別に書くこと
"""
sys.stderr.write(mes)
sys.stderr.write('\n')
#-------------------------------------------------------------------
def stdExceptionHandler(mes):
"""standard Exception Handler.
エラーメッセージを送出し、デバッグのための情報を出力する
"""
errPrint("Exception Captured: " + str(mes))
errPrint("0:" + str(sys.exc_info()[0]))
errPrint("1:" + str(sys.exc_info()[1]))
errPrint("2:" + str(sys.exc_info()[2]))
#-------------------------------------------------------------------
def tryIntParse(st, dval, radix=10):
"""try Parse string to Integer
文字列stをパースして整数化できれば値を返す、できなければデフォルト値dvalを返す
"""
try:
work = int(st, radix)
except:
return dval
return work
#=======================================================================
# 解析オプション クラス
class Options:
"""Options Class.
グローバルオプションを保持するクラス
"""
pass
#=======================================================================
# LOGファイルリーダクラス
[ドキュメント]class logReader:
"""LOG File Reader Class.
insPic2dnn.pyが出力するLOGファイルを読み取って
リストとして記憶するクラス
"""
#--------------------------------------------------------------------
def __init__(self, ifnam):
"""LOG File Reader Constructor
コンストラクタ
"""
self.iFname = ifnam
#データ格納テーブル
# 0: 画像ファイル名
# 1: オリジナル sx位置
# 2: オリジナル sy位置
# 3: オリジナル ex位置
# 4: オリジナル ey位置
# 5: DNN判定結果 (0/1/2)
self.table = []
#
self.tablePTR = 0
#
self.debug = False
self.verbose = False
#--------------------------------------------------------------------
[ドキュメント] def read(self):
"""read method
ファイルから行をリードして処理するメソッド
"""
try:
with open(self.iFname, 'r') as f:
for line in f:
self.rLine(line)
except:
stdExceptionHandler("ERROR: in file reading = " + self.iFname)
return False
return True
#--------------------------------------------------------------------
[ドキュメント] def rLine(self, lin):
"""Read Line method
読み取った1行を処理するメソッド
"""
p0 = re.match('([a-zA-Z0-9_\.]+) : ([0-9]+), ([0-9]+), ([0-9]+), ([0-9]+) => ([0-9]+)', lin)
if p0:
work = []
work.append(p0.group(1))
work.append(tryIntParse(p0.group(2), 0))
work.append(tryIntParse(p0.group(3), 0))
work.append(tryIntParse(p0.group(4), 0))
work.append(tryIntParse(p0.group(5), 0))
work.append(tryIntParse(p0.group(6), 0))
self.table.append(work)
return
#--------------------------------------------------------------------
[ドキュメント] def dumpTable(self):
"""dump table
テーブルのダンプ出力。ベリファイ用。
"""
for item in self.table:
if len(item) > 6:
fnam = item[0]
sx = item[1]
sy = item[2]
ex = item[3]
ey = item[4]
sel = item[5]
print "{0} : {1}, {2}, {3}, {4} => {5}".format(fnam, sx, sy, ex, ey, sel)
#=======================================================================
# イメージファイルリーダライタ クラス
[ドキュメント]class ImageFileRWriter:
"""Image File Reader/Writer Class.
イメージファイルを読み込み、LOGファイルにしたがって加工した後
ファイルに書き戻すためのクラス
"""
#--------------------------------------------------------------------
def __init__(self, ifnam, ofnam, dlis, mag):
"""Image File Reader/Writer Constructor
コンストラクタ
"""
self.iFname = ifnam
self.oFname = ofnam
self.drawList = dlis
self.mag = mag
#--------------------------------------------------------------------
[ドキュメント] def load(self):
"""Image File Reader
イメージファイルのリーダ
"""
try:
self.im = Image.open(self.iFname)
except:
stdExceptionHandler("Error: reading image file = " + self.iFname)
return False
return True
#--------------------------------------------------------------------
[ドキュメント] def save(self):
"""Image File Writer
イメージファイルのライタ
"""
try:
self.im.save(self.oFname)
except:
stdExceptionHandler("Error: writing image file = " + self.oFname)
return False
return True
#--------------------------------------------------------------------
[ドキュメント] def draw(self):
"""Drawing image method
リストに従ってイメージを描く
"""
drObj = ImageDraw.Draw(self.im)
for item in self.drawList:
if len(item) < 6:
continue
sx = item[1] * self.mag
sy = item[2] * self.mag
ex = item[3] * self.mag
ey = item[4] * self.mag
sel = item[5]
color = (128, 128, 128)
width = 4
if sel == 2:
color = (255, 0, 0)
elif sel == 1:
color = (0, 0, 255)
drObj.line((sx, sy, ex, sy), color, width)
drObj.line((sx, sy, sx, ey), color, width)
drObj.line((ex, sy, ex, ey), color, width)
drObj.line((sx, ey, ex, ey), color, width)
#=======================================================================
# メインプログラム
def main():
"""main.
メインプログラム
"""
#-----------------------------------------------------------------------
# コマンドラインオプション処理
#
parser = argparse.ArgumentParser(description='dnn2pic DNN results imager.')
parser.add_argument('--ORG', nargs=1, help='Specify Original picture file.')
parser.add_argument('--LOG', nargs=1, help='Specify LOG file.')
parser.add_argument('--OUT', nargs=1, help='Specify OUTPUT picture file name.')
parser.add_argument('--MAG', nargs=1, help='Specify Magnification(default=1).')
parser.add_argument('-d', dest='debug', help='Debug mode, print debug information.', action='store_true', default=False)
parser.add_argument('-v', dest='verbose', help='Verbose mode.', action='store_true', default=False)
parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False)
args = parser.parse_args()
#-----------------------------------------------------------------------
# Version 表示
#
print versionSTR
if args.VERSION:
sys.exit(0)
#-----------------------------------------------------------------------
# ファイル名処理
#
if args.ORG is None:
orgFname = 'image001.png'
else:
orgFname = args.ORG[0]
if not os.path.isfile(orgFname):
errPrint('ERROR: Original picture file, NOT EXIST.')
sys.exit(1)
if args.LOG is None:
logFname = 'test.log'
else:
logFname = args.LOG[0]
if not os.path.isfile(logFname):
errPrint('ERROR: LOG file, NOT EXIST.')
sys.exit(1)
if args.OUT is None:
outFname = 'imageOut.png'
else:
outFname = args.OUT[0]
#-----------------------------------------------------------------------
# パラメータ処理
if args.MAG is not None:
mag = tryIntParse(args.MAG[0], 1)
else:
mag = 1
#-----------------------------------------------------------------------
# 実処理
#
print "-"*50
log = logReader(logFname)
if not log.read():
sys.exit(1)
if args.verbose:
log.dumpTable()
img = ImageFileRWriter(orgFname, outFname, log.table, mag)
if img.load():
img.draw()
if not img.save():
sys.exit(1) #異常終了
else:
sys.exit(1) #異常終了
today = datetime.today()
print today.strftime("FINISH: %Y/%m/%d %H:%M:%S")
#-----------------------------------------------------------------------
# 正常終了
#
sys.exit(0)
#=======================================================================
# メインプログラムの起動
if __name__ == "__main__":
main()