修改色准测试结果显示
This commit is contained in:
188
tools/demo_accuracy_plot.py
Normal file
188
tools/demo_accuracy_plot.py
Normal file
@@ -0,0 +1,188 @@
|
||||
"""离线色准图 Demo。
|
||||
|
||||
运行后会在 tools/demo_outputs/ 下生成一张 PNG,
|
||||
用于在没有 UCD 设备时预览当前色准图表的 Calman 风格布局。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import math
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use("Agg")
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
plt.rcParams["font.family"] = ["sans-serif"]
|
||||
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "DejaVu Sans"]
|
||||
plt.rcParams["axes.unicode_minus"] = False
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from app.plots.plot_accuracy import plot_accuracy
|
||||
from app.tests.color_accuracy import (
|
||||
calculate_delta_e_2000,
|
||||
get_accuracy_color_standards,
|
||||
)
|
||||
|
||||
|
||||
COLOR_NAMES = [
|
||||
"White",
|
||||
"Gray 80",
|
||||
"Gray 65",
|
||||
"Gray 50",
|
||||
"Gray 35",
|
||||
"Dark Skin",
|
||||
"Light Skin",
|
||||
"Blue Sky",
|
||||
"Foliage",
|
||||
"Blue Flower",
|
||||
"Bluish Green",
|
||||
"Orange",
|
||||
"Purplish Blue",
|
||||
"Moderate Red",
|
||||
"Purple",
|
||||
"Yellow Green",
|
||||
"Orange Yellow",
|
||||
"Blue (Legacy)",
|
||||
"Green (Legacy)",
|
||||
"Red (Legacy)",
|
||||
"Yellow (Legacy)",
|
||||
"Magenta (Legacy)",
|
||||
"Cyan (Legacy)",
|
||||
"100% Red",
|
||||
"100% Green",
|
||||
"100% Blue",
|
||||
"100% Cyan",
|
||||
"100% Magenta",
|
||||
"100% Yellow",
|
||||
]
|
||||
|
||||
|
||||
class _DummyNotebook:
|
||||
def select(self, *_args, **_kwargs):
|
||||
return None
|
||||
|
||||
|
||||
class _DummyCanvas:
|
||||
def draw(self):
|
||||
return None
|
||||
|
||||
|
||||
class _DemoApp:
|
||||
def __init__(self, fig):
|
||||
self.accuracy_fig = fig
|
||||
self.accuracy_canvas = _DummyCanvas()
|
||||
self.chart_notebook = _DummyNotebook()
|
||||
self.accuracy_chart_frame = object()
|
||||
|
||||
def get_test_type_name(self, test_type):
|
||||
mapping = {
|
||||
"sdr_movie": "SDR Movie",
|
||||
"hdr_movie": "HDR Movie",
|
||||
"screen_module": "屏模组",
|
||||
}
|
||||
return mapping.get(test_type, str(test_type))
|
||||
|
||||
|
||||
def _build_demo_data(test_type: str = "sdr_movie"):
|
||||
standards = get_accuracy_color_standards(test_type)
|
||||
rng = np.random.default_rng(20260527)
|
||||
|
||||
measured = []
|
||||
color_patches = []
|
||||
delta_e_values = []
|
||||
|
||||
for idx, name in enumerate(COLOR_NAMES):
|
||||
sx, sy = standards[name]
|
||||
|
||||
# 构造一些“看起来像真实测量”的偏移:
|
||||
# 大部分点轻微偏移,少数点更明显,便于看出方向和等级差异。
|
||||
if idx < 5:
|
||||
offset_scale = 0.0012
|
||||
elif idx < 23:
|
||||
offset_scale = 0.0028
|
||||
else:
|
||||
offset_scale = 0.0045
|
||||
|
||||
angle = rng.uniform(0, 2 * math.pi)
|
||||
radius = offset_scale * (0.55 + 0.85 * rng.random())
|
||||
dx = math.cos(angle) * radius
|
||||
dy = math.sin(angle) * radius
|
||||
|
||||
# 为了让图上连线不完全随机,给部分饱和色再加一点定向偏移。
|
||||
if idx >= 23:
|
||||
dx += 0.002 * (1 if idx % 2 == 0 else -1)
|
||||
dy += 0.0015 * (1 if idx % 3 == 0 else -1)
|
||||
|
||||
mx = min(max(sx + dx, 0.0), 0.8)
|
||||
my = min(max(sy + dy, 0.0), 0.9)
|
||||
|
||||
# 亮度也做一点微小变化,避免所有点完全同一层。
|
||||
measured_lv = 70.0 + rng.normal(0, 4.0)
|
||||
measured_lv = max(measured_lv, 1.0)
|
||||
|
||||
delta_e = calculate_delta_e_2000(mx, my, measured_lv, sx, sy)
|
||||
|
||||
measured.append((mx, my, measured_lv))
|
||||
color_patches.append(name)
|
||||
delta_e_values.append(delta_e)
|
||||
|
||||
avg_delta_e = float(np.mean(delta_e_values))
|
||||
max_delta_e = float(np.max(delta_e_values))
|
||||
min_delta_e = float(np.min(delta_e_values))
|
||||
|
||||
return {
|
||||
"color_patches": color_patches,
|
||||
"delta_e_values": delta_e_values,
|
||||
"color_measurements": measured,
|
||||
"avg_delta_e": avg_delta_e,
|
||||
"max_delta_e": max_delta_e,
|
||||
"min_delta_e": min_delta_e,
|
||||
"excellent_count": sum(1 for value in delta_e_values if value < 3),
|
||||
"good_count": sum(1 for value in delta_e_values if 3 <= value < 5),
|
||||
"poor_count": sum(1 for value in delta_e_values if value >= 5),
|
||||
"avg_delta_e_gray": float(np.mean(delta_e_values[0:5])),
|
||||
"avg_delta_e_colorchecker": float(np.mean(delta_e_values[5:23])),
|
||||
"avg_delta_e_saturated": float(np.mean(delta_e_values[23:29])),
|
||||
"target_gamma": 2.2,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate an offline color accuracy demo PNG.")
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=Path,
|
||||
default=Path(__file__).resolve().parent / "demo_outputs" / "accuracy_demo.png",
|
||||
help="Output PNG path.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--test-type",
|
||||
choices=["sdr_movie", "hdr_movie", "screen_module"],
|
||||
default="sdr_movie",
|
||||
help="Test type used for the title and standard color set.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
fig = plt.Figure(figsize=(14, 8), dpi=120, tight_layout=False)
|
||||
app = _DemoApp(fig)
|
||||
accuracy_data = _build_demo_data(args.test_type)
|
||||
|
||||
plot_accuracy(app, accuracy_data, args.test_type)
|
||||
fig.savefig(args.output, dpi=220)
|
||||
|
||||
print(f"Saved demo image to: {args.output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
BIN
tools/demo_outputs/accuracy_demo.png
Normal file
BIN
tools/demo_outputs/accuracy_demo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 545 KiB |
Reference in New Issue
Block a user