結果の操作
各推論は画像ごとにResultsオブジェクトを返します。ペイロードの種類ごとに名前付きスロットが1つあり、モデルが生成するもの以外は空です。エクスポートした成果物でも同じスロットを使います。
1オブジェクト、ペイロードごとに1スロット
1枚の画像に対する推論は1つのResultsを返します。18個のペイロードスロットがあり、モデルは自身のタスクが生成するものだけを埋めます。そのほかのスロットはすべてNoneなので、検出器でresult.masksを読み取るとエラーではなくNoneになります。
| スロット | クラス | 形状 | 生成するタスク |
|---|---|---|---|
boxes | Boxes | (N, 4)にスコアとクラスを追加 | 検出、および最初に位置特定を行うタスク |
masks | Masks | (N, H, W) | インスタンスセグメンテーション |
keypoints | Keypoints | (N, K, 2)または(N, K, 3) | 姿勢推定 |
probs | Probs | (C,) | 分類 |
obb | OBB | (N, 7)または(N, 8) | 回転バウンディングボックス |
gaze | Gaze | (N, 2)のピッチとヨー(ラジアン) | 視線推定 |
points | Points | x、y、class、confidenceの(N, 4) | 点の位置特定 |
semantic_mask | SemanticMask | (H, W)のクラスID | セマンティックセグメンテーション |
panoptic | PanopticSegmentation | (H, W)のセグメントIDとsegments_info | パノプティックセグメンテーション |
depth_map | DepthMap | (H, W)の浮動小数点数 | 深度推定 |
normal_map | NormalMap | (H, W, 3)の単位ベクトル | 表面法線 |
edges | EdgeMap | [0, 1]内の(H, W)浮動小数点数 | エッジ検出 |
restored | RestoredImage | (H, W, 3)のuint8 RGB | 復元と超解像 |
matte | Matte | [0, 1]内の(H, W)浮動小数点数 | アルファマッティングと背景除去 |
ocr | OCRRegions | (N, 4, 2)のポリゴンと転記テキスト | テキスト検出と認識 |
embeddings | Embeddings | (N, D)のL2正規化済み行 | embedタスク |
identities | Identities | N個の名前とスコア | ギャラリーを伴うembedタスク |
meshes | Meshes | 身体パラメータと任意の頂点 | 人体メッシュ復元 |
これらに加えて、すべての結果が持つフィールドがあります。orig_shapeは(height, width)、pathはソースパス(メモリ内入力ではNone)、namesはクラスIDからクラス名へのマッピング、frame_idxは動画とライブフレーム用、track_idはトラッキング時に使われます。restore_scaleは復元結果の整数アップスケール係数です。
result.normalsはresult.normal_mapの別名です。
result.speedはすべての結果に存在しますが、値が設定されるのはアンサンブルだけです。キーはmember_0、member_1、fusionで、単位はミリ秒です。単一モデルでは空の辞書のままです。
ボックス
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")result = model(SAMPLE_IMAGE) print(result.orig_shape) # ソース画像の (height, width)print(result.path) # ソースパス メモリ内入力では None for xyxy, conf, cls in zip( result.boxes.xyxy.tolist(), result.boxes.conf.tolist(), result.boxes.cls.tolist(),): print(result.names[int(cls)], round(float(conf), 3), xyxy)from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy[:1]) # ピクセル x1 y1 x2 y2print(result.boxes.xywh[:1]) # ピクセル 中心 x 中心 y w hprint(result.boxes.xyxyn[:1]) # 同じボックスを幅と高さで除算print(result.boxes.xywhn[:1])from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")result = model(SAMPLE_IMAGE) # それぞれ新しい Results を返し元のオブジェクトは変更しないas_numpy = result.numpy()on_cpu = result.cpu() print(type(as_numpy.boxes.xyxy).__name__)print(type(on_cpu.boxes.xyxy).__name__)Boxesは座標とスコアを1つのパック済みテンソルではなく、別々の配列として保持します。
| 属性 | 内容 |
|---|---|
xyxy | (N, 4)の絶対ピクセル座標、x1 y1 x2 y2 |
xywh | (N, 4)の絶対ピクセル座標、中心x、中心y、幅、高さ |
xyxyn, xywhn | 同じ値を画像の幅と高さで除算 |
conf | (N,)の信頼度 |
cls | (N,)のクラスID、浮動小数点数 |
id | (N,)のトラックID、またはNone |
is_track | idが設定されているか |
data | すべてを連結した値。ボックス、任意のID、信頼度、クラス |
clsは浮動小数点配列なので、result.names[int(cls)]として使ってください。
xyxynとxywhnにはorig_shapeが必要で、Resultsが自動的に設定します。
密なペイロード
画像全体を覆うペイロードはインスタンスごとのペイロードとは異なる動作をし、スライス時に重要になります。
SemanticMaskは元のキャンバス上の(H, W)クラスIDを保持し、255をクラスとして数えない無視値として予約します。classesは存在するIDを列挙して無視値を除外し、class_mask(id)はブール値の(H, W)を返します。
PanopticSegmentationは(H, W)のセグメントIDを保持し、0をvoid IDとして使います。segments_infoは少なくともidとcategory_idを持つ辞書のリストです。segment_idsは存在するIDを列挙し、segment_mask(id)は1つを選択します。
DepthMapは(H, W)の相対的な逆深度を保持します。値が大きいほど近く、メートル単位の距離ではありません。有限値に対するmin、max、meanを公開し、normalized()で[0, 1]へ再スケーリングします。
NormalMapはOpenCVカメラ座標系の(H, W, 3)単位ベクトルを保持します。+xは右、+yは下、+zはシーンの奥を向くため、カメラに正対する面は(0, 0, -1)です。assert_normalized()は各ピクセルが有限で単位長であることを確認します。
EdgeMapは[0, 1]内の(H, W)float32を保持します。連続マップはしきい値処理されずに維持されるため、binary(threshold=0.5)でカットオフを選択します。
Matteは[0, 1]内の(H, W)float32を保持し、1が完全な前景です。arrayはfloat32としてクリップした値を返します。
RestoredImageは(H, W, 3)のuint8 RGBを保持し、arrayで未加工のndarrayを取得し、save(path)で書き出せます。
Probsは画像の確率ベクトルを1つ保持します。top1とtop5はクラスインデックス、top1confとtop5confは対応するスコアです。
EmbeddingsはL2正規化済みの(N, D)行を保持するため、コサイン類似度は内積になります。similarity(other)はギャラリーに対して(N, M)、単一ベクトルに対して(N,)を返し、verify(i, j, threshold=0.4)は2つの行を比較します。
OCRRegionsは読み取り順の(N, 4, 2)ポリゴンを保持し、コーナーの順序は左上、右上、右下、左下です。転記テキストはtexts、認識スコアはconf、検出スコアはdet_confにあります。これらは実際の回転ポリゴンなのでboxesには値を設定しません。長方形が必要な場合はocr.xyxyで軸平行の外接矩形を取得できます。
スライスと移動
result[i]は1つのインスタンスを保持する新しいResultsを返します。インスタンスごとのペイロードはスライスされ、画像全体のペイロードは変更せずに引き継がれます。そのため、分類結果をスライスしても確率ベクトルが単一クラスに切り詰められず、深度結果をスライスしても(H, W)の配置が壊れません。
len(result)はインスタンス数を数えます。ボックス、点、埋め込みベクトル、OCR領域、メッシュが対象です。密な画像全体のペイロードはどれも1として数えられ、何もない結果は0です。
to()、cpu()、cuda()、numpy()はそれぞれ、値が設定された全スロットを変換した新しいResultsを返します。元のオブジェクトは変更しません。
update()だけがその場で変更するメソッドで、指定されたスロットを置き換え、同じオブジェクトを返します。
JSON
import json from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")result = model(SAMPLE_IMAGE) rows = result.summary()print(json.dumps(rows[:2], indent=2)) # 同じキーワード引数を使い同じ内容を文字列として返すprint(result.to_json(normalize=True, decimals=3)[:200])libreyolo predict model=LibreYOLO9s.pt --json \ source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpgsummary()は通常の辞書のリストを返し、to_json()はそのリストをjson.dumpsへ渡します。どちらも同じ3つの引数を受け取ります。normalize=Falseは座標を[0, 1]へ切り替え、decimals=5は丸め桁数を設定し、embeddings=Falseは埋め込みベクトルを含めるかどうかを制御します。
行の形はペイロードに従います。検出行はname、class、confidence、box辞書を持ちます。マスクが存在する場合はsegments、回転バウンディングボックスではobbとcorners、視線ではラジアンと度の両方のgaze角度、トラッキング時はtrack_id、メッシュが存在する場合はmeshパラメータが追加されます。
ボックスがない場合、1つのペイロードが行を決定します。OCRは領域ごとにtextを持つ1行、点は点ごとに1行、パノプティックはセグメントごとにpixel_countとpixel_fractionを持つ1行、セマンティックは存在するクラスごとに1行、分類は上位5クラスを生成します。深度、法線、エッジ、復元、マッティングはそれぞれ、ピクセルではなくマップを説明する要約行を1つ生成します。
2つのペイロードは意図的に省略されます。512個の浮動小数点数を持つ1行は顔ごとに約2 KBになるため、埋め込みベクトルはembedding_dimだけで報告されます。値を含めるにはembeddings=Trueを渡してください。メッシュ頂点は人物ごとに数万個の座標になるため、一切含まれません。形状データにはresult.meshes.verticesを読み取るか、result.meshes.save_obj(path)を呼び出してください。
描画と保存
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt") # save=True でペイロードを描画し runs/detect/predict* の下に書き込むresult = model(SAMPLE_IMAGE, save=True)print(result.saved_path)predict(save=True)がアノテーションを付けて書き出す経路です。値が設定されたスロットに応じて描画ルーチンを選択します。そのため、セマンティック結果は色付きマスク、深度結果は深度表示、パノプティック結果はセグメント付き、matteは背景が透明なRGBA PNG、検出結果は下にマスクを重ねたボックスとして書き出されます。書き込まれたパスはresult.saved_pathとして結果に追加されます。
Results.plot()は名前から想像されるより対象が限定されています。法線マップとエッジマップだけで定義され、そのほかではNotImplementedErrorが発生します。ほかのタスクではsave=Trueを使ってください。
Results.save(path)も同様に対象が限定されています。matte結果を背景が透明なRGBA PNGの切り抜きとして書き出し、そのほかではNotImplementedErrorが発生します。Results.cutout()は書き込まずに同じRGBA配列を返します。どちらにもソース画像が必要で、result.pathから取得するかimage=で渡します。
2つのペイロードは固有の書き込み機能を持ちます。復元画像にはresult.restored.save(path)、メッシュにはresult.meshes.save_obj(path, index=0)を使います。
ファイルの保存先とoutput_pathおよびoutput_file_formatの動作については推論ソースを参照してください。
エクスポートした成果物も同じオブジェクトを返す
pip install "libreyolo[onnx]"from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreYOLO9s.pt")path = model.export(format="onnx") # 書き込んだパスを返す # LibreYOLO() はファイルサフィックスで振り分けexported = LibreYOLO(path)result = exported(SAMPLE_IMAGE) print(type(result).__name__, len(result.boxes))LibreYOLO()はファイルサフィックスで振り分けるため、エクスポートした成果物は.ptチェックポイントと同じ呼び出しで読み込まれ、同じResultsを返します。.onnx、.engine、.pte、.mnnファイルはサフィックスで認識され、OpenVINO、Paddle、ncnnのディレクトリとTritonモデルURLも認識されます。モデルをエクスポート済みビルドへ切り替えても、result.boxes.xyxyを読み取るコードは変わりません。すべての形式についてはエクスポートを参照してください。
代わりにランタイム固有のAPIを使う場合は、前処理、後処理、クラス名を自分で管理する必要があります。