403Webshell
Server IP : 217.154.3.148  /  Your IP : 216.73.216.90
Web Server : Apache
System : Linux blissful-wright.217-154-3-148.plesk.page 6.8.0-124-generic #124-Ubuntu SMP PREEMPT_DYNAMIC Tue May 26 13:00:45 UTC 2026 x86_64
User : gracious-boyd_hfhh1h8vo9n ( 10000)
PHP Version : 8.3.31
Disable Function : opcache_get_status
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/lib/segmentation/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/vhosts/gracious-boyd.217-154-3-148.plesk.page/nextjs/lib/segmentation/occluder_best.ts
import sharp from "sharp";
import { connectedComponents } from "@/lib/masks/components";
import { OccluderSegOptions, OccluderSegResult, inferOccluderMask } from "./occluder";

export type OccluderMethod = "u2net_refine" | "sam_hq" | "hybrid" | "distilled_unsup";

const DEFAULT_METHOD: OccluderMethod = "u2net_refine";
const SAM_HQ_DEFAULT_MODEL = "syscv-community/sam-hq-vit-base";
const SAM_HQ_DEFAULT_DEVICE = "cpu";
const SAM_HQ_DEFAULT_BAND_RADIUS = "10";
const SAM_HQ_DEFAULT_BOX_MARGIN = "32";
const SAM_HQ_DEFAULT_EDGE_WEIGHT = "0.7";
const SAM_HQ_DEFAULT_EDGE_RADIUS = "2";
const PATCH_REFINE_DEFAULT = "0";

function resolveMethod(input?: string | null): OccluderMethod {
  const value = (input ?? "").trim().toLowerCase();
  if (value === "sam_hq" || value === "sam-hq" || value === "sam_hq_prompted") return "sam_hq";
  if (value === "hybrid") return "hybrid";
  if (value === "distilled_unsup" || value === "distilled-unsup" || value === "distilled") return "distilled_unsup";
  return "u2net_refine";
}

function normalizeBackend(input?: string | null): string {
  const value = (input ?? "").trim().toLowerCase();
  if (value === "rfdet_m3" || value === "comfy_rfdet_m3") return "rfdet_m3";
  return "";
}

function buildSamHqEnv(baseEnv?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
  const env: NodeJS.ProcessEnv = { ...(baseEnv ?? {}) };
  env.OCCLUDER_SAM_HQ = "1";
  if (!env.OCCLUDER_SAM_HQ_MODEL && !process.env.OCCLUDER_SAM_HQ_MODEL) {
    env.OCCLUDER_SAM_HQ_MODEL = SAM_HQ_DEFAULT_MODEL;
  }
  if (!env.OCCLUDER_SAM_HQ_DEVICE && !process.env.OCCLUDER_SAM_HQ_DEVICE) {
    env.OCCLUDER_SAM_HQ_DEVICE = SAM_HQ_DEFAULT_DEVICE;
  }
  if (!env.OCCLUDER_SAM_BAND_RADIUS) {
    env.OCCLUDER_SAM_BAND_RADIUS = SAM_HQ_DEFAULT_BAND_RADIUS;
  }
  if (!env.OCCLUDER_SAM_BOX_MARGIN) {
    env.OCCLUDER_SAM_BOX_MARGIN = SAM_HQ_DEFAULT_BOX_MARGIN;
  }
  if (!env.OCCLUDER_SAM_EDGE_WEIGHT) {
    env.OCCLUDER_SAM_EDGE_WEIGHT = SAM_HQ_DEFAULT_EDGE_WEIGHT;
  }
  if (!env.OCCLUDER_SAM_EDGE_RADIUS) {
    env.OCCLUDER_SAM_EDGE_RADIUS = SAM_HQ_DEFAULT_EDGE_RADIUS;
  }
  return env;
}

function coverageOf(mask: Uint8Array): number {
  if (!mask || mask.length === 0) return 0;
  let solid = 0;
  for (let i = 0; i < mask.length; i += 1) {
    if (mask[i] > 127) solid += 1;
  }
  return solid / mask.length;
}

function parseNumberEnv(name: string, fallback: number): number {
  const raw = Number(process.env[name] ?? "");
  return Number.isFinite(raw) ? raw : fallback;
}

