16、Q Capture与Q Apply管理全解析

Q Capture与Q Apply管理全解析

在数据处理与管理的领域中,Q Capture和Q Apply是非常重要的工具,它们在数据复制和传输方面发挥着关键作用。下面将详细介绍它们的相关管理操作和技术要点。

1. 获取Q Capture重启队列信息

若要从DB2日志的某个点启动Q Capture,就需要从重启队列中获取 qRestartMsg.restartLSN qRestartMsg.lastCommitSEQ 的值。以单向复制为例,重启队列名为 CAPA.RESTARTQ ,队列管理器名为 QMA ,使用以下命令获取信息:

$ asnqmfmt CAPA.RESTARTQ  QMA

执行该命令后,会输出一系列信息,从中可以看到 qRestartMsg.restartLSN qRestartMsg.lastCommitSEQ 的值。

如果不知道重启队列的名称,可以使用以下查询语句来查找:

db2 "SELECT SUBSTR(qmgr,1,10) AS qmgr, SUBSTR(restartq,1,20) AS restartq 
FROM asn.ibmqrep_capparms "

查询结果示例如下:
| QMGR | RESTARTQ |
| ---- | ---- |
| QMA | CAPA.RESTARTQ |

2. Q Capture和Q Apply的管理方式

Q Capture和Q Apply可以通过复制中心或命令行进行管理,这里主要介绍命令行方式。由于Q复制的异步特性,在热启动/停止Q Capture和Q Apply时,顺序无关紧要。但在多向复制中,冷启动时启动顺序很重要,必须先启动所有Q Capture并使其正常运行,再启动Q Apply。

管理Q Capture的两个主要命令是 asnqcap asnqccmd ,管理Q Apply的两个主要命令是 asnqapp asnqacmd

3. Q Capture和Q Apply的日志

