"""画像 1 枚のセグメンテーション(枠で切り出す → ResUNet → 元の画像の位置へ戻す).
枠の決め方は呼び出し側が選ぶ(`detection.py`):
- 検出なし: 画像全体(`full_rect`)を ResUNet に掛ける.切り出し済み画像はこれ
- 正解マスクの外接矩形(`mask_bounding_rect`): 検出が完璧な場合の上限を見るため
- 検出モデル(`OnnxDetector`): DeepTIAS 2.7 と同じ
コピー元(TIASjudge Issue #13.ロジックは改変しない): TIASJudgeModel リポジトリの
`src/tias_judge_model/segmentation/pipeline.py`
(コミット 95cd9a2e18f3dabfc06718a8577666fa9c6ca106.本ファイルの最終変更は
6d332cfa1e637a4a824aada9972f7c6812f72acb).
import のパッケージ名だけを `tiasjudge.core.ml` に合わせた.
引き渡し仕様は TIASJudgeModel の `docs/04_SPEC/SPEC_04_TIASjudge引き渡し仕様.md`.
"""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from tiasjudge.core.ml.detection import Rect
from tiasjudge.core.ml.resunet import CropMasks, ResUNetRunner, output_to_masks
@dataclass(frozen=True)
class SegmentationParams:
"""後処理の設定(`SegEvalConfig` の該当部分).
Attributes:
foreground_channel: 前景として使う ResUNet の出力チャンネル.
min_area: 小領域除去の面積の上限.
mask_threshold: 枠のサイズに戻したマスクの 2 値化のしきい値.
"""
foreground_channel: int
min_area: int
mask_threshold: int
def place_masks(crop: CropMasks, rect: Rect, height: int, width: int) -> CropMasks:
"""枠のサイズのマスクを元の画像サイズのマスクに配置する(枠の外は背景).
Args:
crop: 枠のサイズのマスク.
rect: 枠.
height: 元の画像の高さ.
width: 元の画像の幅.
Returns:
`(height, width)` の bool のマスク.
"""
def place(mask: np.ndarray) -> np.ndarray:
out = np.zeros((height, width), dtype=bool)
out[rect.y0 : rect.y1, rect.x0 : rect.x1] = mask
return out
return CropMasks(
post=place(crop.post),
no_post=place(crop.no_post),
other_channel=place(crop.other_channel),
postprocess_applied=crop.postprocess_applied,
)
def empty_masks(height: int, width: int) -> CropMasks:
"""前景の無いマスク(検出できなかった場合)を返す.
Args:
height: 画像の高さ.
width: 画像の幅.
Returns:
すべて背景のマスク.
"""
empty = np.zeros((height, width), dtype=bool)
return CropMasks(post=empty, no_post=empty, other_channel=empty, postprocess_applied=False)
def segment_in_rect(
bgr: np.ndarray, rect: Rect, runner: ResUNetRunner, params: SegmentationParams
) -> CropMasks:
"""枠で切り出して ResUNet に掛け,元の画像サイズのマスクを返す.
Args:
bgr: BGR 画像(`(H, W, 3)`, uint8).
rect: 切り出す枠(画像の内側.幅・高さは 1 以上).
runner: ResUNet の推論器.
params: 後処理の設定.
Returns:
`(H, W)` の bool のマスク(後処理あり・なし・もう一方のチャンネル).
"""
height, width = bgr.shape[:2]
crop = bgr[rect.y0 : rect.y1, rect.x0 : rect.x1]
output = runner.run(crop)
masks = output_to_masks(
output,
rect.width,
rect.height,
foreground_channel=params.foreground_channel,
min_area=params.min_area,
mask_threshold=params.mask_threshold,
)
return place_masks(masks, rect, height, width)