function parseBool(value: string | undefined | null, fallback: boolean): boolean {
  const normalized = (value ?? "").trim().toLowerCase();
  if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") return true;
  if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") return false;
  return fallback;
}

function scoreCoverage(value: number, low = 0.15, high = 0.55): number {
  if (value >= low && value <= high) return 0;
  if (value < low) return low - value;
  return value - high;
}

function meanBinaryTransitionsPerRow(mask: Uint8Array, width: number, height: number, threshold = 127): number {
  if (!(width > 1 && height > 0)) return 0;
  let sum = 0;
  for (let y = 0; y < height; y += 1) {
    const row = y * width;
    let prev = mask[row] > threshold ? 1 : 0;
    let transitions = 0;
    for (let x = 1; x < width; x += 1) {
      const next = mask[row + x] > threshold ? 1 : 0;
      if (next !== prev) transitions += 1;
      prev = next;
    }
    sum += transitions;
  }
  return sum / height;
}

function meanBinaryTransitionsPerCol(mask: Uint8Array, width: number, height: number, threshold = 127): number {
  if (!(width > 0 && height > 1)) return 0;
  let sum = 0;
  for (let x = 0; x < width; x += 1) {
    let prev = mask[x] > threshold ? 1 : 0;
    let transitions = 0;
    for (let y = 1; y < height; y += 1) {
      const next = mask[y * width + x] > threshold ? 1 : 0;
      if (next !== prev) transitions += 1;
      prev = next;
    }
    sum += transitions;
  }
  return sum / width;
}

function orMasks(a: Uint8Array, b: Uint8Array): Uint8Array {
  const len = Math.min(a.length, b.length);
  const out = new Uint8Array(len);
  for (let i = 0; i < len; i += 1) out[i] = (a[i] > 127 || b[i] > 127) ? 255 : 0;
  return out;
}

function andMasks(a: Uint8Array, b: Uint8Array): Uint8Array {
  const len = Math.min(a.length, b.length);
  const out = new Uint8Array(len);
  for (let i = 0; i < len; i += 1) out[i] = (a[i] > 127 && b[i] > 127) ? 255 : 0;
  return out;
}

function dilateMask(mask: Uint8Array, width: number, height: number, radius: number): Uint8Array {
  const r = Math.max(0, Math.round(radius));
  if (r <= 0) return Uint8Array.from(mask);
  const out = new Uint8Array(mask.length);
  for (let y = 0; y < height; y += 1) {
    for (let x = 0; x < width; x += 1) {
      let solid = false;
      for (let dy = -r; dy <= r && !solid; dy += 1) {
        const ny = y + dy;
        if (ny < 0 || ny >= height) continue;
        const row = ny * width;
        for (let dx = -r; dx <= r; dx += 1) {
          const nx = x + dx;
          if (nx < 0 || nx >= width) continue;
          if (mask[row + nx] > 127) {
            solid = true;
            break;
          }
        }
      }
      out[y * width + x] = solid ? 255 : 0;
    }
  }
  return out;
}

function erodeMask(mask: Uint8Array, width: number, height: number, radius: number): Uint8Array {
  const r = Math.max(0, Math.round(radius));
  if (r <= 0) return Uint8Array.from(mask);
  const out = new Uint8Array(mask.length);
  for (let y = 0; y < height; y += 1) {
    for (let x = 0; x < width; x += 1) {
      let all = true;
      for (let dy = -r; dy <= r && all; dy += 1) {
        const ny = y + dy;
        if (ny < 0 || ny >= height) {
          all = false;
          break;
        }
        const row = ny * width;
        for (let dx = -r; dx <= r; dx += 1) {
          const nx = x + dx;
          if (nx < 0 || nx >= width || mask[row + nx] <= 127) {
            all = false;
            break;
          }
        }
      }
      out[y * width + x] = all ? 255 : 0;
    }
  }
  return out;
}

function boundaryMask(mask: Uint8Array, width: number, height: number): Uint8Array {
  const dil = dilateMask(mask, width, height, 1);
  const ero = erodeMask(mask, width, height, 1);
  const out = new Uint8Array(mask.length);
  for (let i = 0; i < out.length; i += 1) out[i] = (dil[i] > 127 && ero[i] <= 127) ? 255 : 0;
  return out;
}