Q Capture和Q Apply的日志名称由以下部分组成:
- 实例名称
- Q Capture数据库服务器名称
- 控制表模式
- 标签(Q Capture为 QCAP.LOG ,Q Apply为 QAPP.LOG

例如,对于控制表位于DB2A数据库、模式为ASN的DB2实例中的Q Capture,其日志名称为 db2.DB2A.ASN.QCAP.log 。默认情况下,日志会写入程序启动的目录,或者由 CAPTURE_PATH APPLY_PATH 启动参数指定的目录。如果日志文件不存在,在需要写入时会自动创建。为防止日志文件过大,可以定期重命名日志文件,但需要先停止Q Capture和Q Apply。若遇到问题,可以在启动命令后追加 DEBUG=Y 以调试模式启动。

4. Q Capture管理
4.1 Q Capture的主要任务
  • 读取DB2日志,并将已提交的事务放入发送队列。
  • 跟踪已处理的内容。
  • 启动控制表的清理操作。
4.2 启动Q Capture

使用 asnqcap 命令启动Q Capture,该命令有众多参数,具体如下表所示:
| 参数 | 描述 |
| ---- | ---- |
| ADD_PARTITION=Y|N | 确定Q Capture是否开始读取自上次重启后添加的分区的日志文件。 |
| AUTOSTOP=Y|N | 到达日志末尾时终止Q Capture。 |
| CAPTURE_PATH= | Q Capture日志文件的位置。 |
| CAPTURE_SCHEMA= | 用于标识Q Capture的模式名称。 |
| CAPTURE_SERVER= | Q Capture控制服务器的名称(即源数据库)。 |
| COMMIT_INTERVAL=n|500 | 提交到WebSphere MQ的间隔时间(毫秒)。 |
| IGNORE_TRANSID=transaction_ID | 指定Q Capture忽略由transaction_ID标识的事务,这些事务不会被复制或发布。 |
| LOB_SEND_OPTION=I/S | 指定Q Capture是在事务消息中内联发送LOB值(I),还是在单独的消息中发送(S)。 |
| LOGRDBUFSZ=n|256 | 指定Q Capture从DB2检索日志记录时传递给DB2的缓冲区大小。 |
| LOGREUSE=Y|N | 重用或追加消息到日志文件。 |
| LOGSTDOUT=Y|N | 将消息发送到标准输出。 |
| LSN=formatted_lsn | 指定Q Capture在热重启时开始的日志序列号,指定该参数时必须同时指定MAXCMTSEQ参数。 |
| MAXCMTSEQ=formatted_lsn | Q Capture关闭前成功发送的最后一个事务的提交日志记录位置。 |
| MEMORY_LIMIT=n|32 | 从日志重建事务的最大字节数。 |
| MSG_PERSISTENCE=Y/N | 指定Q Capture是否将持久(已记录)消息写入WebSphere MQ队列。 |
| MONITOR_INTERVAL=n|300 | 插入监控表的间隔时间(秒)。 |
| MONITOR_LIMIT=n|10080 | 监控表行可清理的时间(分钟)。 |
| PRUNE_INTERVAL=n|300 | Q Capture尝试清理控制表的间隔时间(秒)。 |
| QFULL_NUM_RETRIES (RN)=N|30 | 指定重试次数,最多1000次,值为0表示MQPUT操作失败时停止。 |
| QFULL_RETRY_DELAY (RD)=N|250 | 指定Q Capture在MQPUT尝试之间等待的时间(毫秒),范围为10毫秒到3600000毫秒(1小时),默认延迟为250毫秒或COMMIT_INTERVAL参数的值,取较小者。 |
| SIGNAL_LIMIT=n|10080 | 信号表行可清理的时间(分钟)。 |
| SLEEP_INTERVAL=n|5000 | 到达日志末尾后休眠的时间(毫秒),默认值为5000毫秒,减小该值可能会降低Q Capture的延迟。 |
| STARTALLQ=Y/N | 指定Q Capture在启动时是否激活所有发送队列。 |
| STARTMODE=[ COLD|WARMSI|WARMSA|WARMNS ] | 启动模式,COLD表示从日志末尾开始读取,等待CAPSTART;WARMSI表示如果没有重启信息则初始切换到冷启动;WARMSA表示如果出错则始终切换到冷启动;WARMNS表示从不切换到冷启动。 |
| TERM=Y|N | 如果DB2终止,则终止Q Capture。 |
| TRACE_LIMIT=n|10080 | 跟踪表行可清理的时间(分钟)。 |

启动Q Capture的最小信息是Q Capture控制表的位置(如DB2A),通常还会指定Q Capture模式(默认为ASN)、Q Capture路径(日志写入位置)和启动模式。示例命令如下:

asnqcap capture_server=DB2A capture_schema=ASN capture_path=c:\temp startmode=WARMSI 

Q Capture的启动参数存储在 IBMQREP_CAPPARMS 控制表中,可以使用相关SQL查询。如果启动Q Capture失败且未在相应目录创建日志文件,需要检查是否有有效的InfoSphere复制服务器许可证。

此外,还可以从DB2日志的已知点启动Q Capture,而无需对目标表进行完全刷新。通过提供 lsn (要捕获的最旧未提交事务的日志序列号)和 maxcmtseq (最近提交并放入发送队列的事务的LSN)的值,使用 asnqcap 命令启动。可以使用 asnqmfmt 命令或查看Q Capture日志中的 ASN7109I 消息来获取这些值。示例命令如下:

asnqcap CAPTURE_SERVER=db2a CAPTURE_SCHEMA=asn LSN=0000:0000:0000:023b:35f8 MAXCMTSEQ=4614:f4b1:0000:0001:0000

也可以不使用冒号指定 LSN MAXCMTSEQ 的值以节省空间,例如 LSN=FFFFFFFFFFFFFFFFFFFF

4.3 管理运行中的Q Capture

使用 asnqccmd 命令管理运行中的Q Capture,其格式为:

asnqccmd [<parameter>=<value> ...] [command]

可能的参数包括:
- CAPTURE_SCHEMA= :用于标识Q Capture的模式名称。
- CAPTURE_SERVER= :Q Capture控制服务器的名称。
- LOGSTDOUT=Y|N :将消息发送到标准输出。

可能的命令包括:
- CHGPARMS :更改Q Capture的操作参数。
- PRUNE :清理Q Capture的控制表。
- QRYPARMS :查询Q Capture的操作参数。
- REINIT :重新初始化所有Q Capture订阅。
- REINITQ :重新初始化Q Capture的一个发送队列。
- STATUS :查询Q Capture线程的状态。
- STATUS SHOW DETAILS :查询Q Capture线程的增强状态。
- STOP :停止Q Capture。

例如,停止Q Capture的命令示例:

asnqccmd CAPTURE_SERVER=db2a STOP

查询Q Capture状态的方式有两种:
- 使用 asnqccmd 命令的 qryparms 选项检查Q Capture实际启动时的参数:

asnqccmd CAPTURE_SERVER=db2a QRYPARMS
  • 使用 asnqccmd 命令的 STATUS 选项查看Q Capture线程的状态:
asnqccmd CAPTURE_SERVER=db2a STATUS

使用 STATUS SHOW DETAILS 选项可以获得更详细的Q Capture状态报告,包括是否正在运行、程序启动后的时间、Q Capture诊断日志的位置、活动Q订阅的数量、当前日志时间和当前内存的值、Q Capture发布到发送队列的最后一个事务的逻辑日志序列号、Q Capture在最近监控间隔内从日志记录构建事务使用的内存量等信息。命令示例:

asnqccmd CAPTURE_SERVER=db2a STATUS SHOW DETAILS
4.4 修改运行中的Q Capture

修改运行中的Q Capture分两步:先更改参数,再重新初始化Q Capture。使用 asnqccmd 命令的 chgparms 关键字和以下参数之一临时更改Q Capture的参数:

autostop         memory_limit                    signal_limit
commit_interval  monitor_interval                sleep_interval
logreuse         monitor_limit                   term
logstdout        prune_interval                  trace_limit

例如,将运行中的Q Capture的 monitor_interval 参数临时更改为10秒:

asnqccmd CAPTURE_SERVER=db2a CHGPARMS monitor_interval=10

如果要临时更改两个参数,参数之间用空格分隔:

asnqccmd capture_server=DB2A chgparms prune_interval=60 sleep_interval=10000

需要注意的是,这些命令只是临时更改运行中的Q Capture的参数。如果停止并重新启动Q Capture,它将从 IBMQREP_CAPPARMS 表中获取参数值。要使更改永久生效,需要更新 IBMQREP_CAPPARMS 表,示例SQL如下:

db2 "UPDATE asn.ibmqrep_capparms SET monitor_interval=10 WHERE qmgr= 'QMA' "
4.5 从DB2日志的特定点启动Q Capture

可以通过命令行参数从DB2日志的已知点启动Q Capture,而无需触发目标表的加载。具体步骤如下:
1. 确定 lsn (要捕获的最旧未提交事务的日志序列号)和 maxcmtseq (最近提交并放入发送队列的事务的LSN)的值。可以使用 asnqmfmt 命令或查看Q Capture日志中的 ASN7109I 消息来获取这些值。
2. 将获取的值插入 asnqcap 命令中,示例如下:

asnqcap CAPTURE_SERVER=db2a CAPTURE_SCHEMA=asn LSN=0000:0000:0000:023b:35f8 MAXCMTSEQ=4614:f4b1:0000:0001:0000

也可以不使用冒号指定 LSN MAXCMTSEQ 的值以节省空间。

可以通过以下步骤测试从DB2日志的已知点启动Q Capture的概念:
1. 设置双向场景。
2. 让应用程序向服务器SYA上的表插入行。
3. 在应用程序运行时,取消服务器SYA上运行的Q Capture。
4. 使用 asnqmfmt 命令确定重启值。
5. 检查Q Capture日志以确定重启值。
6. 确认 asnqmfmt 命令和Q Capture日志中的重启值一致。
7. 使用 asnqcap 命令和适当的重启值重新启动Q Capture。

4.6 无加载启动Q Capture

要从日志末尾启动Q Capture而不触发目标加载,在 asnqcap 命令中指定所有 FFFF

asnqcap CAPTURE_SERVER=db2a CAPTURE_SCHEMA=asn LSN=FFFF:FFFF:FFFF:FFFF:FFFF MAXCMTSEQ=FFFF:FFFF:FFFF:FFFF:FFFF
4.7 进行Q Capture跟踪

使用 asntrc 命令进行Q Capture跟踪,需要在启动Q Capture之前打开跟踪:

asntrc on -db db2a -schema asn -qcap

然后启动Q Capture:

start asnqcap capture_server=DB2A startmode=cold

等待问题出现后,获取跟踪格式和跟踪流:

asntrc fmt -db db2a -schema asn -qcap > trc.fmt
asntrc flw -db db2a -schema asn -qcap > trc.flw

关闭跟踪:

asntrc off -db db2a -schema asn -qcap

可以使用任何文本编辑器查看跟踪输出:

notepad trc.flw
5. Q Apply管理
5.1 Q Apply的主要任务
  • 识别Q订阅是否准备好处理。
  • (如果指定)对目标表进行完全刷新。
  • 将新更改从接收队列复制到目标表。
5.2 启动Q Apply

使用 asnqapp 命令启动Q Apply,该命令有众多参数,具体如下表所示:
| 参数 | 描述 |
| ---- | ---- |
| APPLY_PATH= | Q Apply工作文件的位置。 |
| APPLY_SCHEMA=ASN | 用于标识Q Apply的模式名称。 |
| APPLY_SERVER=DB2DBDFT | Q Apply控制服务器的名称。 |
| APPLYUPTO | Q Apply应用到指定时间戳后停止,该时间戳必须以格林威治标准时间(GMT)的完整或部分时间戳指定。如果使用该参数,应将心跳间隔设置为大于零的值,以便Q Apply能判断是否已过 APPLYUPTO 时间。 |
| AUTOSTOP=Y|N | 所有队列清空后终止Q Apply。 |
| BUFFERED_INSERTS=Y/N | 指定Q Apply是否使用缓冲插入,这在某些分区数据库中可以提高性能。 |
| CLASSIC_LOAD_FILE_SZ=500,000 | 经典加载文件大小。 |
| COMMIT_COUNT= |1 | 指定每个Q Apply代理线程在一个提交范围内应用到目标表的事务数量。 |
| DEADLOCK_RETRIES=n|3 | SQL死锁错误的重试次数。 |
| DFTMODELQ | 指定Q Apply使用的模型队列名称,而不是 IBMQREP.SPILL.MODELQ 。 |
| DIAGLOG=Y|N | 将消息发送到日志文件(在V9.7.1中已弃用)。 |
| IGNBADDATA=Y|N | 对于联邦目标,指定Q Apply是否检查源数据中的非法字符(如果源和目标的代码页不同),并在发现非法字符时继续处理。 |
| INSERT_BIDI_SIGNAL=N|Y | 指定Q Capture和Q Apply是否使用 P2PNORECAPTURE 信号插入来防止双向复制中事务的重新捕获。 |
| LOADCOPY_PATH | 在HADR配置中,当主服务器由Q Apply调用DB2 LOAD实用程序加载时使用该参数。设置该参数会提示Q Apply启动LOAD实用程序,并在指定路径中创建加载数据的副本,HADR配置中的辅助服务器将在该路径中查找复制的数据。 |
| LOAD_DATA_BUFF_SZ=n|8 | 与多维集群(MDC)表一起使用,指定DB2 LOAD实用程序在初始加载目标表时用于在实用程序内传输数据的4KB页面数量,该参数仅适用于使用DB2 LOAD实用程序的自动加载。 |
| LOGREUSE=Y|N | 重用或追加消息到日志文件。 |
| LOGSTDOUT=Y|N | 将消息发送到标准输出。 |
| MAX_PARALLEL_LOADS=n|15 | 指定Q Apply对于给定接收队列可以同时启动的目标表自动加载操作的最大数量。 |
| MONITOR_INTERVAL=n|300 | 插入监控表的间隔时间(秒)。 |
| MONITOR_LIMIT=n|10080 | 监控表行可清理的时间(分钟)。 |
| NICKNAME_COMMIT_CT=n|10 | 指定在加载过程中,导入实用程序对引用目标表的昵称提交更改的行数,该参数仅适用于联邦目标的自动加载,必须使用导出和导入实用程序。 |
| P2P_2NODES= Y|N | 该参数允许Q Apply在仅有两个活动服务器的点对点配置中优化性能,通过不将冲突删除记录到 IBMQREP_DELTOMB 表中。仅在具有两个活动服务器的点对点复制中使用 p2p_2nodes = y 设置。 |
| PRUNE_INTERVAL=n|300 | Q Apply尝试清理控制表的间隔时间(秒)。 |
| PWDFILE=asnpwd.aut | 密码文件的名称。 |
| QMGR | 队列管理器名称。 |
| RICHKLVL=0|2|5 | 指定引用完整性检查的级别,默认情况下,Q Apply检查事务之间基于RI的依赖关系,以确保相关行按正确顺序应用。 |
| SKIPTRANS=” ” | 指定Q Apply不应基于事务ID应用一个或多个接收队列中的一个或多个事务。 |
| SPILL_COMMIT_COUNT=n|10 | 指定Q Apply溢出代理在加载操作期间复制数据时在一个提交范围内分组的行数。 |
| SQL_CAP_SCHEMA | SQL捕获模式。 |
| TERM=Y|N | 如果DB2终止,则终止Q Apply。 |
| TRACE_LIMIT=n|10080 | 跟踪表行可清理的时间(分钟)。 |

启动Q Apply的最小信息是Q Apply控制表的位置(如DB2B),通常还会指定Q Apply模式(默认为ASN)和Q Apply日志路径/密码文件位置。示例命令如下:

asnqapp APPLY_SERVER=db2b APPLY_PATH="C:\TEMP" 
5.3 查看Q Apply启动参数

有两种方式查看Q Apply启动时的参数:
- 查询 IBMQREP_APPLYPARMS 控制表,使用相关SQL查询。
- 使用 asnqacmd 命令的 qryparms 选项, asnqacmd 命令的格式为:

asnqacmd [<parameter>=<value> ...] [command]

可能的参数包括:
- APPLY_SCHEMA= :用于标识Q Apply的模式名称。
- APPLY_SERVER= :Q Apply控制服务器的名称。
- LOGSTDOUT=Y|N :将消息发送到标准输出。

可能的命令包括:
- CHGPARMS :更改Q Apply的操作参数。
- PRUNE :清理Q Apply的控制表。
- QRYPARMS :查询Q Apply的操作参数。
- REINITQ :如果队列处于活动状态,刷新队列的参数。
- STATUS :查询Q Apply线程的状态。
- STATUS SHOW DETAILS :查询Q Apply的增强状态。
- STARTQ :开始处理队列中的消息。
- STOP :停止Q Apply。
- STOPQ :停止处理队列中的消息。
- TRCSTART :开始将程序流信息写入Q Apply跟踪缓冲区(在V9.7中已弃用)。

综上所述,Q Capture和Q Apply在数据复制和管理中起着重要作用,通过合理使用相关命令和参数,可以实现高效的数据处理和管理。在实际应用中,需要根据具体需求和场景,灵活运用这些技术和方法,以确保数据的准确复制和传输。同时,要注意日志管理和参数设置,避免出现问题影响系统的正常运行。

Q Capture与Q Apply管理全解析

6. Q Apply管理操作示例

下面通过具体的示例,进一步展示如何使用 asnqapp asnqacmd 命令进行Q Apply的管理操作。

6.1 启动Q Apply示例

假设我们要启动Q Apply,指定控制服务器为 db2b ,工作文件路径为 C:\TEMP ,模式为 ASN ,启动命令如下:

asnqapp APPLY_SERVER=db2b APPLY_SCHEMA=ASN APPLY_PATH="C:\TEMP"
6.2 查询Q Apply参数示例

若要查询Q Apply的操作参数,可使用 asnqacmd 命令的 QRYPARMS 选项:

asnqacmd APPLY_SERVER=db2b APPLY_SCHEMA=ASN QRYPARMS
6.3 更改Q Apply参数示例

若要将Q Apply的 monitor_interval 参数更改为20秒,使用 asnqacmd 命令的 CHGPARMS 选项:

asnqacmd APPLY_SERVER=db2b APPLY_SCHEMA=ASN CHGPARMS monitor_interval=20
6.4 停止Q Apply示例

停止Q Apply可使用 asnqacmd 命令的 STOP 选项:

asnqacmd APPLY_SERVER=db2b APPLY_SCHEMA=ASN STOP
7. Q Capture与Q Apply管理流程总结

为了更清晰地展示Q Capture和Q Apply的管理流程,下面给出相应的流程图。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px

    A([开始]):::startend --> B{选择操作对象}:::decision
    B -->|Q Capture| C(获取重启队列信息):::process
    B -->|Q Apply| D(确定控制表位置):::process
    C --> E(启动Q Capture):::process
    D --> F(启动Q Apply):::process
    E --> G(管理运行中的Q Capture):::process
    F --> H(管理运行中的Q Apply):::process
    G --> I{是否需要修改参数}:::decision
    H --> J{是否需要修改参数}:::decision
    I -->|是| K(修改Q Capture参数):::process
    J -->|是| L(修改Q Apply参数):::process
    I -->|否| M(监控Q Capture状态):::process
    J -->|否| N(监控Q Apply状态):::process
    K --> M
    L --> N
    M --> O([结束]):::startend
    N --> O
8. 常见问题及解决方法

在使用Q Capture和Q Apply的过程中,可能会遇到一些常见问题,下面给出相应的解决方法。

8.1 Q Capture启动失败且未创建日志文件
  • 问题描述 :尝试启动Q Capture,但未在相应目录创建日志文件,Q Capture未能正常启动。
  • 解决方法 :检查是否有有效的InfoSphere复制服务器许可证。
8.2 Q Apply在处理事务时出现错误
  • 问题描述 :Q Apply在复制新更改到目标表时出现错误,如SQL错误、数据格式错误等。
  • 解决方法
    1. 检查 QAPP.LOG 日志文件,查看详细的错误信息。
    2. 根据错误信息,检查源表和目标表的结构是否一致,数据类型是否匹配。
    3. 若涉及数据格式问题,检查 IGNBADDATA 参数设置,可尝试将其设置为 Y 以忽略非法字符。
8.3 日志文件过大问题
  • 问题描述 :Q Capture和Q Apply的日志文件不断增大,占用大量磁盘空间。
  • 解决方法
    1. 定期重命名日志文件,在重命名前需停止Q Capture和Q Apply。
    2. 可以编写脚本,在系统空闲时自动执行日志文件重命名操作。
9. 总结

Q Capture和Q Apply是数据复制和管理的重要工具,通过命令行方式可以灵活地对它们进行管理。在使用过程中,需要熟悉各个命令和参数的含义,根据实际需求进行合理配置。同时,要注意日志管理和常见问题的解决方法,以确保系统的稳定运行。

在启动Q Capture和Q Apply时,要提供必要的信息,如控制表位置、模式、日志路径等。在管理运行中的Q Capture和Q Apply时,可以使用相应的命令修改参数、查询状态、清理控制表等。通过合理设置参数,可以优化Q Capture和Q Apply的性能,提高数据处理效率。

希望本文的内容能帮助你更好地理解和使用Q Capture和Q Apply,在实际应用中充分发挥它们的优势,实现高效的数据复制和管理。

import os from glob import glob import cv2 import matplotlib import matplotlib.pyplot as plt import numpy as np from joblib import Parallel, delayed from PIL import Image, ImageDraw, ImageFont from utils.function import (XYZ2BT2020_MAT, XYZ2P3_MAT, XYZ2SRGB_MAT, adjust_saturation_hisi_CA, get_cross_dimension) from utils.gamma_opt import gamma_hlg, gamma_ns from utils.parse import LSC_OSR, HistoryFrame, ImageInfo, QImageInfo from utils.xstyle_ce_opt import CESimulator from utils.xstyle_lut_opt import apply_lut3d matplotlib.use("Agg") os.chdir(os.path.dirname(__file__)) def process(image_info: ImageInfo, qimage_info: QImageInfo, lightness:float): picture_dict = {} # 1 HVM mscStats @ msc2xyz @ caMat @ LCH @ gamma simu_msc2xyz = (get_cross_dimension(image_info.msc_golden_raw.clip(0, None)) @ image_info.msc2xyz_mat).reshape(-1, 3) simu_msc2xyz = adjust_saturation_hisi_CA(simu_msc2xyz, image_info.hvm_xy1) simu_msc2xyz /= (simu_msc2xyz.max() * lightness) simu_msc2xyz = (simu_msc2xyz @ image_info.color_space_trans_mat).clip(0, 1).reshape(48, 64, 3) simu_msc2xyz_nonlinear = image_info.gamma(simu_msc2xyz).clip(0, 1) picture_dict["p1"] = np.rot90(simu_msc2xyz_nonlinear, image_info.config['msc_rotation']) # 考虑 MSC 倒装的情况 picture_dict['p1_name'] = 'P1 MSC目标效果(HVM)' picture_dict['p1_description'] = 'mscStats @ msc2xyz @ caMat @ LCH @ gamma' # if image_info.cam_type == 'tele': # msc_xyz_pipe = (image_info.msc_xyz_pipe @ image_info.color_space_trans_mat).clip(0, 1).reshape(48, 64, 3) # pipe_msc2xyz_nonlinear = image_info.gamma(msc_xyz_pipe).clip(0, 1) # if np.sum(msc_xyz_pipe) > 0: # picture_dict["p1"] = np.rot90(pipe_msc2xyz_nonlinear, image_info.config['msc_rotation']) # 考虑 MSC 倒装的情况 # simu_msc2xyz = msc_xyz_pipe # 2 CT 3*3 mscStats @ msc2cam @ baseCT_cam2XYZ @ gamma simu_msc2cam_CT = (get_cross_dimension( (image_info.msc_golden_raw @ image_info.msc2cam_basect).clip(0, None).reshape(-1, 3)) @ image_info.cam2std_basect).clip(0, None) simu_msc2cam_CT = (simu_msc2cam_CT @ image_info.color_space_trans_mat).clip(0, 1).reshape(48, 64, 3) simu_msc2cam_CT *= (simu_msc2xyz.mean() / simu_msc2cam_CT.mean()) simu_msc2cam_CT_nonlinear = image_info.gamma(simu_msc2cam_CT).clip(0, 1) # picture_dict["p2_divcc3x3"] = divide_matrix((image_info.cam2std @ image_info.ca_mat.T @ image_info.color_space_trans_mat).T) if len(image_info.history_frame.face_pos_left_top_x) > 0: try: coordinate = [image_info.history_frame.face_pos_left_top_x[-1] / 2, image_info.history_frame.face_pos_left_top_y[-1] / 2, image_info.history_frame.face_pos_width[-1] / 2, image_info.history_frame.face_pos_height[-1] / 2] h1, h2 = int((coordinate[1] - 14) / 7), int((coordinate[1] + coordinate[3] - 14) / 7) w1, w2 = int((coordinate[0] - 20) / 7), int((coordinate[0] + coordinate[2] - 20) / 7) simu_msc2cam_CT_nonlinear[h1 : h2 + 0, w1] = [1, 0, 0] simu_msc2cam_CT_nonlinear[h1 : h2 + 0, w2] = [1, 0, 0] simu_msc2cam_CT_nonlinear[h1, w1 : w2 + 0] = [1, 0, 0] simu_msc2cam_CT_nonlinear[h2, w1 : w2 + 0] = [1, 0, 0] #---# 人脸区域提亮处理 # simu_msc2cam_CT_nonlinear[h1:h2, w1:w2] = (simu_msc2cam_CT_nonlinear[h1:h2, w1:w2] * 1.5).clip(0, 1) simu_msc2cam_CT_nonlinear[h1:h2, w1:w2] /= (simu_msc2cam_CT_nonlinear[h1 + 0 : h2, w1 + 0 : w2].max() / 1.5) except: pass picture_dict["p2"] = np.rot90(simu_msc2cam_CT_nonlinear, image_info.config['msc_rotation']) # 考虑 MSC 倒装的情况 picture_dict['p2_name'] = 'P2 虚拟CAM,baseCT效果' picture_dict['p2_description'] = '(mscStats @ msc2cam) @ cam2xyz @ gamma' # 3 baseCT 3*6 camStats @ baseCT_cam2XYZ @ gamma simu_baseCT = ((get_cross_dimension(image_info.cam_golden_raw.clip(0, None)) @ image_info.cam2std_basect).clip(0, None)) simu_baseCT = (simu_baseCT @ image_info.color_space_trans_mat).clip(0, 1).reshape(64, 64, 3) simu_baseCT *= (simu_msc2xyz.mean() / simu_baseCT.mean()) simu_baseCT_nonlinear = image_info.gamma(simu_baseCT).clip(0, 1) picture_dict["p3"] = simu_baseCT_nonlinear picture_dict["p3_name"] = "P3 真实CAM,baseCT效果" picture_dict["p3_description"] = "camGoldenStats @ cam2xyz_baseCT @ gamma" # 3 baseCT 3*6 camStats @ baseCT_cam2XYZ @ gamma: test # curr_cam2std_basect = np.array([0.70212766,0.14216634,-0.1615087, # -0.11035156,0.67480469,-0.89160156, # 0.35798817, -0.13510848, 2.55325444, 0.05150692, 0.18464747, # -0.4120554 , 0.16797676, 0.01757896, 0.67288365, # 0.0637888 ,-0.03140371, 1.26203678]).reshape(6, 3) # simu_baseCT = ((get_cross_dimension(image_info.cam_golden_raw.clip(0, None)) @ curr_cam2std_basect).clip(0, None)) # # print(image_info.cam2std_basect) # simu_baseCT = (simu_baseCT @ image_info.color_space_trans_mat).clip(0, 1).reshape(64, 64, 3) # simu_baseCT *= (simu_msc2xyz.mean() / simu_baseCT.mean()) # simu_baseCT_nonlinear = image_info.gamma(simu_baseCT).clip(0, 1) # picture_dict["p3"] = simu_baseCT_nonlinear # picture_dict["p3_name"] = "P3 真实CAM,baseCT效果,Jock" # picture_dict["p3_description"] = "camGoldenStats @ cam2xyz_baseCT @ gamma" # 4 refCT camGoldenStats @ cam2std_refCT @ gamma cam_refCT = (get_cross_dimension(image_info.cam_golden_raw.clip(0, None).reshape(-1, 3)) @ image_info.cam2std_refct).clip(0, None) cam_refCT = (cam_refCT @ image_info.color_space_trans_mat).clip(0, 1).reshape(64, 64, 3) cam_refCT *= (simu_msc2xyz.mean() / cam_refCT.mean()) cam_refCT_nonlinear = image_info.gamma(cam_refCT).clip(0, 1) picture_dict["p4"] = cam_refCT_nonlinear picture_dict["p4_name"] = "P4 真实CAM,refCT效果" picture_dict["p4_description"] = "camGoldenStats @ cam2xyz_refCT @ gamma" # 5 带滤波cam效果 camStats @ pipe_awb_filter @ algo_hdcc @ gamma cam_filter = get_cross_dimension((image_info.cam_raw.reshape(-1, 3) * image_info.pipe_awb_filter).clip(0, 1)) cam_filter = (cam_filter @ image_info.algo_ccm).reshape(64, 64, 3).clip(0, 1) cam_filter *= (simu_msc2xyz.mean() / cam_filter.mean()) cam_filter_nonlinear = image_info.gamma(cam_filter).clip(0, 1) picture_dict["p5"] = cam_filter_nonlinear picture_dict['p5_name'] = 'P5 真实CAM,ISP滤波' picture_dict['p5_description'] = 'camStats @ pipe_awb_filter @ algo_hdcc @ gamma' # 6 带ccgm的cam效果 camStats @ pipe_awb_filter @ pipe_hdcc @ gamma cam_ccgm = get_cross_dimension((image_info.cam_raw.reshape(-1, 3) * image_info.pipe_awb_filter).clip(0, 1)) cam_ccgm = (cam_ccgm @ image_info.pipe_ccm).reshape(64, 64, 3).clip(0, 1) cam_ccgm *= (simu_msc2xyz.mean() / cam_ccgm.mean()) cam_ccgm_nonlinear = image_info.gamma(cam_ccgm).clip(0, 1) picture_dict["p6"] = cam_ccgm_nonlinear picture_dict["p6_name"] = 'P6 真实CAM,CCGM后' picture_dict["p6_description"] = 'camStats @ pipe_awb_filter @ pipe_hdcc @ gamma' xstyle_ce_opt = CESimulator() # 预览 # 1. xstyle on: 预览BE + sync-lut + xstyle-lut + xstyle-ce # 2. xstyle off: 预览BE + sync-lut + real-lut + xstyle-ce if qimage_info.preview_be is not None: picture_dict['p7'] = qimage_info.preview_be picture_dict['p7_name'] = 'P7 预览,LUT前的效果' picture_dict['p7_description'] = 'rawNR(rdp) + awb + hdcc + aitm' if qimage_info.lut_sync is not None: preview_be_synclut = apply_lut3d(qimage_info.preview_be, qimage_info.lut_sync) picture_dict['p8'] = preview_be_synclut picture_dict['p8_name'] = 'P7 预览,DytoneSync效果' picture_dict['p8_description'] = 'P7 + sync-lut' if qimage_info.xstyle_enable and qimage_info.xstyle_enable != 'unknown': if qimage_info.lut_xstyle is not None: preview_be_xstylelut = apply_lut3d(qimage_info.preview_be, qimage_info.lut_xstyle) picture_dict['p9'] = preview_be_xstylelut picture_dict['p9_name'] = 'P8 预览,XStyle-Lut效果' picture_dict['p9_description'] = 'P7 + xstyle-lut' else: if qimage_info.lut_real is not None: preview_be_reallut = apply_lut3d(qimage_info.preview_be, qimage_info.lut_real) picture_dict['p9'] = preview_be_reallut picture_dict['p9_name'] = 'P8 预览,真实性Lut效果' picture_dict['p9_description'] = 'P7 + real-lut' if qimage_info.lut_pre is not None: preview_be_lut = apply_lut3d(qimage_info.preview_be, qimage_info.lut_pre) picture_dict['p10'] = preview_be_lut picture_dict['p10_name'] = 'P10 预览,final-lut效果' picture_dict['p10_description'] = 'P7 + final-lut' if qimage_info.xstyle_enable and qimage_info.xstyle_enable != 'unknown' and qimage_info.scene_type not in ['flower', 'plants']: _preview_be_lut_ce = xstyle_ce_opt.forward(qimage_info.ce_data, preview_be_lut, None) picture_dict['p11'] = _preview_be_lut_ce # 预览 + final_lut + xstyle_yuv picture_dict['p11_name'] = 'P11 预览,XStyle后的效果' picture_dict['p11_description'] = 'P10 + xstyle-ce' # 预览 dytonesync if qimage_info.dytonesync_ref is not None: picture_dict['p12'] = qimage_info.dytonesync_ref # 输入dytoneSync的红枫小图, cap/sdr -> P3,CUVA -> BT2020 picture_dict['p12_name'] = 'P12 MSC目标效果(DytoneSync)' picture_dict['p12_description'] = 'mscRaw + ...(Preprocess)' picture_dict['p13'] = qimage_info.dytonesync_input # 输入dytoneSync的预览小图, cap/sdr -> P3,CUVA -> BT2020 picture_dict['p13_name'] = 'P13 预览(小),DytoneSync前' picture_dict['p13_description'] = 'P7 + ...(Preporcess)' _dytonesync_input_synclut = apply_lut3d(qimage_info.dytonesync_input, qimage_info.lut_sync) picture_dict['p14'] = _dytonesync_input_synclut picture_dict['p14_name'] = 'P14 预览(小),DytoneSync后' picture_dict['p14_description'] = 'P13 + sync-lut' # 拍照: # 1. 没有打开拍照dytonesync # 未进入Net2:拍照BE + lutcap + xstyle-ce # 进入Net2:拍照BE + Net2 # 2. 打开拍照dytonesync # 未进入Net2:拍照BE + sync-lut(cap) + lutpre + xstyle-ce # 进入Net2:拍照BE + sync-lut(cap) + sync-lut(pre) + Net2 if qimage_info.capture_be is not None: picture_dict["p15"] = qimage_info.capture_be picture_dict["p15_name"] = 'P15 拍照,AirawIspIn的效果' picture_dict['p15_description'] = 'MEF + awb + hdcc + aitone-net1' if qimage_info.dycap_merged_lut is not None: if 'net2yuv' in qimage_info.model_name_version: capture_be_mergelut = apply_lut3d(qimage_info.capture_be, qimage_info.dycap_merged_lut) picture_dict['p16'] = capture_be_mergelut picture_dict['p16_name'] = 'P16 拍照,DytoneSync红枫效果' picture_dict['p16_description'] = 'P15 + sync-msc-lut' else: capture_be_synclut = apply_lut3d(qimage_info.capture_be, qimage_info.dycap_sync_lut) picture_dict['p16'] = capture_be_synclut picture_dict['p16_name'] = 'P16 拍照,DytoneSync预览效果' picture_dict['p16_description'] = 'P15 + sync-pre-lut' if qimage_info.lut_pre is not None: capture_be_synclut_lut = apply_lut3d(capture_be_synclut, qimage_info.lut_pre) picture_dict['p17'] = capture_be_synclut_lut picture_dict['p17_name'] = 'P17 拍照,final-lut效果' picture_dict['p17_description'] = 'P15 + final-lut' if qimage_info.xstyle_enable and qimage_info.xstyle_enable != 'unknown' and qimage_info.scene_type not in ['flower', 'plants']: capture_be_synclut_lut_ce = xstyle_ce_opt.forward(qimage_info.ce_data, capture_be_synclut_lut, None) picture_dict['p18'] = capture_be_synclut_lut_ce picture_dict['p18_name'] = 'P18 拍照,XStyle后的效果' picture_dict['p18_description'] = 'P17 + xstyle-ce' else: if 'net2yuv' not in qimage_info.model_name_version and qimage_info.lut_cap is not None: capture_be_lut = apply_lut3d(qimage_info.capture_be, qimage_info.lut_cap) picture_dict['p17'] = capture_be_lut picture_dict['p17_name'] = 'P17 拍照,final-lut效果' picture_dict['p17_description'] = 'P15 + final-lut' if qimage_info.xstyle_enable and qimage_info.xstyle_enable != 'unknown' and qimage_info.scene_type not in ['flower', 'plants']: capture_be_lut_ce = xstyle_ce_opt.forward(qimage_info.ce_data, capture_be_lut, None) picture_dict['p18'] = capture_be_lut_ce # capture + final_lut + xstyle_yuv picture_dict['p18_name'] = 'P18 拍照,XStyle后的效果' picture_dict['p18_description'] = 'P17 + xstyle-ce' # RGB2YUV 出图 if qimage_info.captureOut is not None: picture_dict["p16"] = qimage_info.captureOut picture_dict['p16_name'] = 'P16 拍照,airawRgb2yuvOut的效果' picture_dict['p16_description'] = 'P15 + RGB2YUV Process' # 拍照 net2 出图 if qimage_info.rgb_net2 is not None: picture_dict["p18"] = qimage_info.rgb_net2 picture_dict['p18_name'] = 'P18 拍照,Net2/LUT3D后的效果' picture_dict['p18_description'] = 'P16 + net2/LUT3D, or rather, YuvEnhance or FaceSr' return picture_dict def process_line_graph(lo: LSC_OSR, hf: HistoryFrame): plt.figure(figsize=[12, 10]) # LSC-OSR draw osr_spectral lsc_spectral compare lp1 = plt.subplot2grid((4, 2), (0, 0), rowspan=2) lp1.plot(np.linspace(380, 780, 81), lo.lsc_spectral, linewidth=2, color="#FF8C00") lp1.plot(np.linspace(380, 780, 81), lo.osr_spectral, linewidth=2, color="#008B8B") lp1.set_xlabel("wavelength, lightType = {:.2f}, {:.2f}, {:.2f}".format(lo.osr_weight[0], lo.osr_weight[1], lo.osr_weight[2])) lp1.legend(["lsc spectra", "osr spectra"]) # 历史帧msc ae lp2 = plt.subplot2grid((4, 2), (0, 1)) x = np.linspace(1, hf.n_frame, hf.n_frame) lp2.plot(x, hf.expo / (hf.expo.max() + 0.001), linewidth=1, marker=".", markersize=10, color="#FF8C00") lp2.plot(x, hf.iso / (hf.iso.max() + 0.001), linewidth=1, marker=".", markersize=10, color="#008B8B") lp2.plot(x, hf.lv / (hf.lv.max() + 0.001), linewidth=1, marker=".", markersize=10, color="#6A5ACD") lp2.legend(["expo", "iso", "lv"]) lp2.set_xlabel( f"mscAE: expo_max = {hf.expo.max()}, iso_max = {hf.iso.max()}, lv_max = {hf.lv.max()}") # 历史帧msc2cam lp3 = plt.subplot2grid((4, 2), (1, 1)) lp3.plot(x, hf.msc2main, linewidth=1, marker=".", markersize=10, color="#FF8C00") lp3.plot(x, hf.msc2wide, linewidth=1, marker=".", markersize=10, color="#008B8B") lp3.plot(x, hf.msc2tele, linewidth=1, marker=".", markersize=10, color="#6A5ACD") lp3.set_xlabel("baseCT: msc2cam first element") lp3.legend(["main", "wide", "tele"]) # 历史帧 大直方图均值 小直方图高亮区域的当前均值和target # lp3 = plt.subplot2grid((4, 2), (1, 1)) # lp3.plot(np.linspace(1, len(hf.avg_val), len(hf.avg_val)), hf.avg_val, linewidth=1, marker=".", markersize=10, color="#FF8C00") # lp3.plot(np.linspace(1, len(hf.cur_lum), len(hf.cur_lum)), hf.cur_lum, linewidth=1, marker=".", markersize=10, color="#008B8B") # lp3.plot(np.linspace(1, len(hf.tar_lum), len(hf.tar_lum)), hf.tar_lum, linewidth=1, marker=".", markersize=10, color="#6A5ACD") # lp3.legend(["histAveragevalue", "histCurlum", "histTarlum"]) # lp3.set_xlabel("mscAE: histAveragevalue, histCurlum, histTarlum") # 历史帧hvm XZ 计算cct duv lp4 = plt.subplot2grid((4, 2), (2, 0)) Y = np.array([1.00] * hf.hvm_cct.shape[0]) lp4.plot(x, hf.hvm_cct / hf.hvm_cct.max(), linewidth=1, marker=".", markersize=10, color="#FF8C00") lp4.plot(x, hf.hvm_duv / hf.hvm_duv.max(), linewidth=1, marker=".", markersize=10, color="#008B8B") lp4.legend(["cct", "duv"]) lp4.set_xlabel(f"HVM: cct_max = {hf.hvm_cct.max():.1f}, duv_max = {np.abs(hf.hvm_duv).max():.4f}") # 历史帧refCT lp5 = plt.subplot2grid((4, 2), (3, 0)) lp5.plot(x, hf.refct_l, linewidth=1, marker=".", markersize=10, color="#FF8C00") lp5.plot(x, hf.refct_m, linewidth=1, marker=".", markersize=10, color="#008B8B") lp5.plot(x, hf.refct_s, linewidth=1, marker=".", markersize=10, color="#6A5ACD") lp5.legend(["l", "m", "s"]) lp5.set_xlabel("refCT: lms gain") # 历史帧awb lp6 = plt.subplot2grid((4, 2), (2, 1)) x = np.linspace(1, hf.awb_rgbg.shape[0], hf.awb_rgbg.shape[0]) lp6.plot(x, hf.awb_rgbg[:, 0], linewidth=1, marker="o", markerfacecolor='w', color="#FF8C00") lp6.plot(x, hf.awb_rgbg_filtered[:, 0], linewidth=1, marker=".", markersize=10, color="#008B8B") lp6.legend(["before", "after"], prop={"size": 8}) lp6.set_xlabel("SIA filter - Rgain") lp7 = plt.subplot2grid((4, 2), (3, 1)) lp7.plot(x, hf.awb_rgbg[:, 1], linewidth=1, marker="o", markerfacecolor='w', color="#FF8C00") lp7.plot(x, hf.awb_rgbg_filtered[:, 1], linewidth=1, marker=".", markersize=10, color="#008B8B") lp7.legend(["before", "after"], prop={"size": 8}) lp7.set_xlabel("SIA filter - Bgain") plt.tight_layout() line_picture = plt.gcf() line_picture.canvas.draw() line = np.array(line_picture.canvas.renderer.buffer_rgba())[...,0:3] plt.close() return line def draw(jpg_path, save_path, picture_dict: dict, image_info: ImageInfo, qimage_info: QImageInfo): # 读取原始图像 image = plt.imread(jpg_path)[::3, ::3] # 色域转换 if "hdrvivid" in image_info.pq_info: image_linear = gamma_hlg(image / 255.0, degamma=True) image_xyz = image_linear @ np.linalg.inv(XYZ2P3_MAT) image_linear_2020 = image_xyz @ XYZ2BT2020_MAT image = (image_info.gamma(image_linear_2020) * 255.0).astype('uint8') elif "standardvideo" in image_info.pq_info: image_linear = gamma_ns(image / 255.0, degamma=True) image_xyz = image_linear @ np.linalg.inv(XYZ2P3_MAT) image_linear_srgb = image_xyz @ XYZ2SRGB_MAT image = (image_info.gamma(image_linear_srgb) * 255.0).astype('uint8') else: image = image tiny_image_rot = True if image.shape[0] > image.shape[1] else False # 基础参数配置 h, w, c = 1451, 1931, 3 hist_h, hist_w = 1120, 1340 tiny_row, tiny_col = len(image_info.config['pic_plot']), max(len(_) for _ in image_info.config['pic_plot']) tiny_row_gap, tiny_col_gap = 60, 5 tiny_w = ((w + hist_w) - (tiny_col - 1) * tiny_col_gap) // tiny_col tiny_h = int(tiny_w / 1.33) imageLarge = (np.ones([h + (tiny_h + tiny_row_gap) * tiny_row, w + hist_w, c])).astype(np.uint8) font = ImageFont.truetype("arial.ttf", size=15) # 设置字体样式及大小 font_c = ImageFont.truetype("simsun.ttc", size=25) color = (255, 255, 0) # 文本颜色(RGB格式) # image = cv2.resize(image, (w, h)) imageLarge[:h, :w] = image # 曲线图 imageLarge[0: hist_h, w : w + hist_w ] = cv2.resize(picture_dict['line'], (hist_w, hist_h)) def paste_tiny_image(r, c, i): tiny_img: np.ndarray = picture_dict.get(f"p{i}", None) if tiny_img is not None and not np.isnan(tiny_img).any(): if qimage_info.res_rotation != "unknown": if qimage_info.res_rotation == 14: tiny_img = np.rot90(tiny_img, -3) else: tiny_img = np.rot90(tiny_img, -qimage_info.res_rotation // 90) else: if tiny_image_rot: tiny_img = np.rot90(tiny_img, -1) tiny_img = cv2.resize(tiny_img.clip(0, 1), (tiny_w, tiny_h)).clip(0, 1) imageLarge[ h + (r - 1) * (tiny_h + tiny_row_gap): h + (r - 1) * (tiny_h + tiny_row_gap) + tiny_h, (tiny_w + tiny_col_gap) * (c - 1): (tiny_w + tiny_col_gap) * (c - 1) + tiny_w, ] = (tiny_img * 255).astype(np.uint8) # def paste_tiny_image(r, c, i): # tiny_img: np.ndarray = picture_dict.get(f'p{i}', None) # if tiny_img is not None and not np.isnan(tiny_img).any(): # if tiny_image_rot: # tiny_img = np.rot90(tiny_img, -1) # tiny_img = cv2.resize(tiny_img.clip(0, 1), (tiny_w, tiny_h)).clip(0, 1) # imageLarge[h + (r - 1) * (tiny_h + tiny_row_gap) : h + (r - 1) * (tiny_h + tiny_row_gap) + tiny_h , (tiny_w + tiny_col_gap) * (c - 1): (tiny_w + tiny_col_gap) * (c - 1) + tiny_w] = (tiny_img * 255).astype(np.uint8) for r in range(0, tiny_row): for c, i in enumerate(image_info.config['pic_plot'][r]): paste_tiny_image(r + 1, c + 1, i) imageLarge = Image.fromarray(imageLarge) draw = ImageDraw.Draw(imageLarge) # 在图像上添加文本 def draw_tiny_text(s1: str, s2: str, r, c): draw.text(((tiny_w + tiny_col_gap) * (c - 1) + tiny_w // 2 - draw.textlength(s1, font=font_c) // 2, h + (tiny_h + tiny_row_gap) * (r - 1) + tiny_h + 2), s1, font=font_c, color=color, fill=color) draw.text(((tiny_w + tiny_col_gap) * (c - 1) + tiny_w // 2 - draw.textlength(s2, font=font) // 2, h + (tiny_h + tiny_row_gap) * (r - 1) + tiny_h + 32), s2, font=font, color=color, fill=color) for r in range(0, tiny_row): for c, i in enumerate(image_info.config['pic_plot'][r]): draw_tiny_text(picture_dict.get(f'p{i}_name', ''), picture_dict.get(f'p{i}_description', ''), r + 1, c + 1) draw.text((10, 10), os.path.basename(jpg_path)[:-4], font=ImageFont.truetype("simsun.ttc", size=50), color=color, fill=color) text1 = ( """Camera: {:<4} -- ZOOM: {:<4} -- AI_enable: {:<4} -- AiType: {:<4} -- Capture_Mode: {:<4} -- XtCodeMode: {:<4} CAM - {:<12}: expo = {:<6.0f} us, iso = {:<6.0f}, fn = {:<6.2f}, expo_ratio = {:<6.2f} MSC - {:<12}: expo = {:<6.0f} us, iso = {:<6.0f}, lv = {:<6.0f}, lux = {:<6.2f}, raw_mean = {:6.2f} {:<70} SIA_D_A_LED_Prob = {:<1d},{:<1d},{:<1d} Tone_Net2 = {:<58} airaw_type = {:<12} Tone_Net1 = {:<58} AiRawV2PpAlgo = {:<54} ppalgo = {:<61} algo_refct_res = {:<4.4f},{:<4.4f},{:<4.4f} iso_speed = {:<58} pipe_refct_gain = {:<4d},{:<4d},{:<4d} highSatCardNum = {:<.0f},{:<.0f},{:<.0f}{:3}redHighSatCnt = {:<.0f},{:<.0f},{:<.0f}{:3}blueHighSatCnt = {:<.0f},{:<.0f},{:<.0f}{:3}purpleHighSatCnt = {:<.0f},{:<.0f},{:<.0f}{:3} hvm_cct0 = {:4.0f}K, hvm_duv0 = {:8.4f}{:9}algo_awb = {:<4.0f},{:<4.0f},{:<4.0f}{:14}ccm_com_vector = {:<3d},{:<3d},{:<3d} hvm_cct1 = {:4.0f}K, hvm_duv1 = {:8.4f}{:9}pipe_awb = {:<4.0f},{:<4.0f},{:<4.0f}{:14}ccm_com_weight = {:<3d},{:<3d},{:<3d} osr_cct = {:4.0f}K, osr_duv = {:8.4f}{:9}pipe_awb_filter = {:<4d},{:<4d},{:<4d}{:7}bv = {:<3d} msc2cam = {:8.4f},{:8.4f},{:8.4f}{:10}awb_otp = {:<4d},{:<4d},{:<4d} msc2xyz = {:8.4f},{:8.4f},{:8.4f} """.format( image_info.cam_type, qimage_info.zoom_ratio, str(qimage_info.masterAiEnable), str(qimage_info.masterAiType), str(qimage_info.Capture_Mode), str(qimage_info.XtCodeMode), image_info.cam_sensor_name, image_info.cam_expo, image_info.cam_iso, image_info.cam_fn, image_info.msc_expo * image_info.msc_iso / (1 + image_info.cam_expo * image_info.cam_iso), image_info.msc_sensor_name, image_info.msc_expo, image_info.msc_iso, image_info.msc_lv, 2 ** (image_info.msc_lv / 10 - 1), image_info.msc_raw_mean, '', *image_info.sia_light, qimage_info.model_name_version, qimage_info.airaw_type, qimage_info.model_name_version_net1, qimage_info.AiRawV2PpAlgo, image_info.pq_info[13:], *image_info.algo_refct_result, ','.join([str(i) for i in qimage_info.iso_speed]) if qimage_info.iso_speed else 'unknown', *image_info.refct_gain, image_info.highSatCardNum[0], image_info.highSatCardNum[1], image_info.highSatCardNum[2], '', image_info.redHighSatCnt[0], image_info.redHighSatCnt[1], image_info.redHighSatCnt[2], '', image_info.blueHighSatCnt[0], image_info.blueHighSatCnt[1], image_info.blueHighSatCnt[2], '', image_info.purpleHighSatCnt[0], image_info.purpleHighSatCnt[1], image_info.purpleHighSatCnt[2], '', image_info.hvm_cct0, image_info.hvm_duv0, ' ', *[1092 * _ for _ in image_info.algo_awb], ' ', *image_info.ccm_com_vec, image_info.hvm_cct1, image_info.hvm_duv1, ' ', *[1092 * _ for _ in image_info.pipe_awb], ' ', *image_info.ccm_com_weight, image_info.lsc_osr.osr_cct, image_info.lsc_osr.osr_duv, ' ', *[int(1092 * _) for _ in image_info.pipe_awb_filter], ' ', image_info.bv, image_info.msc2cam[0][0], image_info.msc2cam[0][1], image_info.msc2cam[0][2], ' ', *image_info.awb_otp, image_info.msc2xyz_mat[0][0], image_info.msc2xyz_mat[0][1], image_info.msc2xyz_mat[0][2], )) draw.text((w, hist_h + 10), text1, font=ImageFont.truetype("consola.ttf", size=22), color=color,fill=color) imageLarge.save(save_path, quality=100, dpi=(300, 300, 0)) def parse_image(idx, idx_end, image_path, save_path, phone, cam_type, lightness): print("[{:04d}/{:04d}] {}".format(idx, idx_end, image_path)) image_info = ImageInfo(image_path, phone, cam_type) qimage_info = QImageInfo(image_path) picture_dict = process(image_info, qimage_info, lightness) picture_dict['line'] = process_line_graph(image_info.lsc_osr, image_info.history_frame) jpg_save_name = os.path.join(save_path, os.path.splitext(os.path.basename(image_path))[0] + '_info.jpg') draw(image_path, jpg_save_name, picture_dict, image_info, qimage_info) def try_parse_image(_i,__i, _j, _p, __p, _c, _l): try: parse_image(_i,__i, _j, _p, __p, _c, _l) except Exception as e: print(e) if __name__ == "__main__": ''' ☆☆☆ 脚本详情: 1. 运行之前需要拿到 QTimeMachine v1.6.4 以上版本手动解析所有图获取airaw维测信息 2. 支持图像根据ppAlgoInfo自适应选择色域和相应 gamma (佳露提供) 3. 支持对LUT模块更精细的解析, 预览4个, 拍照2个 (连鹏提供) 4. 如果Q时光机解析不出来这个Xstyle文件或者是CLT平台,就只绘制拍照的aiRawIspIn和YuvEnhance图 5. 支持目前月亮舞台夕阳逻辑的维测适配 6. 添加预览 dytonesync 的三张维测小图,添加拍照 dytonesync 的 sync_msc_lut, 依赖于 QTimeMachine 解析的维测信息 7. 支持 config.yaml 中自定义配置图像摆放方式 8. 工具使用说明: https://wiki.huawei.com/domains/95501/wiki/163974/WIKI202412315590569 ''' # 数据路径 path0 = r"\\10.185.104.154\Cam_Pub\00.SKP_color_data\1_自测数据\KP长焦\1110-模型验证\QT" path1 = os.path.join(path0, 'simu_2.0.0') # 用于保存解析结果的路径 os.makedirs(path1, exist_ok=True) jpgs = glob(path0 + "/*.jpg") debug = False # 调试 parallel = False # 并行 phone_name = None # None: 根据文件名自动选择; 指定手机可使用: CLS, PLR, PLA,... cam_type = None # None: 根据维测信息自动读取,如果报错 "[error] parse.py LINE 278 ...", 需要自动添加模组匿名化在 config.yaml 的 modules 中,或者指定类型使用:main, wide, tele lightness = 0.9 # lightness 默认为1,可调整图1至图6的亮度, 建议纯色场景使用稍低的值如0.4, 其他普通场景可以设置为0.9, 高动态场景适当调高观察暗区 if debug: parse_image(1, 1, jpgs[0], path1, phone_name, cam_type, lightness) exit() if parallel: para = Parallel(n_jobs=16, backend='multiprocessing') para(delayed(try_parse_image)(idx + 1, len(jpgs), jpg, path1, phone_name, cam_type, lightness) for idx, jpg in enumerate(jpgs)) else: for idx, jpg in enumerate(jpgs): try_parse_image(idx + 1, len(jpgs), jpg, path1, phone_name, cam_type, lightness) 报了这个错误[error] parse.py LINE 278, THERE IS NO MATCHING MODULE NAME, ADD MODULE NAME IN config.yaml,请修改代码,出现这个错误时跳过,继续解析后面的图,不要停止程序
11-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值