|
|
import os |
|
|
import sys |
|
|
import glob |
|
|
import numpy as np |
|
|
import cv2 |
|
|
from typing import List, Optional |
|
|
|
|
|
""" |
|
|
Lightweight runner for CropFormer/Mask2Former inference without spawning a process. |
|
|
Keeps a global singleton VisualizationDemo so the model is initialized only once. |
|
|
""" |
|
|
|
|
|
|
|
|
_CROPF_DIR = None |
|
|
def make_cropformer_dir(MK_PATH: str) -> str: |
|
|
global _CROPF_DIR |
|
|
_CROPF_DIR = os.path.join(MK_PATH, "third_party/detectron2/projects/CropFormer") |
|
|
if _CROPF_DIR not in sys.path: |
|
|
sys.path.insert(0, _CROPF_DIR) |
|
|
sys.path.insert(0, os.path.join(_CROPF_DIR, "demo_cropformer")) |
|
|
|
|
|
|
|
|
_DEMO = None |
|
|
_CFG_KEY = None |
|
|
|
|
|
def _build_key(config_file: str, opts: Optional[List[str]]) -> tuple: |
|
|
return (os.path.abspath(config_file), tuple(opts) if opts else ()) |
|
|
|
|
|
def preload_cropformer_model(config_file: str, opts: Optional[List[str]] = None) -> bool: |
|
|
""" |
|
|
Public helper to initialize the model once at script startup. |
|
|
Returns True if initialized or already available. |
|
|
""" |
|
|
_ensure_demo(config_file, opts) |
|
|
return True |
|
|
|
|
|
def _ensure_demo(config_file: str, opts: Optional[List[str]]): |
|
|
""" |
|
|
Build or reuse a global VisualizationDemo for given config/options. |
|
|
""" |
|
|
global _DEMO, _CFG_KEY |
|
|
key = _build_key(config_file, opts) |
|
|
if _DEMO is not None and _CFG_KEY == key: |
|
|
return _DEMO |
|
|
|
|
|
|
|
|
from detectron2.config import get_cfg |
|
|
from detectron2.projects.deeplab import add_deeplab_config |
|
|
from mask2former import add_maskformer2_config |
|
|
from predictor import VisualizationDemo |
|
|
|
|
|
cfg = get_cfg() |
|
|
add_deeplab_config(cfg) |
|
|
add_maskformer2_config(cfg) |
|
|
cfg.merge_from_file(config_file) |
|
|
if opts: |
|
|
cfg.merge_from_list(opts) |
|
|
cfg.freeze() |
|
|
_DEMO = VisualizationDemo(cfg) |
|
|
_CFG_KEY = key |
|
|
return _DEMO |
|
|
|
|
|
def run_cropformer_mask_predict( |
|
|
config_file: str, |
|
|
root: str, |
|
|
image_path_pattern: str, |
|
|
dataset: str, |
|
|
seq_name_list: str, |
|
|
confidence_threshold: float = 0.5, |
|
|
opts: Optional[List[str]] = None, |
|
|
) -> None: |
|
|
""" |
|
|
Run CropFormer/Mask2Former demo (mask_predict) logic directly from Python. |
|
|
Writes mask PNGs into {root}/{seq}/output/mask (or special matterport3d path). |
|
|
""" |
|
|
from detectron2.data.detection_utils import read_image |
|
|
import torch |
|
|
|
|
|
demo = _ensure_demo(config_file, opts) |
|
|
|
|
|
|
|
|
seq_names = seq_name_list.split("+") |
|
|
for seq_name in seq_names: |
|
|
seq_dir = os.path.join(root, seq_name) |
|
|
image_list = sorted(glob.glob(os.path.join(seq_dir, image_path_pattern))) |
|
|
if dataset == "matterport3d": |
|
|
output_dir = os.path.join(seq_dir, seq_name, "output/mask") |
|
|
else: |
|
|
output_dir = os.path.join(seq_dir, "output/mask") |
|
|
os.makedirs(output_dir, exist_ok=True) |
|
|
|
|
|
for path in image_list: |
|
|
|
|
|
img = read_image(path, format="BGR") |
|
|
predictions = demo.run_on_image(img) |
|
|
|
|
|
pred_masks = predictions["instances"].pred_masks |
|
|
pred_scores = predictions["instances"].scores |
|
|
|
|
|
|
|
|
selected_indexes = (pred_scores >= confidence_threshold) |
|
|
selected_scores = pred_scores[selected_indexes] |
|
|
selected_masks = pred_masks[selected_indexes] |
|
|
|
|
|
if selected_masks.numel() == 0: |
|
|
|
|
|
h, w = img.shape[:2] |
|
|
cv2.imwrite( |
|
|
os.path.join(output_dir, os.path.basename(path).split(".")[0] + ".png"), |
|
|
np.zeros((h, w), dtype=np.uint8), |
|
|
) |
|
|
continue |
|
|
|
|
|
_, m_H, m_W = selected_masks.shape |
|
|
mask_image = np.zeros((m_H, m_W), dtype=np.uint8) |
|
|
|
|
|
|
|
|
mask_id = 1 |
|
|
selected_scores, ranks = torch.sort(selected_scores) |
|
|
for index in ranks: |
|
|
num_pixels = torch.sum(selected_masks[index]) |
|
|
if num_pixels < 400: |
|
|
|
|
|
continue |
|
|
mask_image[(selected_masks[index] == 1).cpu().numpy()] = mask_id |
|
|
mask_id += 1 |
|
|
|
|
|
cv2.imwrite( |
|
|
os.path.join(output_dir, os.path.basename(path).split(".")[0] + ".png"), |
|
|
mask_image, |
|
|
) |
|
|
|
|
|
|
|
|
|