function quantile(values: Float32Array, q: number, stride = 4): number {
  if (!values.length) return 0;
  const picked: number[] = [];
  for (let i = 0; i < values.length; i += Math.max(1, stride)) picked.push(values[i] ?? 0);
  if (!picked.length) return 0;
  picked.sort((a, b) => a - b);
  const idx = Math.max(0, Math.min(picked.length - 1, Math.floor((picked.length - 1) * Math.max(0, Math.min(1, q)))));
  return picked[idx] ?? 0;
}

async function decodeGray(raw: Buffer, width: number, height: number): Promise<Float32Array> {
  const out = await sharp(raw, { failOnError: false })
    .removeAlpha()
    .greyscale()
    .resize(width, height, { fit: "fill", kernel: "lanczos3" })
    .raw()
    .toBuffer();
  const gray = new Float32Array(out.length);
  for (let i = 0; i < out.length; i += 1) gray[i] = out[i] ?? 0;
  return gray;
}

type ProxyCrop = {
  rank: number;
  bbox: { x: number; y: number; w: number; h: number };
  score: number;
  reasonTags: string[];
};

function buildProxyPatchPlan(
  baseMask: Uint8Array,
  width: number,
  height: number,
  gray: Float32Array,
  tileMask: Uint8Array,
): { focusMask: Uint8Array; crops: ProxyCrop[]; stats: Record<string, number> } {
  const total = Math.max(1, width * height);
  const tileEdge = boundaryMask(tileMask, width, height);
  const baseEdge = boundaryMask(baseMask, width, height);
  const baseEdgeWide = dilateMask(baseEdge, width, height, 4);
  const tileEdgeWide = dilateMask(tileEdge, width, height, 2);
  const outsideRing = andMasks(dilateMask(baseMask, width, height, 10), invertMask(baseMask));

  const gx = new Float32Array(total);
  const gy = new Float32Array(total);
  const mag = new Float32Array(total);
  for (let y = 1; y < height - 1; y += 1) {
    for (let x = 1; x < width - 1; x += 1) {
      const idx = y * width + x;
      const gxh = (gray[idx + 1] ?? 0) - (gray[idx - 1] ?? 0);
      const gyh = (gray[idx + width] ?? 0) - (gray[idx - width] ?? 0);
      gx[idx] = gxh;
      gy[idx] = gyh;
      mag[idx] = Math.hypot(gxh, gyh);
    }
  }
  const magQ = quantile(mag, 0.82);

  const spill = new Uint8Array(total);
  const texture = new Uint8Array(total);
  for (let i = 0; i < total; i += 1) {
    const inBase = baseMask[i] > 127;
    const atBaseEdge = baseEdgeWide[i] > 127;
    const atTileEdge = tileEdgeWide[i] > 127;
    const outRing = outsideRing[i] > 127;
    const m = mag[i] ?? 0;
    if (inBase && atBaseEdge && atTileEdge) spill[i] = 255;
    if (outRing && atTileEdge && m >= magQ) texture[i] = 255;
  }

  const thinMask = new Uint8Array(total);
  const spillish = andMasks(baseMask, tileEdgeWide);
  const spillComps = connectedComponents(spillish, width, height, 24);
  for (const comp of spillComps) {
    let minX = width;
    let minY = height;
    let maxX = 0;
    let maxY = 0;
    for (const idx of comp.pixels) {
      const y = Math.floor(idx / width);
      const x = idx - y * width;
      if (x < minX) minX = x;
      if (x > maxX) maxX = x;
      if (y < minY) minY = y;
      if (y > maxY) maxY = y;
    }
    const bw = Math.max(1, maxX - minX + 1);
    const bh = Math.max(1, maxY - minY + 1);
    const fill = comp.area / Math.max(1, bw * bh);
    if (Math.min(bw, bh) <= 4 || fill < 0.22 || comp.area < 180) {
      for (const idx of comp.pixels) thinMask[idx] = 255;
    }
  }

  const heat = new Float32Array(total);
  for (let i = 0; i < total; i += 1) {
    const s = spill[i] > 127 ? 1 : 0;
    const t = texture[i] > 127 ? 1 : 0;
    const thin = thinMask[i] > 127 ? 1 : 0;
    heat[i] = 0.52 * s + 0.30 * t + 0.18 * thin;
  }
  const heatThreshold = quantile(heat, 0.84, 2);
  const hot = new Uint8Array(total);
  for (let i = 0; i < total; i += 1) hot[i] = heat[i] >= Math.max(0.12, heatThreshold) ? 255 : 0;
  const hotDil = dilateMask(hot, width, height, 1);
  const comps = connectedComponents(hotDil, width, height, 36);
  const ranked = comps
    .map((comp) => {
      let minX = width;
      let minY = height;
      let maxX = 0;
      let maxY = 0;
      let spillHits = 0;
      let textureHits = 0;
      let thinHits = 0;
      let score = 0;
      for (const idx of comp.pixels) {
        const y = Math.floor(idx / width);
        const x = idx - y * width;
        if (x < minX) minX = x;
        if (x > maxX) maxX = x;
        if (y < minY) minY = y;
        if (y > maxY) maxY = y;
        if (spill[idx] > 127) spillHits += 1;
        if (texture[idx] > 127) textureHits += 1;
        if (thinMask[idx] > 127) thinHits += 1;
        score += heat[idx] ?? 0;
      }
      const avgScore = score / Math.max(1, comp.area);
      const tags: string[] = [];
      if (spillHits / Math.max(1, comp.area) > 0.12) tags.push("tile_edge_overlap");
      if (textureHits / Math.max(1, comp.area) > 0.10) tags.push("texture_mismatch");
      if (thinHits / Math.max(1, comp.area) > 0.08) tags.push("thin_strip_or_island");
      if (!tags.length) tags.push("mixed_proxy");
      return {
        comp,
        score: avgScore * Math.sqrt(comp.area),
        bbox: { x: minX, y: minY, w: Math.max(1, maxX - minX + 1), h: Math.max(1, maxY - minY + 1) },
        tags,
      };
    })
    .sort((a, b) => b.score - a.score);

  const topN = Math.max(1, Math.min(16, Math.round(parseNumberEnv("OCCLUDER_PATCH_TOP_N", 10))));
  const selected = ranked.slice(0, topN);
  const focus = new Uint8Array(total);
  const crops: ProxyCrop[] = [];
  selected.forEach((entry, idx) => {
    for (const px of entry.comp.pixels) focus[px] = 255;
    crops.push({
      rank: idx + 1,
      bbox: entry.bbox,
      score: Number(entry.score.toFixed(4)),
      reasonTags: entry.tags,
    });
  });
  const focusDil = dilateMask(focus, width, height, 3);
  const spillCov = coverageOf(spill);
  const textureCov = coverageOf(texture);
  const thinCov = coverageOf(thinMask);

  return {
    focusMask: focusDil,
    crops,
    stats: {
      heatThreshold: Number(heatThreshold.toFixed(4)),
      selectedCount: crops.length,
      spillCoverage: Number(spillCov.toFixed(6)),
      textureCoverage: Number(textureCov.toFixed(6)),
      thinCoverage: Number(thinCov.toFixed(6)),
    },
  };
}

