Add AOI hotspot strict audit for 20nm compare

This commit is contained in:
OpenAI Codex
2026-03-31 21:21:21 +08:00
parent e15c38398a
commit 2e6bdd40fd
22 changed files with 489 additions and 50 deletions

View File

@@ -115,12 +115,18 @@ When changing the primary compare page:
For the current 20nm visual baseline, prefer: For the current 20nm visual baseline, prefer:
- [`navsea_strict_audit.py`](/root/sourceserver/pbf/navsea_strict_audit.py) - [`navsea_strict_audit.py`](/root/sourceserver/pbf/navsea_strict_audit.py)
- [`strict_audit_hotspots_20nm.json`](/root/sourceserver/pbf/strict_audit_hotspots_20nm.json)
This script combines: This script combines:
- browser-rendered screenshot diff from the fixed compare page - browser-rendered screenshot diff from the fixed compare page
- backend render audit summary from the current 20nm audit JSON - backend render audit summary from the current 20nm audit JSON
And now focuses on:
- small AOI hotspot crops that are chosen to calibrate backend audit blind spots
- not just one coarse full-screen diff number
Use it when you need one report that explains both: Use it when you need one report that explains both:
- what the user really sees - what the user really sees

View File

@@ -334,12 +334,23 @@ Remote: `ssh://git@nas:2222/tei/pbf.git`
本轮已新增统一审计脚本: 本轮已新增统一审计脚本:
- [`navsea_strict_audit.py`](/root/sourceserver/pbf/navsea_strict_audit.py) - [`navsea_strict_audit.py`](/root/sourceserver/pbf/navsea_strict_audit.py)
- [`strict_audit_hotspots_20nm.json`](/root/sourceserver/pbf/strict_audit_hotspots_20nm.json)
它会把两部分合并到同一份报告里: 它会把两部分合并到同一份报告里:
- 浏览器真实出图截图差异 - 浏览器真实出图截图差异
- 当前 20nm backend render audit 摘要 - 当前 20nm backend render audit 摘要
但当前实际工作方式已经进一步收紧为:
- 后台 render audit 是主审计
- 小范围 AOI 图像审计是校准审计
- 不再只看整屏大 diff
- 只盯后台最容易误判的热点区域:
- 航标 / 灯塔 / 红绿标识
- 鱼礁 / 碍航点
- 远处 symbol / 小灯
当前产物: 当前产物:
- [strict_audit_summary.md](/root/sourceserver/pbf/report/strict_audit/strict_audit_summary.md) - [strict_audit_summary.md](/root/sourceserver/pbf/report/strict_audit/strict_audit_summary.md)
@@ -348,25 +359,36 @@ Remote: `ssh://git@nas:2222/tei/pbf.git`
- [compare_left.png](/root/sourceserver/pbf/report/strict_audit/compare_left.png) - [compare_left.png](/root/sourceserver/pbf/report/strict_audit/compare_left.png)
- [compare_right.png](/root/sourceserver/pbf/report/strict_audit/compare_right.png) - [compare_right.png](/root/sourceserver/pbf/report/strict_audit/compare_right.png)
- [compare_diff.png](/root/sourceserver/pbf/report/strict_audit/compare_diff.png) - [compare_diff.png](/root/sourceserver/pbf/report/strict_audit/compare_diff.png)
- [report/strict_audit/hotspots](/root/sourceserver/pbf/report/strict_audit/hotspots)
当前 `r7` strict audit 结论: 当前 `r7` strict audit 结论:
- compare version: - compare version:
- `20nm-r7-20260331-2044` - `20nm-r7-20260331-2044`
- visual changed ratio: - visual changed ratio:
- `0.887847` - `0.899848`
- changed pixels: - changed pixels:
- `411961 / 464000` - `230361 / 256000`
- backend render audit 总体仍是: - backend render audit 总体仍是:
- `extra_in_engineering = 258317` - `extra_in_engineering = 258317`
- `missing_in_engineering = 258317` - `missing_in_engineering = 258317`
当前热点 AOI 排名:
1. `southwest_lighthouse_cluster`
- changed ratio: `0.972315`
2. `takashima_main_harbor_marks`
- changed ratio: `0.783759`
3. `takashima_inner_nearshore_hazards`
- changed ratio: `0.744246`
4. `east_breakwater_marks`
- changed ratio: `0.617833`
这份统一审计的意义是: 这份统一审计的意义是:
- 以后不再把“视觉变好了”与“后台数字没变”当成互相冲突 - 以后不再只靠整屏图像差异判断问题
- 可以一眼看出: - 可以用少量热点小框去校准后台 render audit 的盲区
- 浏览器真实出图变没变 - 当用户肉眼说“这里还不对”时,可以直接把那个区域加入热点审计并复跑
- 后台 render audit 有没有跟上
线上已同步: 线上已同步:
@@ -701,21 +723,26 @@ Style 语义专项里仍最重要的是:
下次继续时,建议按这个顺序推进: 下次继续时,建议按这个顺序推进:
- 先以固定页面 - 固定只用:
- `http://192.168.200.184/newpec/domain/navsea-compare-legacy-domain-compatible.html` - `http://192.168.200.184/newpec/navsea-compare-karatsu-20nm.html`
作为唯一视觉基线 作为唯一视觉基线
- 以 [`src/Domain/style.domain-legacy-compatible-karatsu-10nm.deployed-2026-03-31.json`](/root/sourceserver/pbf/src/Domain/style.domain-legacy-compatible-karatsu-10nm.deployed-2026-03-31.json) - 固定只用:
作为“最接近旧版”的右侧样式母版 - `/home/wwwroot/pbf-delivery-karatsu-20nm`
- 在 Domain compatible 线上逐层确认: 作为当前 delivery PBF
- 哪些 layer 仍依赖 legacy 日文字段 - 先围绕 strict audit 热点逐组修:
- 哪些可以直接切到标准字段而不改变视觉 - `southwest_lighthouse_cluster`
- 哪些需要加兼容映射才能保持视觉不变 - `takashima_main_harbor_marks`
- `takashima_inner_nearshore_hazards`
- `east_breakwater_marks`
- 每修一轮就重跑:
- [`navsea_strict_audit.py`](/root/sourceserver/pbf/navsea_strict_audit.py)
- 目的不是追求整屏 diff 立刻变小,而是让后台 render audit 对热点问题的判断逐步和肉眼一致
当前真正的下一步不再是继续调 `20nm compare` 页面,而是: 当前真正的下一步是:
- deployed baseline style 中对 legacy 字段的依赖系统列出来 -用户指出的新问题优先落进热点 AOI
- 以固定 compare 页面做逐步替换验证 - 用热点截图和点击拾取结果对照右侧实际图层与属性
- 每次替换后只在这一个页面上检查视觉回归 - 再决定是继续修 [`style.navsea-delivery-karatsu-10nm.json`](/root/sourceserver/pbf/src/pbf/style.navsea-delivery-karatsu-10nm.json),还是回到 builder 补更细的 delivery 语义字段
## Important Notes ## Important Notes
@@ -729,4 +756,4 @@ Style 语义专项里仍最重要的是:
下次开机如果要快速接上,可以先看这份文件,再按下面这句继续: 下次开机如果要快速接上,可以先看这份文件,再按下面这句继续:
`继续处理 STEP_RECORD.md 里记录的固定 compare 基线,围绕 navsea-compare-legacy-domain-compatible.html 这一个页面,在 pbf-domain-karatsu-10nm 线上逐步去掉日文字段依赖,同时保持视觉尽量不变。` `继续处理 STEP_RECORD.md 里记录的 20nm 固定 compare 基线,围绕 navsea-compare-karatsu-20nm.html 这一个页面 pbf-delivery-karatsu-20nm 这套 PBF按 strict audit 的热点 AOI 逐组修视觉问题,并用小范围图像审计去校准后台 render audit。`

