LoginSignup
13
10

More than 3 years have passed since last update.

物体検出の評価方法mAPのプログラムを見つけた

Last updated at Posted at 2019-09-19

見つけたもの

物体検出の評価でよく使われる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
conv_voc2txt.py
##
# 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に、認識に使用した画像を入れて実行してください。

以上

急に必要になったのですが、このリポジトリのおかげでなんとかなりました。感謝。

13
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
13
10