function invertMask(mask: Uint8Array): Uint8Array {
  const out = new Uint8Array(mask.length);
  for (let i = 0; i < mask.length; i += 1) out[i] = mask[i] > 127 ? 0 : 255;
  return out;
}

function mergePatchCandidate(
  base: Uint8Array,
  patch: Uint8Array,
  focus: Uint8Array,
  tileMask: Uint8Array | null,
  width: number,
  height: number,
): Uint8Array {
  const baseB = base;
  const patchB = patch;
  const focusDil = dilateMask(focus, width, height, 8);
  const edgeBand = dilateMask(boundaryMask(baseB, width, height), width, height, 7);
  const core = erodeMask(baseB, width, height, 3);
  const tileEdge = tileMask ? dilateMask(boundaryMask(tileMask, width, height), width, height, 2) : null;

  const out = Uint8Array.from(baseB);
  for (let i = 0; i < out.length; i += 1) {
    const inBase = baseB[i] > 127;
    const inPatch = patchB[i] > 127;
    const inFocus = focusDil[i] > 127;
    const inEdge = edgeBand[i] > 127;
    const inCore = core[i] > 127;
    const tileLeakRisk = tileEdge ? (tileEdge[i] > 127 && !inFocus) : false;

    if (!inBase && inPatch && (inFocus || inEdge) && !tileLeakRisk) out[i] = 255;
    if (inBase && !inPatch && inFocus && !inCore) out[i] = 0;
  }
  return out;
}

