見つけたもの
物体検出の評価でよく使われるmean Average Precision(mAP)がサクッと出せちゃうプログラム。
PrecisionやRecallもテキストとして出してくれるみたいです。
これは便利!
だがしかし
正解データと検出結果を以下のフォーマットに書き換えて、inputディレクトリに入れないといけないのです。
また、ファイル名は同じ名前にしてね。とのこと。
しかも、Pascal VOCとかMSCOCOとかからの変換コードはないのです。。。
素晴らしきは、下記の結果データをPascal VOCやYolo形式にしてくれる変換コードは入っていたりします。
正解データ
<class_name> <left> <top> <right> <bottom> [<difficult>]
検出結果
<class_name> <confidence> <left> <top> <right> <bottom>
書いたコード
なので、Pascal VOCフォーマットから上記の正解データフォーマットに変換するコードを書いてみました。
検出結果は、人それぞれなので書けませんでした。
- 動作確認
- Ubuntu 16.04 STL
- Python 3.5.2
##
# cording:utf-8
##
import os
import glob
import shutil
import argparse
from xml.etree import ElementTree as ET
def argparser():
parser = argparse.ArgumentParser()
parser.add_argument('xml_dir', type=str,
help='input dir in pascal voc xml')
parser.add_argument('-o', '--output_dir', type=str,
default='input/ground-truth',
help='output dir name')
return parser.parse_args()
def read_xml(xml_name):
root = ET.parse(xml_name).getroot()
object_list = []
for member in root.findall('object'):
label = member.find('name').text
bbox = member.find('bndbox')
object_list.append({'label': label,
'xmin': bbox.find('xmin').text,
'ymin': bbox.find('ymin').text,
'xmax': bbox.find('xmax').text,
'ymax': bbox.find('ymax').text})
return object_list
def create_output_name(xml_name, output_dir):
p = os.path.split(xml_name)[1]
buf = os.path.splitext(p)[0]
return os.path.join(output_dir,
'{}.txt'.format(buf))
def write_text(object_list, output_txt_name):
"""
output format
<class_name> <left> <top> <right> <bottom>
"""
with open(output_txt_name, 'w') as fp:
for obj in object_list:
line = '{} {} {} {} {}\n'.format(obj['label'],
obj['xmin'], obj['ymin'],
obj['xmax'], obj['ymax'])
fp.write(line)
if __name__ == '__main__':
args = argparser()
if not os.path.isdir(args.xml_dir):
print('input dir name not found:{}'.format(args.xml_dir))
exit()
# create output dir
if os.path.isdir(args.output_dir):
shutil.rmtree(args.output_dir)
os.makedirs(args.output_dir)
xml_list = glob.glob(os.path.join(args.xml_dir, '*.xml'))
for xml_name in xml_list:
print(xml_name)
obj_list = read_xml(xml_name)
output_name = create_output_name(xml_name, args.output_dir)
write_text(obj_list, output_name)
使い方
$ git clone https://github.com/Cartucho/mAP.git
$ cd mAP
$ mv hoge/conv_voc2txt.py ./
$ python3 conv_voc2txt.py [input_dir] -o [<output_dir>]
input_dir
には、変換したいPascal VOCフォーマッ卜のXMLファイルが入っているディレクトリを指定します。
input_dir
のみ指定して実行した場合は、input/ground-truth
のディレクトリ内に出力結果のテキストが格納されます。
output_dir
はオプションで、出力ディレクトリの名前を変更したい際に指定してください。
mAP実行
認識結果のテキストファイルをinput/detection-results
に格納、正解データをinput/ground-truth
のディレクトリに格納します。
ここで、検出結果と正解データの両方のファイル数を同じにする処理をはさみます。
画像中の物体が一つも現出されずに、検出結果ファイルが作られない場合や過検出による本来ない正解データの作成です。
そういったファイルの抜けに対応するプログラムがmAPで提供されています(作者さんすごい)。
$ python3 scripts/extra/intersect-gt-and-dr.py
その後、mAPのmain.py
を実行します。
python3 main.py -na
これで、作者さんのサイトで紹介されているような綺麗なmAPのグラフや、結果のテキストファイルなどが手に入ります。
-na
オプションは、mAP計算時に画像を出力するオプションを切る設定です。この-na
を付けないととても処理が重くなります。
画像が欲しい方は、-na
のオプションを消して、input/images-optional
に、認識に使用した画像を入れて実行してください。
以上
急に必要になったのですが、このリポジトリのおかげでなんとかなりました。感謝。