2026-04-20 10:00:44 +08:00
|
|
|
|
"""CCT / 色度一致性绘制。
|
|
|
|
|
|
|
|
|
|
|
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_cct 原样搬迁。
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-20 11:13:57 +08:00
|
|
|
|
def plot_cct(self, test_type):
|
2026-04-20 10:00:44 +08:00
|
|
|
|
"""绘制 x 和 y 坐标分离图 - 每个点标注纵坐标值"""
|
|
|
|
|
|
|
|
|
|
|
|
self.cct_fig.clear()
|
|
|
|
|
|
|
|
|
|
|
|
gray_data = self.results.get_intermediate_data("shared", "gray")
|
|
|
|
|
|
if not gray_data:
|
|
|
|
|
|
gray_data = self.results.get_intermediate_data("cct", "gray")
|
|
|
|
|
|
|
|
|
|
|
|
if not gray_data or len(gray_data) < 2:
|
|
|
|
|
|
self.log_gui.log("⚠️ 无 xy 数据可用")
|
|
|
|
|
|
ax = self.cct_fig.add_subplot(111)
|
|
|
|
|
|
ax.text(
|
|
|
|
|
|
0.5,
|
|
|
|
|
|
0.5,
|
|
|
|
|
|
"无可用数据",
|
|
|
|
|
|
ha="center",
|
|
|
|
|
|
va="center",
|
|
|
|
|
|
fontsize=14,
|
|
|
|
|
|
color="red",
|
|
|
|
|
|
)
|
|
|
|
|
|
ax.axis("off")
|
|
|
|
|
|
self.cct_canvas.draw()
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
x_measured = [data[0] for data in gray_data]
|
|
|
|
|
|
y_measured = [data[1] for data in gray_data]
|
|
|
|
|
|
|
|
|
|
|
|
# 反转数据顺序(从暗到亮)
|
|
|
|
|
|
x_measured = x_measured[::-1]
|
|
|
|
|
|
y_measured = y_measured[::-1]
|
|
|
|
|
|
|
|
|
|
|
|
# 去掉第一个点
|
|
|
|
|
|
x_measured = x_measured[1:]
|
|
|
|
|
|
y_measured = y_measured[1:]
|
|
|
|
|
|
|
|
|
|
|
|
# 重新生成灰阶坐标
|
|
|
|
|
|
total_points = len(gray_data)
|
|
|
|
|
|
grayscale = np.linspace(100 / total_points, 100, len(x_measured))
|
|
|
|
|
|
|
|
|
|
|
|
self.log_gui.log(f"✓ 已移除第一个数据点,当前数据点数: {len(x_measured)}")
|
|
|
|
|
|
self.log_gui.log(f" x范围: {min(x_measured):.6f} - {max(x_measured):.6f}")
|
|
|
|
|
|
self.log_gui.log(f" y范围: {min(y_measured):.6f} - {max(y_measured):.6f}")
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 根据测试类型读取对应参数 ==========
|
|
|
|
|
|
if test_type == "sdr_movie":
|
|
|
|
|
|
try:
|
|
|
|
|
|
x_ideal = float(self.sdr_cct_x_ideal_var.get())
|
|
|
|
|
|
x_tolerance = float(self.sdr_cct_x_tolerance_var.get())
|
|
|
|
|
|
y_ideal = float(self.sdr_cct_y_ideal_var.get())
|
|
|
|
|
|
y_tolerance = float(self.sdr_cct_y_tolerance_var.get())
|
|
|
|
|
|
self.log_gui.log("✓ 使用 SDR 色度参数")
|
|
|
|
|
|
except:
|
|
|
|
|
|
x_ideal = 0.3127
|
|
|
|
|
|
x_tolerance = 0.003
|
|
|
|
|
|
y_ideal = 0.3290
|
|
|
|
|
|
y_tolerance = 0.003
|
|
|
|
|
|
self.log_gui.log("⚠️ SDR 参数读取失败,使用默认值")
|
|
|
|
|
|
elif test_type == "hdr_movie":
|
|
|
|
|
|
try:
|
|
|
|
|
|
x_ideal = float(self.hdr_cct_x_ideal_var.get())
|
|
|
|
|
|
x_tolerance = float(self.hdr_cct_x_tolerance_var.get())
|
|
|
|
|
|
y_ideal = float(self.hdr_cct_y_ideal_var.get())
|
|
|
|
|
|
y_tolerance = float(self.hdr_cct_y_tolerance_var.get())
|
|
|
|
|
|
self.log_gui.log("✓ 使用 HDR 色度参数")
|
|
|
|
|
|
except:
|
|
|
|
|
|
x_ideal = 0.3127
|
|
|
|
|
|
x_tolerance = 0.003
|
|
|
|
|
|
y_ideal = 0.3290
|
|
|
|
|
|
y_tolerance = 0.003
|
|
|
|
|
|
self.log_gui.log("⚠️ HDR 参数读取失败,使用默认值")
|
|
|
|
|
|
else: # screen_module
|
|
|
|
|
|
try:
|
|
|
|
|
|
x_ideal = float(self.cct_x_ideal_var.get())
|
|
|
|
|
|
x_tolerance = float(self.cct_x_tolerance_var.get())
|
|
|
|
|
|
y_ideal = float(self.cct_y_ideal_var.get())
|
|
|
|
|
|
y_tolerance = float(self.cct_y_tolerance_var.get())
|
|
|
|
|
|
self.log_gui.log("✓ 使用屏模组色度参数")
|
|
|
|
|
|
except:
|
|
|
|
|
|
x_ideal = 0.306
|
|
|
|
|
|
x_tolerance = 0.003
|
|
|
|
|
|
y_ideal = 0.318
|
|
|
|
|
|
y_tolerance = 0.003
|
|
|
|
|
|
self.log_gui.log("⚠️ 屏模组参数读取失败,使用默认值")
|
|
|
|
|
|
|
|
|
|
|
|
x_low = x_ideal - x_tolerance
|
|
|
|
|
|
x_high = x_ideal + x_tolerance
|
|
|
|
|
|
y_low = y_ideal - y_tolerance
|
|
|
|
|
|
y_high = y_ideal + y_tolerance
|
|
|
|
|
|
|
|
|
|
|
|
self.log_gui.log(f"✓ 用户设置参数:")
|
|
|
|
|
|
self.log_gui.log(f" x-ideal={x_ideal:.4f}, tolerance={x_tolerance:.4f}")
|
|
|
|
|
|
self.log_gui.log(f" x范围: [{x_low:.4f}, {x_high:.4f}]")
|
|
|
|
|
|
self.log_gui.log(f" y-ideal={y_ideal:.4f}, tolerance={y_tolerance:.4f}")
|
|
|
|
|
|
self.log_gui.log(f" y范围: [{y_low:.4f}, {y_high:.4f}]")
|
|
|
|
|
|
|
|
|
|
|
|
# 为所有测试类型创建子图
|
|
|
|
|
|
ax1 = self.cct_fig.add_subplot(211)
|
|
|
|
|
|
ax2 = self.cct_fig.add_subplot(212)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 上图:x coordinates ==========
|
|
|
|
|
|
ax1.plot(
|
|
|
|
|
|
grayscale,
|
|
|
|
|
|
x_measured,
|
|
|
|
|
|
"b-o",
|
|
|
|
|
|
label="屏本体",
|
|
|
|
|
|
linewidth=2,
|
|
|
|
|
|
markersize=4,
|
|
|
|
|
|
zorder=5,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 为每个点添加数值标注(x 坐标)
|
|
|
|
|
|
for i, (gs, x_val) in enumerate(zip(grayscale, x_measured)):
|
|
|
|
|
|
ax1.annotate(
|
|
|
|
|
|
f"{x_val:.5f}",
|
|
|
|
|
|
xy=(gs, x_val),
|
|
|
|
|
|
xytext=(0, 8),
|
|
|
|
|
|
textcoords="offset points",
|
|
|
|
|
|
ha="center",
|
|
|
|
|
|
va="bottom",
|
|
|
|
|
|
fontsize=7,
|
|
|
|
|
|
color="blue",
|
|
|
|
|
|
bbox=dict(
|
|
|
|
|
|
boxstyle="round,pad=0.2",
|
|
|
|
|
|
facecolor="white",
|
|
|
|
|
|
edgecolor="blue",
|
|
|
|
|
|
alpha=0.8,
|
|
|
|
|
|
linewidth=0.5,
|
|
|
|
|
|
),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 绘制完整的参考线
|
|
|
|
|
|
full_grayscale = np.linspace(0, 100, 100)
|
|
|
|
|
|
ax1.axhline(
|
|
|
|
|
|
y=x_ideal,
|
|
|
|
|
|
color="green",
|
|
|
|
|
|
linestyle="--",
|
|
|
|
|
|
linewidth=1.5,
|
|
|
|
|
|
label=f"x-ideal ({x_ideal:.4f})",
|
|
|
|
|
|
zorder=3,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax1.axhline(
|
|
|
|
|
|
y=x_low,
|
|
|
|
|
|
color="red",
|
|
|
|
|
|
linestyle=":",
|
|
|
|
|
|
linewidth=1,
|
|
|
|
|
|
alpha=0.7,
|
|
|
|
|
|
label=f"x-low ({x_low:.4f})",
|
|
|
|
|
|
zorder=2,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax1.axhline(
|
|
|
|
|
|
y=x_high,
|
|
|
|
|
|
color="red",
|
|
|
|
|
|
linestyle=":",
|
|
|
|
|
|
linewidth=1,
|
|
|
|
|
|
alpha=0.7,
|
|
|
|
|
|
label=f"x-high ({x_high:.4f})",
|
|
|
|
|
|
zorder=2,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax1.fill_between(
|
|
|
|
|
|
full_grayscale, x_low, x_high, alpha=0.15, color="blue", zorder=1
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ax1.set_xlabel("灰阶 (%)", fontsize=9)
|
|
|
|
|
|
ax1.set_ylabel("CIE x", fontsize=9)
|
|
|
|
|
|
ax1.grid(True, linestyle="--", alpha=0.3)
|
|
|
|
|
|
ax1.tick_params(labelsize=8)
|
|
|
|
|
|
ax1.set_xlim(0, 105)
|
|
|
|
|
|
|
|
|
|
|
|
# 纵坐标范围由用户参数控制
|
|
|
|
|
|
x_min_data = min(x_measured)
|
|
|
|
|
|
x_max_data = max(x_measured)
|
|
|
|
|
|
data_range_x = x_max_data - x_min_data
|
|
|
|
|
|
|
|
|
|
|
|
self.log_gui.log(f" x数据波动: {data_range_x:.6f}")
|
|
|
|
|
|
|
|
|
|
|
|
range_span = x_tolerance * 2
|
|
|
|
|
|
margin_ratio = 0.20
|
|
|
|
|
|
extra_margin = range_span * margin_ratio
|
|
|
|
|
|
|
|
|
|
|
|
final_y_min = min(x_min_data, x_low) - extra_margin
|
|
|
|
|
|
final_y_max = max(x_max_data, x_high) + extra_margin
|
|
|
|
|
|
|
|
|
|
|
|
if x_min_data >= x_low and x_max_data <= x_high:
|
|
|
|
|
|
self.log_gui.log(f" x数据在tolerance范围内,使用tolerance范围显示")
|
|
|
|
|
|
final_y_min = x_low - extra_margin
|
|
|
|
|
|
final_y_max = x_high + extra_margin
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.log_gui.log(f" x数据超出tolerance范围,扩展显示范围")
|
|
|
|
|
|
|
|
|
|
|
|
ax1.set_ylim(final_y_min, final_y_max)
|
|
|
|
|
|
self.log_gui.log(
|
|
|
|
|
|
f" x轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 下图:y coordinates ==========
|
|
|
|
|
|
ax2.plot(
|
|
|
|
|
|
grayscale,
|
|
|
|
|
|
y_measured,
|
|
|
|
|
|
"r-o",
|
|
|
|
|
|
label="屏本体",
|
|
|
|
|
|
linewidth=2,
|
|
|
|
|
|
markersize=4,
|
|
|
|
|
|
zorder=5,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 为每个点添加数值标注(y 坐标)
|
|
|
|
|
|
for i, (gs, y_val) in enumerate(zip(grayscale, y_measured)):
|
|
|
|
|
|
ax2.annotate(
|
|
|
|
|
|
f"{y_val:.5f}",
|
|
|
|
|
|
xy=(gs, y_val),
|
|
|
|
|
|
xytext=(0, 8),
|
|
|
|
|
|
textcoords="offset points",
|
|
|
|
|
|
ha="center",
|
|
|
|
|
|
va="bottom",
|
|
|
|
|
|
fontsize=7,
|
|
|
|
|
|
color="red",
|
|
|
|
|
|
bbox=dict(
|
|
|
|
|
|
boxstyle="round,pad=0.2",
|
|
|
|
|
|
facecolor="white",
|
|
|
|
|
|
edgecolor="red",
|
|
|
|
|
|
alpha=0.8,
|
|
|
|
|
|
linewidth=0.5,
|
|
|
|
|
|
),
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ax2.axhline(
|
|
|
|
|
|
y=y_ideal,
|
|
|
|
|
|
color="green",
|
|
|
|
|
|
linestyle="--",
|
|
|
|
|
|
linewidth=1.5,
|
|
|
|
|
|
label=f"y-ideal ({y_ideal:.4f})",
|
|
|
|
|
|
zorder=3,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax2.axhline(
|
|
|
|
|
|
y=y_low,
|
|
|
|
|
|
color="orange",
|
|
|
|
|
|
linestyle=":",
|
|
|
|
|
|
linewidth=1,
|
|
|
|
|
|
alpha=0.7,
|
|
|
|
|
|
label=f"y-low ({y_low:.4f})",
|
|
|
|
|
|
zorder=2,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax2.axhline(
|
|
|
|
|
|
y=y_high,
|
|
|
|
|
|
color="orange",
|
|
|
|
|
|
linestyle=":",
|
|
|
|
|
|
linewidth=1,
|
|
|
|
|
|
alpha=0.7,
|
|
|
|
|
|
label=f"y-high ({y_high:.4f})",
|
|
|
|
|
|
zorder=2,
|
|
|
|
|
|
)
|
|
|
|
|
|
ax2.fill_between(
|
|
|
|
|
|
full_grayscale, y_low, y_high, alpha=0.15, color="orange", zorder=1
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ax2.set_xlabel("灰阶 (%)", fontsize=9)
|
|
|
|
|
|
ax2.set_ylabel("CIE y", fontsize=9)
|
|
|
|
|
|
ax2.grid(True, linestyle="--", alpha=0.3)
|
|
|
|
|
|
ax2.tick_params(labelsize=8)
|
|
|
|
|
|
ax2.set_xlim(0, 105)
|
|
|
|
|
|
|
|
|
|
|
|
# 纵坐标范围由用户参数控制
|
|
|
|
|
|
y_min_data = min(y_measured)
|
|
|
|
|
|
y_max_data = max(y_measured)
|
|
|
|
|
|
data_range_y = y_max_data - y_min_data
|
|
|
|
|
|
|
|
|
|
|
|
self.log_gui.log(f" y数据波动: {data_range_y:.6f}")
|
|
|
|
|
|
|
|
|
|
|
|
range_span = y_tolerance * 2
|
|
|
|
|
|
extra_margin = range_span * margin_ratio
|
|
|
|
|
|
|
|
|
|
|
|
final_y_min = min(y_min_data, y_low) - extra_margin
|
|
|
|
|
|
final_y_max = max(y_max_data, y_high) + extra_margin
|
|
|
|
|
|
|
|
|
|
|
|
if y_min_data >= y_low and y_max_data <= y_high:
|
|
|
|
|
|
self.log_gui.log(f" y数据在tolerance范围内,使用tolerance范围显示")
|
|
|
|
|
|
final_y_min = y_low - extra_margin
|
|
|
|
|
|
final_y_max = y_high + extra_margin
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.log_gui.log(f" y数据超出tolerance范围,扩展显示范围")
|
|
|
|
|
|
|
|
|
|
|
|
ax2.set_ylim(final_y_min, final_y_max)
|
|
|
|
|
|
self.log_gui.log(
|
|
|
|
|
|
f" y轴显示范围: {final_y_min:.6f} - {final_y_max:.6f} (跨度: {final_y_max - final_y_min:.6f})"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 总标题 - 统一格式(去掉统计信息)==========
|
|
|
|
|
|
test_type_name = self.get_test_type_name(test_type)
|
|
|
|
|
|
|
|
|
|
|
|
self.cct_fig.suptitle(
|
|
|
|
|
|
f"{test_type_name} - 色度一致性测试",
|
|
|
|
|
|
fontsize=12,
|
|
|
|
|
|
y=0.98,
|
|
|
|
|
|
fontweight="bold",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
self.cct_fig.subplots_adjust(
|
|
|
|
|
|
left=0.12,
|
|
|
|
|
|
right=0.82,
|
|
|
|
|
|
top=0.92,
|
|
|
|
|
|
bottom=0.08,
|
|
|
|
|
|
hspace=0.30,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ax1.legend(
|
|
|
|
|
|
fontsize=7, loc="center left", bbox_to_anchor=(1.05, 0.5), framealpha=1.0
|
|
|
|
|
|
)
|
|
|
|
|
|
ax2.legend(
|
|
|
|
|
|
fontsize=7, loc="center left", bbox_to_anchor=(1.05, 0.5), framealpha=1.0
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
self.cct_canvas.draw()
|
2026-04-20 10:16:31 +08:00
|
|
|
|
self.chart_notebook.select(self.cct_chart_frame)
|
2026-04-20 10:00:44 +08:00
|
|
|
|
|
|
|
|
|
|
self.log_gui.log("✓ xy 色度坐标图绘制完成")
|