async function alignTileMask(
  tileMask: Uint8Array | null | undefined,
  width: number | null | undefined,
  height: number | null | undefined,
  targetW: number,
  targetH: number,
): Promise<Uint8Array | null> {
  if (!tileMask || !width || !height || width <= 0 || height <= 0) return null;
  if (tileMask.length !== width * height) return null;
  if (width === targetW && height === targetH) return tileMask;
  const resized = await sharp(Buffer.from(tileMask), { raw: { width, height, channels: 1 } })
    .resize(targetW, targetH, { kernel: "nearest", fit: "fill" })
    .threshold(128)
    .raw()
    .toBuffer();
  return new Uint8Array(resized);
}

function analyzeMaskQuality(
  mask: Uint8Array,
  width: number,
  height: number,
  tileMask?: Uint8Array | null,
): { score: number; coverage: number; transitionDensity: number; tileLeak: number; largestCompRatio: number } {
  const total = Math.max(1, width * height);
  let area = 0;
  let tileHit = 0;
  const hasTile = Boolean(tileMask && tileMask.length === mask.length);
  for (let i = 0; i < mask.length; i += 1) {
    if (mask[i] > 127) {
      area += 1;
      if (hasTile && (tileMask![i] > 127)) tileHit += 1;
    }
  }
  const coverage = area / total;
  const rowT = meanBinaryTransitionsPerRow(mask, width, height);
  const colT = meanBinaryTransitionsPerCol(mask, width, height);
  const transitionDensity = ((rowT / Math.max(1, width)) + (colT / Math.max(1, height))) * 0.5;
  const tileLeak = area > 0 ? tileHit / area : 0;

  const comps = connectedComponents(mask, width, height, 1);
  let largest = 0;
  for (const comp of comps) largest = Math.max(largest, comp.area);
  const largestCompRatio = area > 0 ? largest / area : 0;

  const minCoverage = parseNumberEnv("OCCLUDER_DISTILL_MIN_COVERAGE", 0.08);
  const maxCoverage = parseNumberEnv("OCCLUDER_DISTILL_MAX_COVERAGE", 0.62);
  const maxTransitionDensity = parseNumberEnv("OCCLUDER_DISTILL_MAX_TRANS_DENSITY", 0.18);
  const maxTileLeak = parseNumberEnv("OCCLUDER_DISTILL_MAX_TILE_LEAK", 0.78);

  let score = 100;
  score -= 150 * Math.max(0, coverage - maxCoverage);
  score -= 120 * Math.max(0, minCoverage - coverage);
  score -= 120 * Math.max(0, transitionDensity - maxTransitionDensity);
  if (hasTile) score -= 55 * Math.max(0, tileLeak - maxTileLeak);
  score -= 28 * Math.max(0, 0.18 - largestCompRatio);
  score = Math.max(0, Math.min(100, score));

  return {
    score: Number(score.toFixed(4)),
    coverage: Number(coverage.toFixed(6)),
    transitionDensity: Number(transitionDensity.toFixed(6)),
    tileLeak: Number(tileLeak.toFixed(6)),
    largestCompRatio: Number(largestCompRatio.toFixed(6)),
  };
}

