忘備録に残しておきます。
こちらの記事で、OIDv4_Toolkit で Dolphin のみ画像とアノテーションデータを取得することができました。
もともと下記の公開モデルでYOLOv3 の再学習をさせたいというモチベーションでデータを集めていました。
https://github.com/eriklindernoren/PyTorch-YOLOv3
こちらでは、アノテーションデータは [ label_idx x_center y_center width height ] のtxtファイルで与えてあげる必要があると書いてあります。また、各座標は 0 ~ 1 のスケールに変換されています。
一方で、OIDv4_Toolkit で取得したアノテーションファイルを見てみると、[ label_name left top right bottom] というふうになっています。

このように取得したアノテーションデータをそのまま使用することができないため、今回はこちらをすべて指定された形に変換をしてあげたいと思います。
① 各座標を 0 ~ 1 の範囲にスケール変換
② [ label_name left top right bottom] → [label_idx x_center y_center width height]
各座標を 0 ~ 1 の範囲にスケール変換
まず①についてですが、OIDv4-Toolkit を使うと、
OID > csv_folder > validation-annotations-bbox.csv
に 0 ~ 1 スケールでのすべてのファイルのアノテーション座標情報がまとまっています。こちらを利用したいと思います。解決。
(訓練画像のものに関しては train-annotations-bbox.csv、テスト画像のものについては test-annotations-bbox.csv とあります。)
1 2 3 4 5 6 7 8 9 10 |
import pandas as pd from PIL import Image from glob import glob # validation ラベル情報が記載されたcsvファイルを取得 df = pd.read_csv("./OID/csv_folder/validation-annotations-bbox.csv") # validation 画像のすべてのパスを取得 paths = glob("./OID/Dataset/validation/Dolphin/*.jpg") |
csv ファイルの中身はこんなです。

ImageID 列の値と、画像のファイル名が一致しています。この csv ファイルには Open Images Dataset のすべての画像の座標情報が乗っているので、まずはこの csv ファイルの中で、イルカの画像のアノテーション情報以外を削除します。
1 2 3 4 5 6 7 8 9 10 |
# イルカ画像のファイル名を格納する IDs = [] # イルカ画像のファイル名をパスから取得 for path in paths: ID = path.split("/")[-1].split(".")[0] IDs.append(ID) # df の ImageID と IDs(イルカ画像のファイル名) が一致する行のみ残す tmp = df[df["ImageID"].isin(IDs)] |
同じ ImageID で複数行あるのは、1枚の画像の中に物体が複数存在していて、それぞれの座標情報があるためですね。
今 tmp に残っているのは、イルカのみの座標情報です。
[ label_name left top right bottom] → [label_idx x_center y_center width height]
では変換しましょう。
x_center = ( XMax + XMin ) / 2
y_center = (YMax + YMin ) / 2
width = XMax – XMin
height = YMax – YMin
です。まとめて計算します。
1 2 3 4 5 6 7 |
# 座標の計算 tmp["x_center"] = (tmp["XMax"] + tmp["XMin"]) / 2 tmp["y_center"] = (tmp["YMax"] + tmp["YMin"]) / 2 tmp["width"] = tmp["XMax"] - tmp["XMin"] tmp["height"] = tmp["YMax"] - tmp["YMin"] result = tmp.loc[:, ["ImageID", "x_center", "y_center", "width", "height"]] |
result には必要な情報の列だけ残しました。
最後に一枚のファイルに一枚のアノテーション情報が記載されるかたちで保存してきたいと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
for ID in IDs: rows = result[result["ImageID"] == ID].values.tolist() # label_name -> label_idx (今回 Dolphin のインデックスは 0 とする) for row in rows: row[0] = 0 # ファイルを書き出して保存 f = open("./output/validation/Dolphin/{}.txt".format(ID), "w") for row in rows: out = " ".join(map(str, row)) f.write(str(out) + "\r") f.close() |
これで output > validation > Dolphin 配下に画像ごとのアノテーションデータを作成することができました。

各ファイルの中身はこんなかんじです。

いいかんじですね。
今回は検証データについてのみのスクリプトですが、訓練データのものを変換したければ、 validation としていたところを全部 train と変えてあげればうまくいきます。テストデータに関しても同様です。
全体を通してはこうなります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import pandas as pd from PIL import Image from glob import glob df = pd.read_csv("./OID/csv_folder/validation-annotations-bbox.csv") paths = glob("./OID/Dataset/validation/Dolphin/*.jpg") IDs = [] for path in paths: ID = path.split("/")[-1].split(".")[0] IDs.append(ID) tmp = df[df["ImageID"].isin(IDs)] # 座標の計算 tmp["x_center"] = (tmp["XMax"] + tmp["XMin"]) / 2 tmp["y_center"] = (tmp["YMax"] + tmp["YMin"]) / 2 tmp["width"] = tmp["XMax"] - tmp["XMin"] tmp["height"] = tmp["YMax"] - tmp["YMin"] result = tmp.loc[:, ["ImageID", "x_center", "y_center", "width", "height"]] for ID in IDs: rows = result[result["ImageID"] == ID].values.tolist() for row in rows: row[0] = 0 f = open("./output/validation/Dolphin/{}.txt".format(ID), "w") for row in rows: o = " ".join(map(str, row)) f.write(str(o) + "\r") f.close() |
おわり