540 lines
18 KiB
Python
540 lines
18 KiB
Python
|
|
"""色域图(Gamut)绘制。
|
|||
|
|
|
|||
|
|
Step 2 重构:从 pqAutomationApp.PQAutomationApp.plot_gamut 整体搬迁,
|
|||
|
|
实现与原方法完全一致;原方法仅保留为一行转发。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import matplotlib.image as mpimg
|
|||
|
|
|
|||
|
|
import algorithm.pq_algorithm as pq_algorithm
|
|||
|
|
from app.resources import get_resource_path
|
|||
|
|
|
|||
|
|
|
|||
|
|
def plot_gamut(app, results, coverage, test_type):
|
|||
|
|
"""绘制色域图 - 根据用户选择的参考标准动态计算覆盖率"""
|
|||
|
|
# 实现从原 PQAutomationApp 方法体原样搬迁,为减少修改面
|
|||
|
|
# 范围、保持行为一致,给 self 赋值为传入的 app 实例。
|
|||
|
|
self = app
|
|||
|
|
|
|||
|
|
self.gamut_ax_xy.clear()
|
|||
|
|
self.gamut_ax_uv.clear()
|
|||
|
|
|
|||
|
|
# ==================== XY 图校准参数 ====================
|
|||
|
|
XY_ORIGIN_X = 20.55
|
|||
|
|
XY_ORIGIN_Y = 378.00
|
|||
|
|
XY_PIXELS_PER_X = 510.6818
|
|||
|
|
XY_PIXELS_PER_Y = 429.8844
|
|||
|
|
|
|||
|
|
# ==================== UV 图校准参数 ====================
|
|||
|
|
UV_ORIGIN_U = 26.91
|
|||
|
|
UV_ORIGIN_V = 377.16
|
|||
|
|
UV_PIXELS_PER_U = 615.7260
|
|||
|
|
UV_PIXELS_PER_V = 599.8432
|
|||
|
|
|
|||
|
|
# ========== ✅ 读取用户选择的参考标准 ==========
|
|||
|
|
if test_type == "screen_module":
|
|||
|
|
current_ref = self.screen_gamut_ref_var.get()
|
|||
|
|
elif test_type == "sdr_movie":
|
|||
|
|
current_ref = self.sdr_gamut_ref_var.get()
|
|||
|
|
elif test_type == "hdr_movie":
|
|||
|
|
current_ref = self.hdr_gamut_ref_var.get()
|
|||
|
|
else:
|
|||
|
|
current_ref = "DCI-P3"
|
|||
|
|
|
|||
|
|
# ========== ✅✅✅ 根据参考标准重新计算覆盖率(XY 空间)==========
|
|||
|
|
xy_coverage = coverage # 默认使用传入的值
|
|||
|
|
uv_coverage = 0.0
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 提取前 3 个 RGB 点的 xy 坐标
|
|||
|
|
if len(results) >= 3:
|
|||
|
|
xy_points = [[result[0], result[1]] for result in results[:3]]
|
|||
|
|
|
|||
|
|
# 根据参考标准计算 XY 覆盖率
|
|||
|
|
if current_ref == "BT.2020":
|
|||
|
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_BT2020(
|
|||
|
|
xy_points
|
|||
|
|
)
|
|||
|
|
elif current_ref == "BT.709":
|
|||
|
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_BT709(
|
|||
|
|
xy_points
|
|||
|
|
)
|
|||
|
|
elif current_ref == "DCI-P3":
|
|||
|
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_DCIP3(
|
|||
|
|
xy_points
|
|||
|
|
)
|
|||
|
|
elif current_ref == "BT.601":
|
|||
|
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_BT601(
|
|||
|
|
xy_points
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
self.log_gui.log(f"⚠️ 未知参考标准 '{current_ref}',使用 DCI-P3")
|
|||
|
|
_, xy_coverage = pq_algorithm.calculate_gamut_coverage_DCIP3(
|
|||
|
|
xy_points
|
|||
|
|
)
|
|||
|
|
current_ref = "DCI-P3"
|
|||
|
|
|
|||
|
|
self.log_gui.log(
|
|||
|
|
f"✓ XY 空间覆盖率({current_ref}): {xy_coverage:.1f}%"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.log_gui.log(f"⚠️ 重新计算 XY 覆盖率失败: {str(e)}")
|
|||
|
|
xy_coverage = coverage # 回退到传入值
|
|||
|
|
# =================================================
|
|||
|
|
|
|||
|
|
# ========== 左图:CIE 1931 xy ==========
|
|||
|
|
try:
|
|||
|
|
img_xy = mpimg.imread(get_resource_path("assets/cie.png"))
|
|||
|
|
h_xy, w_xy = img_xy.shape[:2]
|
|||
|
|
|
|||
|
|
self.log_gui.log(f"加载 XY 色域图: {w_xy}x{h_xy}")
|
|||
|
|
|
|||
|
|
self.gamut_ax_xy.imshow(img_xy, extent=[0, w_xy, h_xy, 0], aspect="equal")
|
|||
|
|
self.gamut_ax_xy.set_xlim(0, w_xy)
|
|||
|
|
self.gamut_ax_xy.set_ylim(h_xy, 0)
|
|||
|
|
self.gamut_ax_xy.axis("off")
|
|||
|
|
self.gamut_ax_xy.set_clip_on(False)
|
|||
|
|
|
|||
|
|
def cie_xy_to_pixel(x, y):
|
|||
|
|
"""CIE xy → 像素坐标"""
|
|||
|
|
px = XY_ORIGIN_X + x * XY_PIXELS_PER_X
|
|||
|
|
py = XY_ORIGIN_Y - y * XY_PIXELS_PER_Y
|
|||
|
|
return px, py
|
|||
|
|
|
|||
|
|
if len(results) >= 3:
|
|||
|
|
red_x, red_y = results[0][0], results[0][1]
|
|||
|
|
green_x, green_y = results[1][0], results[1][1]
|
|||
|
|
blue_x, blue_y = results[2][0], results[2][1]
|
|||
|
|
|
|||
|
|
self.log_gui.log(
|
|||
|
|
f"测量色域: R({red_x:.4f},{red_y:.4f}) "
|
|||
|
|
f"G({green_x:.4f},{green_y:.4f}) B({blue_x:.4f},{blue_y:.4f})"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== 绘制测量三角形 ==========
|
|||
|
|
points = [
|
|||
|
|
cie_xy_to_pixel(red_x, red_y),
|
|||
|
|
cie_xy_to_pixel(green_x, green_y),
|
|||
|
|
cie_xy_to_pixel(blue_x, blue_y),
|
|||
|
|
cie_xy_to_pixel(red_x, red_y),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
xs = [p[0] for p in points]
|
|||
|
|
ys = [p[1] for p in points]
|
|||
|
|
|
|||
|
|
self.gamut_ax_xy.plot(
|
|||
|
|
xs,
|
|||
|
|
ys,
|
|||
|
|
color="red",
|
|||
|
|
linewidth=2.5,
|
|||
|
|
marker="o",
|
|||
|
|
markersize=10,
|
|||
|
|
markerfacecolor="red",
|
|||
|
|
markeredgecolor="white",
|
|||
|
|
markeredgewidth=2,
|
|||
|
|
label="测量色域",
|
|||
|
|
zorder=10,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== 标注 RGB 点 ==========
|
|||
|
|
labels = ["R", "G", "B"]
|
|||
|
|
coords = [(red_x, red_y), (green_x, green_y), (blue_x, blue_y)]
|
|||
|
|
|
|||
|
|
for (x_cie, y_cie), label in zip(coords, labels):
|
|||
|
|
px, py = cie_xy_to_pixel(x_cie, y_cie)
|
|||
|
|
|
|||
|
|
# 自适应偏移
|
|||
|
|
if label == "R":
|
|||
|
|
offset = (-60, -40) if x_cie > 0.6 else (0, -60)
|
|||
|
|
elif label == "G":
|
|||
|
|
offset = (0, -60)
|
|||
|
|
else: # B
|
|||
|
|
offset = (60, 40)
|
|||
|
|
|
|||
|
|
self.gamut_ax_xy.annotate(
|
|||
|
|
f"{label}\n({x_cie:.3f},{y_cie:.3f})",
|
|||
|
|
xy=(px, py),
|
|||
|
|
xytext=offset,
|
|||
|
|
textcoords="offset points",
|
|||
|
|
fontsize=9,
|
|||
|
|
color="white",
|
|||
|
|
fontweight="bold",
|
|||
|
|
bbox=dict(
|
|||
|
|
boxstyle="round,pad=0.5",
|
|||
|
|
facecolor="red",
|
|||
|
|
alpha=0.9,
|
|||
|
|
edgecolor="white",
|
|||
|
|
linewidth=2,
|
|||
|
|
),
|
|||
|
|
arrowprops=dict(arrowstyle="->", color="red", lw=2),
|
|||
|
|
zorder=11,
|
|||
|
|
clip_on=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== 绘制所有参考标准 ==========
|
|||
|
|
# DCI-P3
|
|||
|
|
dcip3 = [
|
|||
|
|
(0.6800, 0.3200),
|
|||
|
|
(0.2650, 0.6900),
|
|||
|
|
(0.1500, 0.0600),
|
|||
|
|
(0.6800, 0.3200),
|
|||
|
|
]
|
|||
|
|
dcip3_px = [cie_xy_to_pixel(x, y) for x, y in dcip3]
|
|||
|
|
self.gamut_ax_xy.plot(
|
|||
|
|
[p[0] for p in dcip3_px],
|
|||
|
|
[p[1] for p in dcip3_px],
|
|||
|
|
color="blue",
|
|||
|
|
linewidth=1.5,
|
|||
|
|
linestyle="--",
|
|||
|
|
marker="s",
|
|||
|
|
markersize=6,
|
|||
|
|
alpha=0.7,
|
|||
|
|
label="DCI-P3",
|
|||
|
|
zorder=5,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# BT.2020
|
|||
|
|
bt2020 = [
|
|||
|
|
(0.7080, 0.2920),
|
|||
|
|
(0.1700, 0.7970),
|
|||
|
|
(0.1310, 0.0460),
|
|||
|
|
(0.7080, 0.2920),
|
|||
|
|
]
|
|||
|
|
bt2020_px = [cie_xy_to_pixel(x, y) for x, y in bt2020]
|
|||
|
|
self.gamut_ax_xy.plot(
|
|||
|
|
[p[0] for p in bt2020_px],
|
|||
|
|
[p[1] for p in bt2020_px],
|
|||
|
|
color="green",
|
|||
|
|
linewidth=1.5,
|
|||
|
|
linestyle="-.",
|
|||
|
|
marker="D",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.7,
|
|||
|
|
label="BT.2020",
|
|||
|
|
zorder=4,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# BT.709
|
|||
|
|
bt709 = [
|
|||
|
|
(0.6400, 0.3300),
|
|||
|
|
(0.3000, 0.6000),
|
|||
|
|
(0.1500, 0.0600),
|
|||
|
|
(0.6400, 0.3300),
|
|||
|
|
]
|
|||
|
|
bt709_px = [cie_xy_to_pixel(x, y) for x, y in bt709]
|
|||
|
|
self.gamut_ax_xy.plot(
|
|||
|
|
[p[0] for p in bt709_px],
|
|||
|
|
[p[1] for p in bt709_px],
|
|||
|
|
color="gray",
|
|||
|
|
linewidth=1.2,
|
|||
|
|
linestyle=":",
|
|||
|
|
marker="^",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.6,
|
|||
|
|
label="BT.709",
|
|||
|
|
zorder=3,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# BT.601(仅 SDR 测试)
|
|||
|
|
if test_type == "sdr_movie":
|
|||
|
|
bt601 = [
|
|||
|
|
(0.6300, 0.3400),
|
|||
|
|
(0.3100, 0.5950),
|
|||
|
|
(0.1550, 0.0700),
|
|||
|
|
(0.6300, 0.3400),
|
|||
|
|
]
|
|||
|
|
bt601_px = [cie_xy_to_pixel(x, y) for x, y in bt601]
|
|||
|
|
self.gamut_ax_xy.plot(
|
|||
|
|
[p[0] for p in bt601_px],
|
|||
|
|
[p[1] for p in bt601_px],
|
|||
|
|
color="purple",
|
|||
|
|
linewidth=1.2,
|
|||
|
|
linestyle="-",
|
|||
|
|
marker="o",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.6,
|
|||
|
|
label="BT.601",
|
|||
|
|
zorder=3,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== ✅ XY 覆盖率标注(使用重新计算的值)==========
|
|||
|
|
self.gamut_ax_xy.text(
|
|||
|
|
w_xy * 0.85,
|
|||
|
|
h_xy * 0.92,
|
|||
|
|
f"参考: {current_ref}\n覆盖率: {xy_coverage:.1f}%",
|
|||
|
|
ha="right",
|
|||
|
|
va="bottom",
|
|||
|
|
fontsize=11,
|
|||
|
|
fontweight="bold",
|
|||
|
|
color="red",
|
|||
|
|
bbox=dict(
|
|||
|
|
boxstyle="round,pad=0.5",
|
|||
|
|
facecolor="white",
|
|||
|
|
alpha=0.95,
|
|||
|
|
edgecolor="red",
|
|||
|
|
linewidth=2,
|
|||
|
|
),
|
|||
|
|
zorder=12,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 图例
|
|||
|
|
self.gamut_ax_xy.legend(
|
|||
|
|
loc="upper right",
|
|||
|
|
fontsize=7,
|
|||
|
|
framealpha=0.95,
|
|||
|
|
edgecolor="black",
|
|||
|
|
fancybox=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.log_gui.log(f"XY 图绘制失败: {str(e)}")
|
|||
|
|
import traceback
|
|||
|
|
|
|||
|
|
self.log_gui.log(traceback.format_exc())
|
|||
|
|
|
|||
|
|
# ========== 右图:CIE 1976 u'v' ==========
|
|||
|
|
try:
|
|||
|
|
img_uv = mpimg.imread(get_resource_path("assets/cie_uv.png"))
|
|||
|
|
h_uv, w_uv = img_uv.shape[:2]
|
|||
|
|
|
|||
|
|
self.log_gui.log(f"加载 UV 色域图: {w_uv}x{h_uv}")
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.imshow(img_uv, extent=[0, w_uv, h_uv, 0], aspect="equal")
|
|||
|
|
self.gamut_ax_uv.set_xlim(0, w_uv)
|
|||
|
|
self.gamut_ax_uv.set_ylim(h_uv, 0)
|
|||
|
|
self.gamut_ax_uv.axis("off")
|
|||
|
|
self.gamut_ax_uv.set_clip_on(False)
|
|||
|
|
|
|||
|
|
def cie_uv_to_pixel(u, v):
|
|||
|
|
"""CIE u'v' → 像素坐标"""
|
|||
|
|
px = UV_ORIGIN_U + u * UV_PIXELS_PER_U
|
|||
|
|
py = UV_ORIGIN_V - v * UV_PIXELS_PER_V
|
|||
|
|
return px, py
|
|||
|
|
|
|||
|
|
if len(results) >= 3:
|
|||
|
|
# 只取前 3 个 RGB 点
|
|||
|
|
rgb_results = results[:3]
|
|||
|
|
|
|||
|
|
# 转换为 u'v' 坐标
|
|||
|
|
def xy_to_uv(x, y):
|
|||
|
|
"""xy → u'v' 转换"""
|
|||
|
|
denom = -2 * x + 12 * y + 3
|
|||
|
|
if abs(denom) < 1e-10:
|
|||
|
|
return 0, 0
|
|||
|
|
u = (4 * x) / denom
|
|||
|
|
v = (9 * y) / denom
|
|||
|
|
return u, v
|
|||
|
|
|
|||
|
|
uv_coords = [
|
|||
|
|
[u, v] for u, v in [xy_to_uv(r[0], r[1]) for r in rgb_results]
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
self.log_gui.log(f"UV 坐标: {uv_coords}")
|
|||
|
|
|
|||
|
|
# ========== ✅✅✅ 计算 u'v' 覆盖率(使用参考标准)==========
|
|||
|
|
try:
|
|||
|
|
uv_coverage = pq_algorithm.calculate_uv_gamut_coverage(
|
|||
|
|
uv_coords, reference=current_ref
|
|||
|
|
)
|
|||
|
|
self.log_gui.log(
|
|||
|
|
f"✓ UV 空间覆盖率({current_ref}): {uv_coverage:.1f}%"
|
|||
|
|
)
|
|||
|
|
except Exception as e:
|
|||
|
|
self.log_gui.log(f"⚠️ 计算 UV 覆盖率失败: {str(e)}")
|
|||
|
|
uv_coverage = 0.0
|
|||
|
|
# =================================================
|
|||
|
|
|
|||
|
|
# ========== 绘制测量三角形 ==========
|
|||
|
|
uv_coords_plot = uv_coords + [uv_coords[0]]
|
|||
|
|
points_uv = [cie_uv_to_pixel(u, v) for u, v in uv_coords_plot]
|
|||
|
|
xs_uv = [p[0] for p in points_uv]
|
|||
|
|
ys_uv = [p[1] for p in points_uv]
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.plot(
|
|||
|
|
xs_uv,
|
|||
|
|
ys_uv,
|
|||
|
|
color="red",
|
|||
|
|
linewidth=2.5,
|
|||
|
|
marker="o",
|
|||
|
|
markersize=10,
|
|||
|
|
markerfacecolor="red",
|
|||
|
|
markeredgecolor="white",
|
|||
|
|
markeredgewidth=2,
|
|||
|
|
label="测量色域",
|
|||
|
|
zorder=10,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== 标注 RGB 点 ==========
|
|||
|
|
labels = ["R", "G", "B"]
|
|||
|
|
for (u, v), label in zip(uv_coords, labels):
|
|||
|
|
px, py = cie_uv_to_pixel(u, v)
|
|||
|
|
|
|||
|
|
# 自适应偏移
|
|||
|
|
if label == "R":
|
|||
|
|
if u > 0.42 and v > 0.50:
|
|||
|
|
offset = (-70, 20)
|
|||
|
|
elif u > 0.45:
|
|||
|
|
offset = (30, 50)
|
|||
|
|
else:
|
|||
|
|
offset = (50, 45)
|
|||
|
|
elif label == "G":
|
|||
|
|
offset = (0, -60)
|
|||
|
|
else: # B
|
|||
|
|
offset = (60, 40)
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.annotate(
|
|||
|
|
f"{label}\n({u:.3f},{v:.3f})",
|
|||
|
|
xy=(px, py),
|
|||
|
|
xytext=offset,
|
|||
|
|
textcoords="offset points",
|
|||
|
|
fontsize=9,
|
|||
|
|
color="white",
|
|||
|
|
fontweight="bold",
|
|||
|
|
bbox=dict(
|
|||
|
|
boxstyle="round,pad=0.5",
|
|||
|
|
facecolor="red",
|
|||
|
|
alpha=0.9,
|
|||
|
|
edgecolor="white",
|
|||
|
|
linewidth=2,
|
|||
|
|
),
|
|||
|
|
arrowprops=dict(arrowstyle="->", color="red", lw=2),
|
|||
|
|
zorder=11,
|
|||
|
|
clip_on=False,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== DCI-P3 参考(蓝色)==========
|
|||
|
|
dcip3_uv = [
|
|||
|
|
[0.4970, 0.5260],
|
|||
|
|
[0.0999, 0.5780],
|
|||
|
|
[0.1754, 0.1576],
|
|||
|
|
[0.4970, 0.5260],
|
|||
|
|
]
|
|||
|
|
dcip3_uv_px = [cie_uv_to_pixel(u, v) for u, v in dcip3_uv]
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.plot(
|
|||
|
|
[p[0] for p in dcip3_uv_px],
|
|||
|
|
[p[1] for p in dcip3_uv_px],
|
|||
|
|
color="blue",
|
|||
|
|
linewidth=1.5,
|
|||
|
|
linestyle="--",
|
|||
|
|
marker="s",
|
|||
|
|
markersize=6,
|
|||
|
|
alpha=0.7,
|
|||
|
|
label="DCI-P3",
|
|||
|
|
zorder=5,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== BT.2020 参考(绿色)==========
|
|||
|
|
bt2020_uv = [
|
|||
|
|
[0.5566, 0.5165],
|
|||
|
|
[0.0556, 0.5868],
|
|||
|
|
[0.1593, 0.1258],
|
|||
|
|
[0.5566, 0.5165],
|
|||
|
|
]
|
|||
|
|
bt2020_uv_px = [cie_uv_to_pixel(u, v) for u, v in bt2020_uv]
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.plot(
|
|||
|
|
[p[0] for p in bt2020_uv_px],
|
|||
|
|
[p[1] for p in bt2020_uv_px],
|
|||
|
|
color="green",
|
|||
|
|
linewidth=1.5,
|
|||
|
|
linestyle="-.",
|
|||
|
|
marker="D",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.7,
|
|||
|
|
label="BT.2020",
|
|||
|
|
zorder=4,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== BT.709 参考(灰色)==========
|
|||
|
|
bt709_uv = [
|
|||
|
|
[0.4507, 0.5229],
|
|||
|
|
[0.1250, 0.5625],
|
|||
|
|
[0.1754, 0.1576],
|
|||
|
|
[0.4507, 0.5229],
|
|||
|
|
]
|
|||
|
|
bt709_uv_px = [cie_uv_to_pixel(u, v) for u, v in bt709_uv]
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.plot(
|
|||
|
|
[p[0] for p in bt709_uv_px],
|
|||
|
|
[p[1] for p in bt709_uv_px],
|
|||
|
|
color="gray",
|
|||
|
|
linewidth=1.2,
|
|||
|
|
linestyle=":",
|
|||
|
|
marker="^",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.6,
|
|||
|
|
label="BT.709",
|
|||
|
|
zorder=3,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== BT.601 参考(紫色)- 仅 SDR 测试显示 ==========
|
|||
|
|
if test_type == "sdr_movie":
|
|||
|
|
bt601_uv = [
|
|||
|
|
[0.4510, 0.5236],
|
|||
|
|
[0.1291, 0.5606],
|
|||
|
|
[0.1787, 0.1610],
|
|||
|
|
[0.4510, 0.5236],
|
|||
|
|
]
|
|||
|
|
bt601_uv_px = [cie_uv_to_pixel(u, v) for u, v in bt601_uv]
|
|||
|
|
|
|||
|
|
self.gamut_ax_uv.plot(
|
|||
|
|
[p[0] for p in bt601_uv_px],
|
|||
|
|
[p[1] for p in bt601_uv_px],
|
|||
|
|
color="purple",
|
|||
|
|
linewidth=1.2,
|
|||
|
|
linestyle="-",
|
|||
|
|
marker="o",
|
|||
|
|
markersize=5,
|
|||
|
|
alpha=0.6,
|
|||
|
|
label="BT.601",
|
|||
|
|
zorder=3,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# ========== ✅ UV 覆盖率标注(使用动态计算的值)==========
|
|||
|
|
self.gamut_ax_uv.text(
|
|||
|
|
w_uv * 0.85,
|
|||
|
|
h_uv * 0.92,
|
|||
|
|
f"参考: {current_ref}\n覆盖率: {uv_coverage:.1f}%",
|
|||
|
|
ha="right",
|
|||
|
|
va="bottom",
|
|||
|
|
fontsize=11,
|
|||
|
|
fontweight="bold",
|
|||
|
|
color="red",
|
|||
|
|
bbox=dict(
|
|||
|
|
boxstyle="round,pad=0.5",
|
|||
|
|
facecolor="white",
|
|||
|
|
alpha=0.95,
|
|||
|
|
edgecolor="red",
|
|||
|
|
linewidth=2,
|
|||
|
|
),
|
|||
|
|
zorder=12,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 图例
|
|||
|
|
self.gamut_ax_uv.legend(
|
|||
|
|
loc="upper right",
|
|||
|
|
fontsize=7,
|
|||
|
|
framealpha=0.95,
|
|||
|
|
edgecolor="black",
|
|||
|
|
fancybox=True,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
self.log_gui.log(f"UV 图绘制失败: {str(e)}")
|
|||
|
|
import traceback
|
|||
|
|
|
|||
|
|
self.log_gui.log(traceback.format_exc())
|
|||
|
|
|
|||
|
|
# ========== 总标题 ==========
|
|||
|
|
test_type_name = self.get_test_type_name(test_type)
|
|||
|
|
self.gamut_fig.suptitle(
|
|||
|
|
f"{test_type_name} - 色域测试", fontsize=12, y=0.98, fontweight="bold"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
self.gamut_canvas.draw()
|
|||
|
|
self.chart_notebook.select(0)
|
|||
|
|
|
|||
|
|
self.log_gui.log("色域图绘制完成")
|