function mergeDistilledMasks(
  base: Uint8Array,
  sam: Uint8Array,
  width: number,
  height: number,
  tileMask?: Uint8Array | null,
): Uint8Array {
  const total = width * height;
  const union = orMasks(base, sam);
  const core = dilateMask(andMasks(base, sam), width, height, 4);
  const bottomStart = Math.floor(height * (1 - parseNumberEnv("OCCLUDER_DISTILL_BOTTOM_STRIP_FRAC", 0.18)));
  const minArea = Math.max(64, Math.floor(total * parseNumberEnv("OCCLUDER_DISTILL_MIN_COMP_FRAC", 0.00012)));
  const bigArea = Math.max(minArea * 3, Math.floor(total * parseNumberEnv("OCCLUDER_DISTILL_BIG_COMP_FRAC", 0.015)));
  const out = new Uint8Array(union.length);
  const comps = connectedComponents(union, width, height, minArea);

  for (const comp of comps) {
    let touchCore = false;
    let touchBottom = false;
    let tileHits = 0;
    for (const idx of comp.pixels) {
      if (core[idx] > 127) touchCore = true;
      const y = Math.floor(idx / width);
      if (y >= bottomStart) touchBottom = true;
      if (tileMask && tileMask.length === union.length && tileMask[idx] > 127) tileHits += 1;
      if (touchCore && touchBottom) break;
    }
    const tileRatio = tileMask && tileMask.length === union.length ? tileHits / Math.max(1, comp.area) : 0;
    const keep = touchCore || touchBottom || comp.area >= bigArea || (comp.area >= minArea * 2 && tileRatio < 0.92);
    if (!keep) continue;
    for (const idx of comp.pixels) out[idx] = 255;
  }
  return out;
}