View File

@@ -5,7 +5,6 @@ import argparse
import json import json
import re import re
import subprocess import subprocess
import tempfile
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
@@ -19,6 +18,7 @@ DEFAULT_BACKEND_AUDIT_JSON = Path(
"/root/sourceserver/pbf/NavSea_Original_vs_Delivery_Render_Audit_Karatsu_20nm_2026-03-31.r7.json" "/root/sourceserver/pbf/NavSea_Original_vs_Delivery_Render_Audit_Karatsu_20nm_2026-03-31.r7.json"
) )
DEFAULT_OUTPUT_DIR = Path("/root/sourceserver/pbf/report/strict_audit") DEFAULT_OUTPUT_DIR = Path("/root/sourceserver/pbf/report/strict_audit")
DEFAULT_HOTSPOTS_PATH = Path("/root/sourceserver/pbf/strict_audit_hotspots_20nm.json")
@dataclass @dataclass
@@ -32,6 +32,15 @@ class CropBox:
return (self.left, self.top, self.right, self.bottom) return (self.left, self.top, self.right, self.bottom)
@dataclass(frozen=True)
class HotspotSpec:
id: str
label: str
notes: str
pane_box_norm: tuple[float, float, float, float]
backend_focus: tuple[str, ...]
def parse_args() -> argparse.Namespace: def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Run strict audit by combining browser-rendered visual diff with backend render audit summary." description="Run strict audit by combining browser-rendered visual diff with backend render audit summary."
@@ -39,11 +48,12 @@ def parse_args() -> argparse.Namespace:
parser.add_argument("--compare-url", default=DEFAULT_COMPARE_URL) parser.add_argument("--compare-url", default=DEFAULT_COMPARE_URL)
parser.add_argument("--backend-audit-json", type=Path, default=DEFAULT_BACKEND_AUDIT_JSON) parser.add_argument("--backend-audit-json", type=Path, default=DEFAULT_BACKEND_AUDIT_JSON)
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR) parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR)
parser.add_argument("--width", type=int, default=1600) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=900) parser.add_argument("--height", type=int, default=720)
parser.add_argument("--toolbar-height", type=int, default=150) parser.add_argument("--toolbar-height", type=int, default=150)
parser.add_argument("--bottom-trim", type=int, default=170) parser.add_argument("--bottom-trim", type=int, default=170)
parser.add_argument("--timeout-sec", type=int, default=90) parser.add_argument("--timeout-sec", type=int, default=120)
parser.add_argument("--hotspots-json", type=Path, default=DEFAULT_HOTSPOTS_PATH)
return parser.parse_args() return parser.parse_args()
@@ -65,7 +75,7 @@ def run_browser_screenshot(compare_url: str, output_png: Path, width: int, heigh
"--disable-gpu", "--disable-gpu",
"--enable-unsafe-swiftshader", "--enable-unsafe-swiftshader",
"--no-sandbox", "--no-sandbox",
"--virtual-time-budget=20000", "--virtual-time-budget=15000",
f"--window-size={width},{height}", f"--window-size={width},{height}",
f"--screenshot={output_png}", f"--screenshot={output_png}",
compare_url, compare_url,
@@ -82,6 +92,30 @@ def build_crop_boxes(image_width: int, image_height: int, toolbar_height: int, b
return left_box, right_box return left_box, right_box
def load_hotspots(hotspots_json: Path) -> list[HotspotSpec]:
raw = json.loads(hotspots_json.read_text())
hotspots: list[HotspotSpec] = []
for item in raw:
hotspots.append(
HotspotSpec(
id=item["id"],
label=item["label"],
notes=item.get("notes", ""),
pane_box_norm=tuple(item["pane_box_norm"]),
backend_focus=tuple(item.get("backend_focus", [])),
)
)
return hotspots
def normalized_box_to_pixels(box_norm: tuple[float, float, float, float], pane_width: int, pane_height: int) -> CropBox:
left = max(0, min(pane_width, round(box_norm[0] * pane_width)))
top = max(0, min(pane_height, round(box_norm[1] * pane_height)))
right = max(left + 1, min(pane_width, round(box_norm[2] * pane_width)))
bottom = max(top + 1, min(pane_height, round(box_norm[3] * pane_height)))
return CropBox(left, top, right, bottom)
def compute_visual_metrics(left_img: Image.Image, right_img: Image.Image) -> dict[str, Any]: def compute_visual_metrics(left_img: Image.Image, right_img: Image.Image) -> dict[str, Any]:
if left_img.size != right_img.size: if left_img.size != right_img.size:
raise ValueError(f"image sizes differ: {left_img.size} vs {right_img.size}") raise ValueError(f"image sizes differ: {left_img.size} vs {right_img.size}")
@@ -116,7 +150,16 @@ def compute_visual_metrics(left_img: Image.Image, right_img: Image.Image) -> dic
} }
def save_visual_outputs(full_png: Path, left_png: Path, right_png: Path, diff_png: Path, toolbar_height: int, bottom_trim: int) -> dict[str, Any]: def save_visual_outputs(
full_png: Path,
left_png: Path,
right_png: Path,
diff_png: Path,
toolbar_height: int,
bottom_trim: int,
hotspots: list[HotspotSpec],
output_dir: Path,
) -> dict[str, Any]:
image = Image.open(full_png).convert("RGBA") image = Image.open(full_png).convert("RGBA")
left_box, right_box = build_crop_boxes(image.width, image.height, toolbar_height, bottom_trim) left_box, right_box = build_crop_boxes(image.width, image.height, toolbar_height, bottom_trim)
left = image.crop(left_box.as_tuple()) left = image.crop(left_box.as_tuple())
@@ -131,9 +174,49 @@ def save_visual_outputs(full_png: Path, left_png: Path, right_png: Path, diff_pn
metrics["full_crop_left"] = list(left_box.as_tuple()) metrics["full_crop_left"] = list(left_box.as_tuple())
metrics["full_crop_right"] = list(right_box.as_tuple()) metrics["full_crop_right"] = list(right_box.as_tuple())
metrics["hotspots"] = save_hotspot_outputs(left, right, hotspots, output_dir)
return metrics return metrics
def save_hotspot_outputs(
left_img: Image.Image,
right_img: Image.Image,
hotspots: list[HotspotSpec],
output_dir: Path,
) -> list[dict[str, Any]]:
hotspot_dir = output_dir / "hotspots"
hotspot_dir.mkdir(parents=True, exist_ok=True)
results: list[dict[str, Any]] = []
for hotspot in hotspots:
box = normalized_box_to_pixels(hotspot.pane_box_norm, left_img.width, left_img.height)
left_crop = left_img.crop(box.as_tuple())
right_crop = right_img.crop(box.as_tuple())
metrics = compute_visual_metrics(left_crop, right_crop)
diff_img = metrics.pop("diff_image")
diff_boost = diff_img.convert("RGB").point(lambda value: min(255, value * 4))
left_path = hotspot_dir / f"{hotspot.id}_left.png"
right_path = hotspot_dir / f"{hotspot.id}_right.png"
diff_path = hotspot_dir / f"{hotspot.id}_diff.png"
left_crop.save(left_path)
right_crop.save(right_path)
diff_boost.save(diff_path)
metrics["id"] = hotspot.id
metrics["label"] = hotspot.label
metrics["notes"] = hotspot.notes
metrics["backend_focus"] = list(hotspot.backend_focus)
metrics["pane_box_norm"] = list(hotspot.pane_box_norm)
metrics["pane_box_pixels"] = list(box.as_tuple())
metrics["left_image"] = str(left_path)
metrics["right_image"] = str(right_path)
metrics["diff_image"] = str(diff_path)
results.append(metrics)
return sorted(results, key=lambda item: item["changed_ratio"], reverse=True)
def load_backend_summary(report_json_path: Path) -> dict[str, Any]: def load_backend_summary(report_json_path: Path) -> dict[str, Any]:
data = json.loads(report_json_path.read_text()) data = json.loads(report_json_path.read_text())
@@ -200,6 +283,32 @@ def write_reports(
f"- `{output_dir / 'compare_right.png'}`", f"- `{output_dir / 'compare_right.png'}`",
f"- `{output_dir / 'compare_diff.png'}`", f"- `{output_dir / 'compare_diff.png'}`",
"", "",
"## Hotspot AOI Audit",
"",
]
for hotspot in visual_metrics.get("hotspots", []):
lines.extend(
[
f"### {hotspot['label']}",
"",
f"- id: `{hotspot['id']}`",
f"- notes: `{hotspot['notes']}`",
f"- backend focus: `{hotspot['backend_focus']}`",
f"- changed pixels: `{hotspot['changed_pixels']}` / `{hotspot['total_pixels']}`",
f"- changed ratio: `{hotspot['changed_ratio']}`",
f"- mean abs rgb: `{hotspot['mean_abs_rgb']}`",
f"- pane box norm: `{hotspot['pane_box_norm']}`",
f"- pane box pixels: `{hotspot['pane_box_pixels']}`",
f"- left image: `{hotspot['left_image']}`",
f"- right image: `{hotspot['right_image']}`",
f"- diff image: `{hotspot['diff_image']}`",
"",
]
)
lines.extend(
[
"## Backend Render Audit", "## Backend Render Audit",
"", "",
f"- original feature instances: `{backend_summary['original_feature_instances']}`", f"- original feature instances: `{backend_summary['original_feature_instances']}`",
@@ -208,7 +317,8 @@ def write_reports(
"", "",
"Status counts:", "Status counts:",
"", "",
] ]
)
for key, value in backend_summary["status_counts"].items(): for key, value in backend_summary["status_counts"].items():
lines.append(f"- `{key}`: `{value}`") lines.append(f"- `{key}`: `{value}`")
@@ -238,6 +348,7 @@ def main() -> None:
args.output_dir.mkdir(parents=True, exist_ok=True) args.output_dir.mkdir(parents=True, exist_ok=True)
compare_version = fetch_compare_version(args.compare_url) compare_version = fetch_compare_version(args.compare_url)
hotspots = load_hotspots(args.hotspots_json)
full_png = args.output_dir / "compare_full.png" full_png = args.output_dir / "compare_full.png"
left_png = args.output_dir / "compare_left.png" left_png = args.output_dir / "compare_left.png"
right_png = args.output_dir / "compare_right.png" right_png = args.output_dir / "compare_right.png"
@@ -251,6 +362,8 @@ def main() -> None:
diff_png=diff_png, diff_png=diff_png,
toolbar_height=args.toolbar_height, toolbar_height=args.toolbar_height,
bottom_trim=args.bottom_trim, bottom_trim=args.bottom_trim,
hotspots=hotspots,
output_dir=args.output_dir,
) )
backend_summary = load_backend_summary(args.backend_audit_json) backend_summary = load_backend_summary(args.backend_audit_json)
report_md, report_json = write_reports( report_md, report_json = write_reports(
@@ -270,6 +383,13 @@ def main() -> None:
"report_json": str(report_json), "report_json": str(report_json),
"changed_ratio": visual_metrics["changed_ratio"], "changed_ratio": visual_metrics["changed_ratio"],
"changed_pixels": visual_metrics["changed_pixels"], "changed_pixels": visual_metrics["changed_pixels"],
"hotspots": [
{
"id": item["id"],
"changed_ratio": item["changed_ratio"],
}
for item in visual_metrics.get("hotspots", [])
],
}, },
ensure_ascii=False, ensure_ascii=False,
indent=2, indent=2,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 533 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 KiB

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 KiB

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -3,38 +3,222 @@
"compare_version": "20nm-r7-20260331-2044", "compare_version": "20nm-r7-20260331-2044",
"backend_audit_json": "/root/sourceserver/pbf/NavSea_Original_vs_Delivery_Render_Audit_Karatsu_20nm_2026-03-31.r7.json", "backend_audit_json": "/root/sourceserver/pbf/NavSea_Original_vs_Delivery_Render_Audit_Karatsu_20nm_2026-03-31.r7.json",
"visual_metrics": { "visual_metrics": {
"image_width": 800, "image_width": 640,
"image_height": 580, "image_height": 400,
"total_pixels": 464000, "total_pixels": 256000,
"changed_pixels": 411961, "changed_pixels": 230361,
"changed_ratio": 0.887847, "changed_ratio": 0.899848,
"mean_abs_rgb": [ "mean_abs_rgb": [
30.3034, 27.394,
31.6079, 28.0012,
61.2516 51.399
], ],
"rms_rgb": [ "rms_rgb": [
45.7879, 42.1614,
45.5806, 40.8117,
75.4396 66.9404
], ],
"diff_bbox": [ "diff_bbox": [
0, 0,
0, 0,
800, 640,
580 400
], ],
"full_crop_left": [ "full_crop_left": [
0, 0,
150, 150,
800, 640,
730 550
], ],
"full_crop_right": [ "full_crop_right": [
800, 640,
150, 150,
1600, 1280,
730 550
],
"hotspots": [
{
"image_width": 90,
"image_height": 120,
"total_pixels": 10800,
"changed_pixels": 10501,
"changed_ratio": 0.972315,
"mean_abs_rgb": [
35.1766,
36.7016,
83.6827
],
"rms_rgb": [
43.2452,
44.0282,
90.1318
],
"diff_bbox": [
0,
0,
90,
120
],
"id": "southwest_lighthouse_cluster",
"label": "西南灯塔区",
"notes": "左下角远处灯塔与标记点,用来校验远处 symbol 表现。",
"backend_focus": [
"p航路標識群",
"p陸上構造物"
],
"pane_box_norm": [
0.0,
0.7,
0.14,
1.0
],
"pane_box_pixels": [
0,
280,
90,
400
],
"left_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_left.png",
"right_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_right.png",
"diff_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_diff.png"
},
{
"image_width": 147,
"image_height": 80,
"total_pixels": 11760,
"changed_pixels": 9217,
"changed_ratio": 0.783759,
"mean_abs_rgb": [
25.8832,
26.3819,
35.8165
],
"rms_rgb": [
40.7513,
43.6982,
55.4931
],
"diff_bbox": [
0,
0,
147,
80
],
"id": "takashima_main_harbor_marks",
"label": "高岛主港航标区",
"notes": "主港口灯塔、红绿标识、近岸障碍标记。",
"backend_focus": [
"p航路標識群",
"safety_icon_missing",
"text_missing_in_engineering"
],
"pane_box_norm": [
0.34,
0.05,
0.57,
0.25
],
"pane_box_pixels": [
218,
20,
365,
100
],
"left_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_left.png",
"right_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_right.png",
"diff_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_diff.png"
},
{
"image_width": 115,
"image_height": 68,
"total_pixels": 7820,
"changed_pixels": 5820,
"changed_ratio": 0.744246,
"mean_abs_rgb": [
26.0925,
28.3926,
32.3252
],
"rms_rgb": [
40.8552,
45.3891,
51.1523
],
"diff_bbox": [
0,
0,
115,
68
],
"id": "takashima_inner_nearshore_hazards",
"label": "高岛近岸碍航与鱼礁区",
"notes": "近岸鱼礁、碍航点、灯塔与小灯混合区。",
"backend_focus": [
"p投錨注意障害物",
"p航行危険障害物",
"p航路標識群"
],
"pane_box_norm": [
0.44,
0.14,
0.62,
0.31
],
"pane_box_pixels": [
282,
56,
397,
124
],
"left_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_left.png",
"right_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_right.png",
"diff_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_diff.png"
},
{
"image_width": 109,
"image_height": 64,
"total_pixels": 6976,
"changed_pixels": 4310,
"changed_ratio": 0.617833,
"mean_abs_rgb": [
14.5257,
14.9903,
20.7008
],
"rms_rgb": [
30.1275,
32.1947,
39.6306
],
"diff_bbox": [
0,
4,
109,
64
],
"id": "east_breakwater_marks",
"label": "东侧防波堤灯台区",
"notes": "右上沿岸的防波堤灯台与港口标记。",
"backend_focus": [
"p航路標識群",
"safety_icon_missing"
],
"pane_box_norm": [
0.83,
0.0,
1.0,
0.16
],
"pane_box_pixels": [
531,
0,
640,
64
],
"left_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_left.png",
"right_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_right.png",
"diff_image": "/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_diff.png"
}
] ]
}, },
"backend_summary": { "backend_summary": {

View File

@@ -8,12 +8,12 @@
## Visual Audit ## Visual Audit
- changed pixels: `411961` / `464000` - changed pixels: `230361` / `256000`
- changed ratio: `0.887847` - changed ratio: `0.899848`
- mean abs rgb: `[30.3034, 31.6079, 61.2516]` - mean abs rgb: `[27.394, 28.0012, 51.399]`
- rms rgb: `[45.7879, 45.5806, 75.4396]` - rms rgb: `[42.1614, 40.8117, 66.9404]`
- left crop: `[0, 150, 800, 730]` - left crop: `[0, 150, 640, 550]`
- right crop: `[800, 150, 1600, 730]` - right crop: `[640, 150, 1280, 550]`
Artifacts: Artifacts:
@@ -22,6 +22,64 @@ Artifacts:
- `/root/sourceserver/pbf/report/strict_audit/compare_right.png` - `/root/sourceserver/pbf/report/strict_audit/compare_right.png`
- `/root/sourceserver/pbf/report/strict_audit/compare_diff.png` - `/root/sourceserver/pbf/report/strict_audit/compare_diff.png`
## Hotspot AOI Audit
### 西南灯塔区
- id: `southwest_lighthouse_cluster`
- notes: `左下角远处灯塔与标记点,用来校验远处 symbol 表现。`
- backend focus: `['p航路標識群', 'p陸上構造物']`
- changed pixels: `10501` / `10800`
- changed ratio: `0.972315`
- mean abs rgb: `[35.1766, 36.7016, 83.6827]`
- pane box norm: `[0.0, 0.7, 0.14, 1.0]`
- pane box pixels: `[0, 280, 90, 400]`
- left image: `/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_left.png`
- right image: `/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_right.png`
- diff image: `/root/sourceserver/pbf/report/strict_audit/hotspots/southwest_lighthouse_cluster_diff.png`
### 高岛主港航标区
- id: `takashima_main_harbor_marks`
- notes: `主港口灯塔、红绿标识、近岸障碍标记。`
- backend focus: `['p航路標識群', 'safety_icon_missing', 'text_missing_in_engineering']`
- changed pixels: `9217` / `11760`
- changed ratio: `0.783759`
- mean abs rgb: `[25.8832, 26.3819, 35.8165]`
- pane box norm: `[0.34, 0.05, 0.57, 0.25]`
- pane box pixels: `[218, 20, 365, 100]`
- left image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_left.png`
- right image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_right.png`
- diff image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_main_harbor_marks_diff.png`
### 高岛近岸碍航与鱼礁区
- id: `takashima_inner_nearshore_hazards`
- notes: `近岸鱼礁、碍航点、灯塔与小灯混合区。`
- backend focus: `['p投錨注意障害物', 'p航行危険障害物', 'p航路標識群']`
- changed pixels: `5820` / `7820`
- changed ratio: `0.744246`
- mean abs rgb: `[26.0925, 28.3926, 32.3252]`
- pane box norm: `[0.44, 0.14, 0.62, 0.31]`
- pane box pixels: `[282, 56, 397, 124]`
- left image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_left.png`
- right image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_right.png`
- diff image: `/root/sourceserver/pbf/report/strict_audit/hotspots/takashima_inner_nearshore_hazards_diff.png`
### 东侧防波堤灯台区
- id: `east_breakwater_marks`
- notes: `右上沿岸的防波堤灯台与港口标记。`
- backend focus: `['p航路標識群', 'safety_icon_missing']`
- changed pixels: `4310` / `6976`
- changed ratio: `0.617833`
- mean abs rgb: `[14.5257, 14.9903, 20.7008]`
- pane box norm: `[0.83, 0.0, 1.0, 0.16]`
- pane box pixels: `[531, 0, 640, 64]`
- left image: `/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_left.png`
- right image: `/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_right.png`
- diff image: `/root/sourceserver/pbf/report/strict_audit/hotspots/east_breakwater_marks_diff.png`
## Backend Render Audit ## Backend Render Audit
- original feature instances: `258317` - original feature instances: `258317`

View File

@@ -0,0 +1,44 @@
[
{
"id": "takashima_main_harbor_marks",
"label": "高岛主港航标区",
"notes": "主港口灯塔、红绿标识、近岸障碍标记。",
"pane_box_norm": [0.34, 0.05, 0.57, 0.25],
"backend_focus": [
"p航路標識群",
"safety_icon_missing",
"text_missing_in_engineering"
]
},
{
"id": "takashima_inner_nearshore_hazards",
"label": "高岛近岸碍航与鱼礁区",
"notes": "近岸鱼礁、碍航点、灯塔与小灯混合区。",
"pane_box_norm": [0.44, 0.14, 0.62, 0.31],
"backend_focus": [
"p投錨注意障害物",
"p航行危険障害物",
"p航路標識群"
]
},
{
"id": "east_breakwater_marks",
"label": "东侧防波堤灯台区",
"notes": "右上沿岸的防波堤灯台与港口标记。",
"pane_box_norm": [0.83, 0.0, 1.0, 0.16],
"backend_focus": [
"p航路標識群",
"safety_icon_missing"
]
},
{
"id": "southwest_lighthouse_cluster",
"label": "西南灯塔区",
"notes": "左下角远处灯塔与标记点,用来校验远处 symbol 表现。",
"pane_box_norm": [0.0, 0.70, 0.14, 1.0],
"backend_focus": [
"p航路標識群",
"p陸上構造物"
]
}
]