2026-04-16 16:51:05 +08:00
|
|
|
|
# PQ自动化测试配置模块
|
|
|
|
|
|
import json
|
|
|
|
|
|
import copy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PQConfig:
|
|
|
|
|
|
def __init__(self, current_test_type="screen_module", device_config={}, pattern={}):
|
2026-04-20 16:44:46 +08:00
|
|
|
|
self.default_cct_params_by_type = {
|
|
|
|
|
|
"screen_module": {
|
|
|
|
|
|
"x_ideal": 0.3127,
|
|
|
|
|
|
"x_tolerance": 0.003,
|
|
|
|
|
|
"y_ideal": 0.3290,
|
|
|
|
|
|
"y_tolerance": 0.003,
|
|
|
|
|
|
},
|
|
|
|
|
|
"sdr_movie": {
|
|
|
|
|
|
"x_ideal": 0.3127,
|
|
|
|
|
|
"x_tolerance": 0.003,
|
|
|
|
|
|
"y_ideal": 0.3290,
|
|
|
|
|
|
"y_tolerance": 0.003,
|
|
|
|
|
|
},
|
|
|
|
|
|
"hdr_movie": {
|
|
|
|
|
|
"x_ideal": 0.3127,
|
|
|
|
|
|
"x_tolerance": 0.003,
|
|
|
|
|
|
"y_ideal": 0.3290,
|
|
|
|
|
|
"y_tolerance": 0.003,
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
self.default_gamut_reference_by_type = {
|
|
|
|
|
|
"screen_module": "DCI-P3",
|
|
|
|
|
|
"sdr_movie": "BT.709",
|
|
|
|
|
|
"hdr_movie": "BT.2020",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-16 16:51:05 +08:00
|
|
|
|
self.default_test_types = {
|
|
|
|
|
|
"screen_module": {
|
|
|
|
|
|
"name": "屏模组性能测试",
|
|
|
|
|
|
"test_items": ["gamut", "gamma", "cct", "contrast"],
|
|
|
|
|
|
"timing": "DMT 1920x 1080 @ 60Hz",
|
|
|
|
|
|
"color_format": "RGB",
|
|
|
|
|
|
"bpc": 8,
|
|
|
|
|
|
"colorimetry": "sRGB",
|
|
|
|
|
|
},
|
|
|
|
|
|
"sdr_movie": {
|
|
|
|
|
|
"name": "SDR Movie测试",
|
|
|
|
|
|
"test_items": ["gamut", "gamma", "cct", "contrast", "accuracy"],
|
|
|
|
|
|
"timing": "DMT 1920x 1080 @ 60Hz",
|
|
|
|
|
|
"color_format": "RGB",
|
|
|
|
|
|
"bpc": 8,
|
|
|
|
|
|
"colorimetry": "sRGB",
|
|
|
|
|
|
},
|
|
|
|
|
|
"hdr_movie": {
|
|
|
|
|
|
"name": "HDR Movie测试",
|
|
|
|
|
|
"test_items": ["gamut", "eotf", "cct", "contrast", "accuracy"],
|
|
|
|
|
|
"timing": "DMT 1920x 1080 @ 60Hz",
|
|
|
|
|
|
"color_format": "RGB",
|
|
|
|
|
|
"bpc": 8,
|
|
|
|
|
|
"colorimetry": "sRGB",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 设备连接配置
|
|
|
|
|
|
self.device_config = {
|
|
|
|
|
|
"ca_com": "COM1",
|
|
|
|
|
|
"ucd_list": "0: UCD-323 [2128C209]",
|
|
|
|
|
|
"ca_channel": "0",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ========== RGB Pattern 配置 ==========
|
|
|
|
|
|
self.default_pattern_rgb = {
|
|
|
|
|
|
"pattern_mode": "SolidColor",
|
|
|
|
|
|
"measurement_bit_depth": 8,
|
|
|
|
|
|
"measurement_max_value": 2,
|
|
|
|
|
|
"pattern_params": [
|
|
|
|
|
|
[255, 0, 0], # 红色
|
|
|
|
|
|
[0, 255, 0], # 绿色
|
|
|
|
|
|
[0, 0, 255], # 蓝色
|
|
|
|
|
|
],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 灰阶 Pattern 配置 ==========
|
|
|
|
|
|
self.default_pattern_gray = {
|
|
|
|
|
|
"pattern_mode": "SolidColor",
|
|
|
|
|
|
"measurement_bit_depth": 8,
|
|
|
|
|
|
"measurement_max_value": 10,
|
|
|
|
|
|
"pattern_params": [
|
|
|
|
|
|
[255, 255, 255], # 100% 白色
|
|
|
|
|
|
[230, 230, 230], # 90%
|
|
|
|
|
|
[205, 205, 205], # 80%
|
|
|
|
|
|
[179, 179, 179], # 70%
|
|
|
|
|
|
[154, 154, 154], # 60%
|
|
|
|
|
|
[128, 128, 128], # 50%
|
|
|
|
|
|
[102, 102, 102], # 40%
|
|
|
|
|
|
[78, 78, 78], # 30%
|
|
|
|
|
|
[52, 52, 52], # 20%
|
|
|
|
|
|
[26, 26, 26], # 10%
|
|
|
|
|
|
[0, 0, 0], # 0% 黑色
|
|
|
|
|
|
],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 色准 Pattern 配置(29色 - SDR 和 HDR 通用)==========
|
|
|
|
|
|
self.default_pattern_accuracy = {
|
|
|
|
|
|
"pattern_mode": "SolidColor",
|
|
|
|
|
|
"measurement_bit_depth": 8,
|
|
|
|
|
|
"measurement_max_value": 28, # 29个颜色,最大索引是28
|
|
|
|
|
|
"pattern_params": [
|
|
|
|
|
|
# ========== 灰阶 (5个) ==========
|
|
|
|
|
|
[255, 255, 255], # 0: White
|
|
|
|
|
|
[230, 230, 230], # 1: Gray 80
|
|
|
|
|
|
[209, 209, 209], # 2: Gray 65
|
|
|
|
|
|
[186, 186, 186], # 3: Gray 50
|
|
|
|
|
|
[158, 158, 158], # 4: Gray 35
|
|
|
|
|
|
# ========== ColorChecker 24色 (18个) ==========
|
|
|
|
|
|
[115, 82, 66], # 5: Dark Skin
|
|
|
|
|
|
[194, 150, 130], # 6: Light Skin
|
|
|
|
|
|
[94, 122, 156], # 7: Blue Sky
|
|
|
|
|
|
[89, 107, 66], # 8: Foliage
|
|
|
|
|
|
[130, 128, 176], # 9: Blue Flower
|
|
|
|
|
|
[99, 189, 168], # 10: Bluish Green
|
|
|
|
|
|
[217, 120, 41], # 11: Orange
|
|
|
|
|
|
[74, 92, 163], # 12: Purplish Blue
|
|
|
|
|
|
[194, 84, 97], # 13: Moderate Red
|
|
|
|
|
|
[92, 61, 107], # 14: Purple
|
|
|
|
|
|
[158, 186, 64], # 15: Yellow Green
|
|
|
|
|
|
[230, 161, 46], # 16: Orange Yellow
|
|
|
|
|
|
[51, 61, 150], # 17: Blue (Legacy)
|
|
|
|
|
|
[71, 148, 71], # 18: Green (Legacy)
|
|
|
|
|
|
[176, 48, 59], # 19: Red (Legacy)
|
|
|
|
|
|
[237, 199, 33], # 20: Yellow (Legacy)
|
|
|
|
|
|
[186, 84, 145], # 21: Magenta (Legacy)
|
|
|
|
|
|
[0, 133, 163], # 22: Cyan (Legacy)
|
|
|
|
|
|
# ========== 100% 饱和色 (6个) ==========
|
|
|
|
|
|
[255, 0, 0], # 23: 100% Red
|
|
|
|
|
|
[0, 255, 0], # 24: 100% Green
|
|
|
|
|
|
[0, 0, 255], # 25: 100% Blue
|
|
|
|
|
|
[0, 255, 255], # 26: 100% Cyan
|
|
|
|
|
|
[255, 0, 255], # 27: 100% Magenta
|
|
|
|
|
|
[255, 255, 0], # 28: 100% Yellow
|
|
|
|
|
|
],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.default_pattern_temp = {
|
|
|
|
|
|
"pattern_mode": "SolidColor",
|
|
|
|
|
|
"measurement_bit_depth": 8,
|
|
|
|
|
|
"measurement_max_value": 146,
|
|
|
|
|
|
"pattern_params": [
|
|
|
|
|
|
[255, 255, 255],
|
|
|
|
|
|
[242, 242, 242],
|
|
|
|
|
|
[230, 230, 230],
|
|
|
|
|
|
[217, 217, 217],
|
|
|
|
|
|
[204, 204, 204],
|
|
|
|
|
|
[191, 191, 191],
|
|
|
|
|
|
[179, 179, 179],
|
|
|
|
|
|
[166, 166, 166],
|
|
|
|
|
|
[153, 153, 153],
|
|
|
|
|
|
[140, 140, 140],
|
|
|
|
|
|
[128, 128, 128],
|
|
|
|
|
|
[115, 115, 115],
|
|
|
|
|
|
[102, 102, 102],
|
|
|
|
|
|
[89, 89, 89],
|
|
|
|
|
|
[77, 77, 77],
|
|
|
|
|
|
[64, 64, 64],
|
|
|
|
|
|
[51, 51, 51],
|
|
|
|
|
|
[38, 38, 38],
|
|
|
|
|
|
[26, 26, 26],
|
|
|
|
|
|
[13, 13, 13],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[255, 0, 0],
|
|
|
|
|
|
[242, 0, 0],
|
|
|
|
|
|
[230, 0, 0],
|
|
|
|
|
|
[217, 0, 0],
|
|
|
|
|
|
[204, 0, 0],
|
|
|
|
|
|
[191, 0, 0],
|
|
|
|
|
|
[179, 0, 0],
|
|
|
|
|
|
[166, 0, 0],
|
|
|
|
|
|
[153, 0, 0],
|
|
|
|
|
|
[140, 0, 0],
|
|
|
|
|
|
[128, 0, 0],
|
|
|
|
|
|
[115, 0, 0],
|
|
|
|
|
|
[102, 0, 0],
|
|
|
|
|
|
[89, 0, 0],
|
|
|
|
|
|
[77, 0, 0],
|
|
|
|
|
|
[64, 0, 0],
|
|
|
|
|
|
[51, 0, 0],
|
|
|
|
|
|
[38, 0, 0],
|
|
|
|
|
|
[26, 0, 0],
|
|
|
|
|
|
[13, 0, 0],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[0, 255, 0],
|
|
|
|
|
|
[0, 242, 0],
|
|
|
|
|
|
[0, 230, 0],
|
|
|
|
|
|
[0, 217, 0],
|
|
|
|
|
|
[0, 204, 0],
|
|
|
|
|
|
[0, 191, 0],
|
|
|
|
|
|
[0, 179, 0],
|
|
|
|
|
|
[0, 166, 0],
|
|
|
|
|
|
[0, 153, 0],
|
|
|
|
|
|
[0, 140, 0],
|
|
|
|
|
|
[0, 128, 0],
|
|
|
|
|
|
[0, 115, 0],
|
|
|
|
|
|
[0, 102, 0],
|
|
|
|
|
|
[0, 89, 0],
|
|
|
|
|
|
[0, 77, 0],
|
|
|
|
|
|
[0, 64, 0],
|
|
|
|
|
|
[0, 51, 0],
|
|
|
|
|
|
[0, 38, 0],
|
|
|
|
|
|
[0, 26, 0],
|
|
|
|
|
|
[0, 13, 0],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[0, 0, 255],
|
|
|
|
|
|
[0, 0, 242],
|
|
|
|
|
|
[0, 0, 230],
|
|
|
|
|
|
[0, 0, 217],
|
|
|
|
|
|
[0, 0, 204],
|
|
|
|
|
|
[0, 0, 191],
|
|
|
|
|
|
[0, 0, 179],
|
|
|
|
|
|
[0, 0, 166],
|
|
|
|
|
|
[0, 0, 153],
|
|
|
|
|
|
[0, 0, 140],
|
|
|
|
|
|
[0, 0, 128],
|
|
|
|
|
|
[0, 0, 115],
|
|
|
|
|
|
[0, 0, 102],
|
|
|
|
|
|
[0, 0, 89],
|
|
|
|
|
|
[0, 0, 77],
|
|
|
|
|
|
[0, 0, 64],
|
|
|
|
|
|
[0, 0, 51],
|
|
|
|
|
|
[0, 0, 38],
|
|
|
|
|
|
[0, 0, 26],
|
|
|
|
|
|
[0, 0, 13],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[255, 255, 0],
|
|
|
|
|
|
[242, 242, 0],
|
|
|
|
|
|
[230, 230, 0],
|
|
|
|
|
|
[217, 217, 0],
|
|
|
|
|
|
[204, 204, 0],
|
|
|
|
|
|
[191, 191, 0],
|
|
|
|
|
|
[179, 179, 0],
|
|
|
|
|
|
[166, 166, 0],
|
|
|
|
|
|
[153, 153, 0],
|
|
|
|
|
|
[140, 140, 0],
|
|
|
|
|
|
[128, 128, 0],
|
|
|
|
|
|
[115, 115, 0],
|
|
|
|
|
|
[102, 102, 0],
|
|
|
|
|
|
[89, 89, 0],
|
|
|
|
|
|
[77, 77, 0],
|
|
|
|
|
|
[64, 64, 0],
|
|
|
|
|
|
[51, 51, 0],
|
|
|
|
|
|
[38, 38, 0],
|
|
|
|
|
|
[26, 26, 0],
|
|
|
|
|
|
[13, 13, 0],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[0, 255, 255],
|
|
|
|
|
|
[0, 242, 242],
|
|
|
|
|
|
[0, 230, 230],
|
|
|
|
|
|
[0, 217, 217],
|
|
|
|
|
|
[0, 204, 204],
|
|
|
|
|
|
[0, 191, 191],
|
|
|
|
|
|
[0, 179, 179],
|
|
|
|
|
|
[0, 166, 166],
|
|
|
|
|
|
[0, 153, 153],
|
|
|
|
|
|
[0, 140, 140],
|
|
|
|
|
|
[0, 128, 128],
|
|
|
|
|
|
[0, 115, 115],
|
|
|
|
|
|
[0, 102, 102],
|
|
|
|
|
|
[0, 89, 89],
|
|
|
|
|
|
[0, 77, 77],
|
|
|
|
|
|
[0, 64, 64],
|
|
|
|
|
|
[0, 51, 51],
|
|
|
|
|
|
[0, 38, 38],
|
|
|
|
|
|
[0, 26, 26],
|
|
|
|
|
|
[0, 13, 13],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
|
|
|
|
|
|
[255, 0, 255],
|
|
|
|
|
|
[242, 0, 242],
|
|
|
|
|
|
[230, 0, 230],
|
|
|
|
|
|
[217, 0, 217],
|
|
|
|
|
|
[204, 0, 204],
|
|
|
|
|
|
[191, 0, 191],
|
|
|
|
|
|
[179, 0, 179],
|
|
|
|
|
|
[166, 0, 166],
|
|
|
|
|
|
[153, 0, 153],
|
|
|
|
|
|
[140, 0, 140],
|
|
|
|
|
|
[128, 0, 128],
|
|
|
|
|
|
[115, 0, 115],
|
|
|
|
|
|
[102, 0, 102],
|
|
|
|
|
|
[89, 0, 89],
|
|
|
|
|
|
[77, 0, 77],
|
|
|
|
|
|
[64, 0, 64],
|
|
|
|
|
|
[51, 0, 51],
|
|
|
|
|
|
[38, 0, 38],
|
|
|
|
|
|
[26, 0, 26],
|
|
|
|
|
|
[13, 0, 13],
|
|
|
|
|
|
[0, 0, 0],
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 自定义图案
|
|
|
|
|
|
self.custom_pattern = {
|
|
|
|
|
|
"pattern_mode": "SolidColor",
|
|
|
|
|
|
"measurement_bit_depth": 8,
|
|
|
|
|
|
"measurement_max_value": 0,
|
|
|
|
|
|
"pattern_params": [],
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.current_test_types = self.default_test_types
|
|
|
|
|
|
self.current_test_type = current_test_type
|
|
|
|
|
|
self.current_pattern = self.default_pattern_rgb
|
|
|
|
|
|
|
2026-04-20 16:44:46 +08:00
|
|
|
|
def get_default_cct_params(self, test_type):
|
|
|
|
|
|
"""获取指定测试类型的默认 CCT 参数副本。"""
|
|
|
|
|
|
default = self.default_cct_params_by_type.get(
|
|
|
|
|
|
test_type, self.default_cct_params_by_type["screen_module"]
|
|
|
|
|
|
)
|
|
|
|
|
|
return copy.deepcopy(default)
|
|
|
|
|
|
|
|
|
|
|
|
def get_default_gamut_reference(self, test_type):
|
|
|
|
|
|
"""获取指定测试类型的默认色域参考。"""
|
|
|
|
|
|
return self.default_gamut_reference_by_type.get(test_type, "DCI-P3")
|
|
|
|
|
|
|
2026-04-16 16:51:05 +08:00
|
|
|
|
# ========== 获取临时配置(用于 Full/Limited 转换)==========
|
|
|
|
|
|
def get_temp_config_with_converted_params(self, mode, converted_params):
|
|
|
|
|
|
"""
|
|
|
|
|
|
创建一个临时配置对象,包含转换后的 pattern 参数
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
mode: "rgb" | "gray" | "accuracy"
|
|
|
|
|
|
converted_params: 转换后的参数列表(Full 或 Limited Range)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
PQConfig: 临时配置对象(深拷贝,不影响原始配置)
|
|
|
|
|
|
"""
|
|
|
|
|
|
# 1. 深拷贝整个配置对象
|
|
|
|
|
|
temp_config = copy.deepcopy(self)
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 设置正确的 pattern 模式
|
|
|
|
|
|
if mode == "rgb":
|
|
|
|
|
|
temp_config.current_pattern = copy.deepcopy(self.default_pattern_rgb)
|
|
|
|
|
|
elif mode == "gray":
|
|
|
|
|
|
temp_config.current_pattern = copy.deepcopy(self.default_pattern_gray)
|
|
|
|
|
|
elif mode == "accuracy":
|
|
|
|
|
|
temp_config.current_pattern = copy.deepcopy(self.default_pattern_accuracy)
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 替换为转换后的参数
|
|
|
|
|
|
temp_config.current_pattern["pattern_params"] = converted_params
|
|
|
|
|
|
|
|
|
|
|
|
return temp_config
|
|
|
|
|
|
|
|
|
|
|
|
def to_dict(self):
|
|
|
|
|
|
"""将配置转换为字典格式"""
|
|
|
|
|
|
return {
|
|
|
|
|
|
"current_test_type": self.current_test_type,
|
|
|
|
|
|
"test_types": self.current_test_types,
|
|
|
|
|
|
"device_config": self.device_config,
|
|
|
|
|
|
"default_pattern_rgb": self.default_pattern_rgb,
|
|
|
|
|
|
"default_pattern_gray": self.default_pattern_gray,
|
|
|
|
|
|
"default_pattern_accuracy": self.default_pattern_accuracy,
|
|
|
|
|
|
"custom_pattern": self.custom_pattern,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def from_dict(self, config_dict):
|
|
|
|
|
|
"""从字典加载配置"""
|
|
|
|
|
|
self.current_test_type = config_dict.get("current_test_type", "screen_module")
|
|
|
|
|
|
self.current_test_types = config_dict.get("test_types", self.current_test_types)
|
|
|
|
|
|
self.device_config = config_dict.get("device_config", self.device_config)
|
|
|
|
|
|
|
|
|
|
|
|
self.default_pattern_rgb = config_dict.get(
|
|
|
|
|
|
"default_pattern_rgb", self.default_pattern_rgb
|
|
|
|
|
|
)
|
|
|
|
|
|
self.default_pattern_gray = config_dict.get(
|
|
|
|
|
|
"default_pattern_gray", self.default_pattern_gray
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
# ========== 强制使用新的 29色配置 ==========
|
2026-04-16 16:51:05 +08:00
|
|
|
|
loaded_accuracy = config_dict.get("default_pattern_accuracy", None)
|
|
|
|
|
|
|
|
|
|
|
|
# 检查加载的配置是否是旧的 10色
|
|
|
|
|
|
if loaded_accuracy and len(loaded_accuracy.get("pattern_params", [])) != 29:
|
|
|
|
|
|
print(
|
2026-04-21 15:31:48 +08:00
|
|
|
|
f"检测到旧的配置({len(loaded_accuracy.get('pattern_params', []))}色),强制使用新的 29色配置"
|
2026-04-16 16:51:05 +08:00
|
|
|
|
)
|
|
|
|
|
|
# 使用 __init__ 中定义的新配置
|
|
|
|
|
|
self.default_pattern_accuracy = self.default_pattern_accuracy
|
|
|
|
|
|
else:
|
|
|
|
|
|
self.default_pattern_accuracy = config_dict.get(
|
|
|
|
|
|
"default_pattern_accuracy", self.default_pattern_accuracy
|
|
|
|
|
|
)
|
|
|
|
|
|
# ==========================================
|
|
|
|
|
|
|
|
|
|
|
|
self.custom_pattern = config_dict.get("custom_pattern", self.custom_pattern)
|
|
|
|
|
|
|
|
|
|
|
|
def save_to_file(self, filename):
|
|
|
|
|
|
"""将配置保存到文件"""
|
|
|
|
|
|
with open(filename, "w", encoding="utf-8") as f:
|
|
|
|
|
|
json.dump(self.to_dict(), f, indent=4, ensure_ascii=False)
|
|
|
|
|
|
|
|
|
|
|
|
def set_current_test_type(self, test_type):
|
|
|
|
|
|
"""设置当前测试类型"""
|
|
|
|
|
|
if test_type in self.current_test_types:
|
|
|
|
|
|
self.current_test_type = test_type
|
|
|
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def set_current_test_items(self, test_items):
|
|
|
|
|
|
"""设置当前测试类型的测试项"""
|
|
|
|
|
|
if self.current_test_type in self.current_test_types:
|
|
|
|
|
|
self.current_test_types[self.current_test_type]["test_items"] = test_items
|
|
|
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def set_current_timing(self, timing):
|
|
|
|
|
|
if self.current_test_type in self.current_test_types:
|
|
|
|
|
|
self.current_test_types[self.current_test_type]["timing"] = timing
|
|
|
|
|
|
return True
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def set_device_config(self, ca_com, ucd_list, ca_channel):
|
|
|
|
|
|
"""设置设备连接配置"""
|
|
|
|
|
|
self.device_config["ca_com"] = ca_com
|
|
|
|
|
|
self.device_config["ucd_list"] = ucd_list
|
|
|
|
|
|
self.device_config["ca_channel"] = ca_channel
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def set_current_pattern(self, mode):
|
|
|
|
|
|
"""设置当前模式的测试图案"""
|
|
|
|
|
|
if mode == "rgb":
|
|
|
|
|
|
self.current_pattern = self.default_pattern_rgb
|
|
|
|
|
|
elif mode == "gray":
|
|
|
|
|
|
self.current_pattern = self.default_pattern_gray
|
2026-04-21 15:31:48 +08:00
|
|
|
|
elif mode == "accuracy": # 色准模式(SDR 和 HDR 通用 29色)
|
2026-04-16 16:51:05 +08:00
|
|
|
|
self.current_pattern = self.default_pattern_accuracy
|
|
|
|
|
|
elif mode == "custom":
|
|
|
|
|
|
# self.current_pattern = self.custom_pattern
|
|
|
|
|
|
self.current_pattern = self.default_pattern_temp
|
|
|
|
|
|
else:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
# 确保 measurement_max_value 是整数
|
|
|
|
|
|
if "measurement_max_value" in self.current_pattern:
|
|
|
|
|
|
value = self.current_pattern["measurement_max_value"]
|
|
|
|
|
|
if isinstance(value, str):
|
|
|
|
|
|
try:
|
|
|
|
|
|
self.current_pattern["measurement_max_value"] = int(value)
|
|
|
|
|
|
except ValueError:
|
|
|
|
|
|
self.current_pattern["measurement_max_value"] = (
|
|
|
|
|
|
len(self.current_pattern["pattern_params"]) - 1
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def set_custom_pattern(self, pattern_mode, pattern_params):
|
|
|
|
|
|
"""设置自定义模式的测试项"""
|
|
|
|
|
|
self.custom_pattern["pattern_mode"] = pattern_mode
|
|
|
|
|
|
self.custom_pattern["pattern_params"] = pattern_params
|
|
|
|
|
|
self.custom_pattern["measurement_max_value"] = len(pattern_params) - 1
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
# ========== 获取 29色名称列表 ==========
|
2026-04-16 16:51:05 +08:00
|
|
|
|
def get_accuracy_color_names(self):
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取色准测试的 29个颜色名称(SDR 和 HDR 通用)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
list: 29个颜色名称
|
|
|
|
|
|
"""
|
|
|
|
|
|
return [
|
|
|
|
|
|
# 灰阶 (5个)
|
|
|
|
|
|
"White",
|
|
|
|
|
|
"Gray 80",
|
|
|
|
|
|
"Gray 65",
|
|
|
|
|
|
"Gray 50",
|
|
|
|
|
|
"Gray 35",
|
|
|
|
|
|
# ColorChecker 24色 (18个)
|
|
|
|
|
|
"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% 饱和色 (6个)
|
|
|
|
|
|
"100% Red",
|
|
|
|
|
|
"100% Green",
|
|
|
|
|
|
"100% Blue",
|
|
|
|
|
|
"100% Cyan",
|
|
|
|
|
|
"100% Magenta",
|
|
|
|
|
|
"100% Yellow",
|
|
|
|
|
|
]
|
|
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
# ========== 获取 29色的 RGB 值 ==========
|
2026-04-16 16:51:05 +08:00
|
|
|
|
def get_accuracy_color_rgb(self):
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取色准测试的 RGB 值(用于标准值计算)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
list: [(name, r, g, b), ...]
|
|
|
|
|
|
"""
|
|
|
|
|
|
names = self.get_accuracy_color_names()
|
|
|
|
|
|
rgb_values = self.default_pattern_accuracy["pattern_params"]
|
|
|
|
|
|
|
|
|
|
|
|
return [(name, r, g, b) for name, (r, g, b) in zip(names, rgb_values)]
|
|
|
|
|
|
|
|
|
|
|
|
def get_temp_pattern_names(self):
|
|
|
|
|
|
"""获取客户模板测试(default_pattern_temp)的固定 pattern 名称列表"""
|
|
|
|
|
|
percentages = list(range(100, -1, -5))
|
|
|
|
|
|
color_prefixes = ["W", "R", "G", "B", "Y", "C", "M"]
|
|
|
|
|
|
|
|
|
|
|
|
names = []
|
|
|
|
|
|
for prefix in color_prefixes:
|
|
|
|
|
|
for value in percentages:
|
|
|
|
|
|
names.append(f"{prefix} {value}%")
|
|
|
|
|
|
|
|
|
|
|
|
pattern_count = len(self.default_pattern_temp.get("pattern_params", []))
|
|
|
|
|
|
|
|
|
|
|
|
if pattern_count <= len(names):
|
|
|
|
|
|
return names[:pattern_count]
|
|
|
|
|
|
|
|
|
|
|
|
# 兜底:如果后续扩展了 pattern 数量,补充通用名称,避免索引越界。
|
|
|
|
|
|
for i in range(len(names), pattern_count):
|
|
|
|
|
|
names.append(f"P {i + 1}")
|
|
|
|
|
|
|
|
|
|
|
|
return names
|
|
|
|
|
|
|
|
|
|
|
|
def get_test_item_chinese_names(self, test_items):
|
|
|
|
|
|
"""获取测试项目的显示名称"""
|
|
|
|
|
|
item_names = []
|
|
|
|
|
|
for item in test_items:
|
|
|
|
|
|
if item == "gamut":
|
|
|
|
|
|
item_names.append("色域")
|
|
|
|
|
|
elif item == "gamma":
|
|
|
|
|
|
item_names.append("Gamma")
|
|
|
|
|
|
elif item == "eotf":
|
|
|
|
|
|
item_names.append("EOTF")
|
|
|
|
|
|
elif item == "cct":
|
|
|
|
|
|
item_names.append("色度一致性")
|
|
|
|
|
|
elif item == "contrast":
|
|
|
|
|
|
item_names.append("对比度")
|
|
|
|
|
|
elif item == "accuracy":
|
|
|
|
|
|
item_names.append("色准")
|
|
|
|
|
|
else:
|
|
|
|
|
|
item_names.append(item)
|
|
|
|
|
|
return item_names
|
|
|
|
|
|
|
|
|
|
|
|
def get_current_config(self):
|
|
|
|
|
|
"""返回当前测试类型相关的所有配置信息"""
|
|
|
|
|
|
if self.current_test_type not in self.current_test_types:
|
|
|
|
|
|
return {}
|
|
|
|
|
|
|
|
|
|
|
|
current_test = self.current_test_types[self.current_test_type]
|
|
|
|
|
|
|
|
|
|
|
|
config_info = {
|
|
|
|
|
|
"test_type": self.current_test_type,
|
|
|
|
|
|
"test_name": current_test.get("name", "未知测试"),
|
|
|
|
|
|
"test_items": current_test.get("test_items", []),
|
|
|
|
|
|
"test_items_chinese": self.get_test_item_chinese_names(
|
|
|
|
|
|
current_test.get("test_items", [])
|
|
|
|
|
|
),
|
|
|
|
|
|
"timing": current_test.get("timing", "DMT 1920x 1080 @ 60Hz"),
|
|
|
|
|
|
"color_format": current_test.get("color_format", "RGB"),
|
|
|
|
|
|
"bpc": current_test.get("bpc", 8),
|
|
|
|
|
|
"colorimetry": current_test.get("colorimetry", "sRGB"),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return config_info
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
# ========== 验证代码(测试完成后可删除)==========
|
2026-04-16 16:51:05 +08:00
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
print("验证 pq_config.py 配置")
|
|
|
|
|
|
print("=" * 60)
|
|
|
|
|
|
|
|
|
|
|
|
config = PQConfig()
|
|
|
|
|
|
|
|
|
|
|
|
# 检查 default_pattern_accuracy
|
|
|
|
|
|
pattern_count = len(config.default_pattern_accuracy["pattern_params"])
|
|
|
|
|
|
max_value = config.default_pattern_accuracy["measurement_max_value"]
|
|
|
|
|
|
|
|
|
|
|
|
print(f"\ndefault_pattern_accuracy:")
|
|
|
|
|
|
print(f" 图案数量: {pattern_count}")
|
|
|
|
|
|
print(f" measurement_max_value: {max_value}")
|
|
|
|
|
|
|
|
|
|
|
|
if pattern_count == 29 and max_value == 28:
|
2026-04-21 15:31:48 +08:00
|
|
|
|
print("\n配置正确(29色)")
|
2026-04-16 16:51:05 +08:00
|
|
|
|
|
|
|
|
|
|
# 显示前 5 个图案
|
|
|
|
|
|
print("\n前5个图案:")
|
|
|
|
|
|
for i in range(5):
|
|
|
|
|
|
rgb = config.default_pattern_accuracy["pattern_params"][i]
|
|
|
|
|
|
names = config.get_accuracy_color_names()
|
|
|
|
|
|
print(f" [{i}] {names[i]:15s} RGB{rgb}")
|
|
|
|
|
|
|
|
|
|
|
|
# 显示后 5 个图案
|
|
|
|
|
|
print("\n后5个图案:")
|
|
|
|
|
|
for i in range(24, 29):
|
|
|
|
|
|
rgb = config.default_pattern_accuracy["pattern_params"][i]
|
|
|
|
|
|
names = config.get_accuracy_color_names()
|
|
|
|
|
|
print(f" [{i}] {names[i]:15s} RGB{rgb}")
|
|
|
|
|
|
|
|
|
|
|
|
# 测试 set_current_pattern
|
|
|
|
|
|
print("\n测试 set_current_pattern('accuracy'):")
|
|
|
|
|
|
config.set_current_pattern("accuracy")
|
|
|
|
|
|
current_count = len(config.current_pattern["pattern_params"])
|
|
|
|
|
|
print(f" current_pattern 图案数量: {current_count}")
|
|
|
|
|
|
|
|
|
|
|
|
if current_count == 29:
|
2026-04-21 15:31:48 +08:00
|
|
|
|
print(" set_current_pattern 工作正常")
|
2026-04-16 16:51:05 +08:00
|
|
|
|
else:
|
2026-04-21 15:31:48 +08:00
|
|
|
|
print(f" [Error] set_current_pattern 失败!只有 {current_count} 个图案")
|
2026-04-16 16:51:05 +08:00
|
|
|
|
|
|
|
|
|
|
else:
|
2026-04-21 15:31:48 +08:00
|
|
|
|
print(f"\n[Error] 配置错误!")
|
2026-04-16 16:51:05 +08:00
|
|
|
|
print(f" 期望: 29 个图案, measurement_max_value=28")
|
|
|
|
|
|
print(f" 实际: {pattern_count} 个图案, measurement_max_value={max_value}")
|
|
|
|
|
|
|
2026-04-21 15:31:48 +08:00
|
|
|
|
print("\n[Error] 请检查 default_pattern_accuracy 定义!")
|
2026-04-16 16:51:05 +08:00
|
|
|
|
print(" 应该包含:")
|
|
|
|
|
|
print(" - 5个灰阶")
|
|
|
|
|
|
print(" - 18个 ColorChecker 色块")
|
|
|
|
|
|
print(" - 6个 100% 饱和色")
|
|
|
|
|
|
print(" - 总计 29 个 RGB 数组")
|
|
|
|
|
|
|
|
|
|
|
|
print("=" * 60)
|