export async function inferOccluderBest(
  raw: Buffer,
  options: OccluderSegOptions = {},
): Promise<OccluderSegResult> {
  const envMethod = options.env?.OCCLUDER_METHOD ?? process.env.OCCLUDER_METHOD;
  const backend = normalizeBackend(
    options.env?.OCCLUDER_BACKEND ??
    options.env?.OCCLUDER_PRESET ??
    process.env.OCCLUDER_BACKEND ??
    process.env.OCCLUDER_PRESET,
  );
  let method = resolveMethod(envMethod);
  if (backend === "rfdet_m3" && method === "u2net_refine") {
    method = "distilled_unsup";
  }

  if (method === "sam_hq") {
    // NOTE: current pipeline only supports SAM prompted mode via occluder_segment.py.
    const env = buildSamHqEnv(options.env);
    return inferOccluderMask(raw, { ...options, samPrompted: true, env });
  }

  if (method === "hybrid") {
    const base = await inferOccluderMask(raw, { ...options, samPrompted: false });
    if (!options.tileMask || !options.tileMaskWidth || !options.tileMaskHeight) {
      return base;
    }
    const baseCoverage = coverageOf(base.mask);
    if (baseCoverage >= 0.12 && baseCoverage <= 0.65) {
      return base;
    }
    const sam = await inferOccluderMask(raw, { ...options, samPrompted: true });
    const samCoverage = coverageOf(sam.mask);
    const baseScore = scoreCoverage(baseCoverage);
    const samScore = scoreCoverage(samCoverage);
    return samScore <= baseScore ? sam : base;
  }

  if (method === "distilled_unsup") {
    const base = await inferOccluderMask(raw, { ...options, samPrompted: false });
    const alignedTileMask = await alignTileMask(
      options.tileMask ?? null,
      options.tileMaskWidth ?? null,
      options.tileMaskHeight ?? null,
      base.width,
      base.height,
    );
    const candidates: Array<{ name: string; result: OccluderSegResult }> = [{ name: "base", result: base }];
    let samError: string | null = null;

    if (alignedTileMask) {
      try {
        const sam = await inferOccluderMask(raw, {
          ...options,
          samPrompted: true,
          tileMask: alignedTileMask,
          tileMaskWidth: base.width,
          tileMaskHeight: base.height,
        });
        candidates.push({ name: "sam_prompted", result: sam });
        const mergedMask = mergeDistilledMasks(base.mask, sam.mask, base.width, base.height, alignedTileMask);
        candidates.push({
          name: "distilled_merge",
          result: {
            mask: mergedMask,
            width: base.width,
            height: base.height,
            source: "distilled_unsup_merge",
            meta: {
              baseSource: base.source,
              samSource: sam.source,
            },
          },
        });
      } catch (err) {
        samError = err instanceof Error ? err.message : String(err);
      }
    }

    const analyzed = candidates.map((entry) => ({
      ...entry,
      proxy: analyzeMaskQuality(entry.result.mask, entry.result.width, entry.result.height, alignedTileMask),
    }));
    analyzed.sort((a, b) => b.proxy.score - a.proxy.score);
    let winner = analyzed[0]!;
    const minProxy = parseNumberEnv("OCCLUDER_DISTILL_MIN_PROXY", 42);
    if (winner.proxy.score < minProxy) {
      const baseEval = analyzed.find((x) => x.name === "base");
      if (baseEval) winner = baseEval;
    }

    const patchRefineEnabled = parseBool(
      options.env?.OCCLUDER_PATCH_REFINE ??
      process.env.OCCLUDER_PATCH_REFINE ??
      PATCH_REFINE_DEFAULT,
      false,
    );
    let patchRefineMeta: Record<string, unknown> | null = null;
    if (patchRefineEnabled && alignedTileMask && winner.result.width > 0 && winner.result.height > 0) {
      try {
        const gray = await decodeGray(raw, winner.result.width, winner.result.height);
        const proxyPlan = buildProxyPatchPlan(
          winner.result.mask,
          winner.result.width,
          winner.result.height,
          gray,
          alignedTileMask,
        );
        if (proxyPlan.crops.length > 0 && coverageOf(proxyPlan.focusMask) > 0.001) {
          const patchEnv = buildSamHqEnv({
            ...(options.env ?? {}),
            OCCLUDER_SAM_POS_INSIDE: "1",
            OCCLUDER_SAM_POS_BAND_ONLY: "0",
            OCCLUDER_SAM_TOP_K: options.env?.OCCLUDER_SAM_TOP_K ?? "2",
          });
          const patchResult = await inferOccluderMask(raw, {
            ...options,
            samPrompted: true,
            tileMask: proxyPlan.focusMask,
            tileMaskWidth: winner.result.width,
            tileMaskHeight: winner.result.height,
            env: patchEnv,
          });
          const mergedPatch = mergePatchCandidate(
            winner.result.mask,
            patchResult.mask,
            proxyPlan.focusMask,
            alignedTileMask,
            winner.result.width,
            winner.result.height,
          );
          const mergedProxy = analyzeMaskQuality(mergedPatch, winner.result.width, winner.result.height, alignedTileMask);
          const guardDelta = mergedProxy.score - winner.proxy.score;
          const allowPatch = guardDelta >= -1.5;
          patchRefineMeta = {
            enabled: true,
            accepted: allowPatch,
            scoreDelta: Number(guardDelta.toFixed(4)),
            proxyStats: proxyPlan.stats,
            proxyCrops: proxyPlan.crops,
            patchSource: patchResult.source,
          };
          if (allowPatch) {
            winner = {
              name: "patch_refined",
              result: {
                ...winner.result,
                mask: mergedPatch,
                source: `${winner.result.source}+patch_refined`,
                meta: {
                  ...(winner.result.meta ?? {}),
                  patchRefine: patchRefineMeta,
                },
              },
              proxy: mergedProxy,
            };
          }
        } else {
          patchRefineMeta = {
            enabled: true,
            accepted: false,
            reason: "proxy_targets_empty",
            proxyStats: proxyPlan.stats,
          };
        }
      } catch (err) {
        patchRefineMeta = {
          enabled: true,
          accepted: false,
          error: err instanceof Error ? err.message : String(err),
        };
      }
    }

    return {
      ...winner.result,
      source: `${winner.result.source}+distilled_unsup`,
      meta: {
        ...(winner.result.meta ?? {}),
        distilled: {
          method: "distilled_unsup",
          backend: backend || null,
          selected: winner.name,
          minProxy,
          proxy: winner.proxy,
          candidates: analyzed.map((x) => ({
            name: x.name,
            source: x.result.source,
            proxy: x.proxy,
          })),
          samPromptedAttempted: Boolean(alignedTileMask),
          samPromptedError: samError ?? undefined,
          patchRefine: patchRefineMeta ?? undefined,
        },
      },
    };
  }

  return inferOccluderMask(raw, { ...options, samPrompted: false });
}

export function getOccluderMethod(): OccluderMethod {
  const backend = normalizeBackend(process.env.OCCLUDER_BACKEND ?? process.env.OCCLUDER_PRESET);
  if (backend === "rfdet_m3" && !process.env.OCCLUDER_METHOD) {
    return "distilled_unsup";
  }
  return resolveMethod(process.env.OCCLUDER_METHOD) ?? DEFAULT_METHOD;
}

Youez - 2016 - github.com/yon3zu
LinuXploit