├── test ├── __init__.py ├── components │ ├── __init__.py │ └── test_basic_image.py └── resource │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.png │ ├── 7.png │ ├── 8.png │ ├── 6月壁纸.jpg │ └── 星空背景 绘画 夜空 4k壁纸_彼岸图网.jpg ├── ui ├── __init__.py ├── yuvconfig.ui ├── yuvconfig.py ├── yuvviewer_window.ui └── yuvviewer_window.py ├── components ├── __init__.py ├── resource │ ├── add.png │ ├── up.png │ ├── 快进.png │ ├── 快退.png │ ├── down.png │ ├── main.ico │ ├── main.png │ ├── open.png │ ├── pause.png │ ├── right.png │ ├── start.png │ ├── stats.png │ ├── stop.png │ ├── compare.png │ ├── config.png │ ├── delete.png │ ├── restart .png │ ├── subtract.png │ └── save_icon.png ├── resource.qrc ├── status_code_enum.py ├── ui │ ├── help_window.ui │ ├── help_window.py │ ├── mainwindow.ui │ ├── mainwindow.py │ ├── histgramview.py │ └── histgramview.ui ├── logconfig.py ├── MatplotWidget.py ├── window.py ├── histview.py ├── BasicImage.py └── customwidget.py ├── requirements.txt ├── .gitignore ├── Pipfile ├── .vscode └── launch.json ├── ImageViewer.py ├── image_config.py ├── Readme.md ├── ImageViewer.iss ├── image_viewer.py └── resource_rc.py /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyside2 2 | numpy 3 | opencv-python==4.5.4.60 4 | natsort 5 | matplotlib -------------------------------------------------------------------------------- /test/resource/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/1.jpg -------------------------------------------------------------------------------- /test/resource/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/2.jpg -------------------------------------------------------------------------------- /test/resource/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/3.png -------------------------------------------------------------------------------- /test/resource/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/7.png -------------------------------------------------------------------------------- /test/resource/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/8.png -------------------------------------------------------------------------------- /test/resource/6月壁纸.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/6月壁纸.jpg -------------------------------------------------------------------------------- /components/resource/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/add.png -------------------------------------------------------------------------------- /components/resource/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/up.png -------------------------------------------------------------------------------- /components/resource/快进.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/快进.png -------------------------------------------------------------------------------- /components/resource/快退.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/快退.png -------------------------------------------------------------------------------- /components/resource/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/down.png -------------------------------------------------------------------------------- /components/resource/main.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/main.ico -------------------------------------------------------------------------------- /components/resource/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/main.png -------------------------------------------------------------------------------- /components/resource/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/open.png -------------------------------------------------------------------------------- /components/resource/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/pause.png -------------------------------------------------------------------------------- /components/resource/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/right.png -------------------------------------------------------------------------------- /components/resource/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/start.png -------------------------------------------------------------------------------- /components/resource/stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/stats.png -------------------------------------------------------------------------------- /components/resource/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/stop.png -------------------------------------------------------------------------------- /components/resource/compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/compare.png -------------------------------------------------------------------------------- /components/resource/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/config.png -------------------------------------------------------------------------------- /components/resource/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/delete.png -------------------------------------------------------------------------------- /components/resource/restart .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/restart .png -------------------------------------------------------------------------------- /components/resource/subtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/subtract.png -------------------------------------------------------------------------------- /components/resource/save_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/components/resource/save_icon.png -------------------------------------------------------------------------------- /test/resource/星空背景 绘画 夜空 4k壁纸_彼岸图网.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiaoqinxing/ImageViewer/HEAD/test/resource/星空背景 绘画 夜空 4k壁纸_彼岸图网.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | *.spec 4 | __pycache__/ 5 | *.pyc 6 | settings.json 7 | *.mp4 8 | config/ 9 | *.exe 10 | *.raw 11 | log/ 12 | .pytest_cache/ -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | pyside2 = "*" 8 | numpy = "*" 9 | opencv-python = "*" 10 | logging = "*" 11 | natsort = "*" 12 | 13 | [dev-packages] 14 | 15 | [requires] 16 | python_version = "3.9" 17 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: 当前文件", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/ImageViewer.py", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /ImageViewer.py: -------------------------------------------------------------------------------- 1 | from sys import exit 2 | from PySide2.QtWidgets import QApplication 3 | from PySide2.QtCore import Qt 4 | import components.logconfig as log 5 | from image_viewer import ImageViewer 6 | 7 | if __name__ == "__main__": 8 | QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) 9 | apps = QApplication([]) 10 | apps.setStyle('Fusion') 11 | log.clean_old_log() 12 | log.init_log() 13 | appswindow = ImageViewer() 14 | appswindow.show() 15 | exit(apps.exec_()) 16 | -------------------------------------------------------------------------------- /components/resource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | resource/add.png 4 | resource/subtract.png 5 | resource/快进.png 6 | resource/快退.png 7 | resource/restart .png 8 | resource/save_icon.png 9 | resource/compare.png 10 | resource/start.png 11 | resource/pause.png 12 | resource/stop.png 13 | resource/main.png 14 | resource/open.png 15 | resource/stats.png 16 | resource/down.png 17 | resource/up.png 18 | resource/delete.png 19 | resource/right.png 20 | resource/config.png 21 | 22 | 23 | -------------------------------------------------------------------------------- /image_config.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QDialog 2 | from PySide2.QtGui import Qt 3 | from PySide2.QtCore import Signal 4 | from ui.yuvconfig import Ui_YUVConfig 5 | from components.BasicImage import YuvParam 6 | 7 | 8 | class YUVConfig(QDialog): 9 | format = YuvParam() 10 | need_saveimg_in_rotate = True 11 | configUpdateEvent = Signal() 12 | 13 | def __init__(self, parent=None) -> None: 14 | super().__init__(parent) 15 | self.ui = Ui_YUVConfig() 16 | self.ui.setupUi(self) 17 | self.ui.buttonBox.clicked.connect(self.get) 18 | 19 | def set(self): 20 | self.ui.width.setValue(self.format.width) 21 | self.ui.height.setValue(self.format.height) 22 | index = self.ui.yuvformat.findText(self.format.yuv_format) 23 | self.ui.yuvformat.setCurrentIndex(index) 24 | self.ui.saveimg_in_rotate.setCheckState( 25 | Qt.Checked if self.need_saveimg_in_rotate else Qt.Unchecked) 26 | 27 | def get(self): 28 | self.format.height = self.ui.height.value() 29 | self.format.width = self.ui.width.value() 30 | self.format.yuv_format = self.ui.yuvformat.currentText() 31 | self.need_saveimg_in_rotate = ( 32 | self.ui.saveimg_in_rotate.checkState() == Qt.Checked) 33 | self.configUpdateEvent.emit() 34 | -------------------------------------------------------------------------------- /components/status_code_enum.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from logging import error 3 | from traceback import format_exc, print_exc 4 | from components.logconfig import critical_win 5 | 6 | 7 | class StatusCode(Enum): 8 | """状态码枚举类""" 9 | OK = '成功' 10 | ERROR = '错误' 11 | FILE_NOT_FOUND = '文件不存在' 12 | FILE_PATH_NOT_VALID = '文件路径不合法' 13 | IMAGE_FORMAT_ERR = '图像格式错误' 14 | IMAGE_FORMAT_NOT_SUPPORT = '图像格式不支持' 15 | IMAGE_READ_ERR = '图像读取失败' 16 | IMAGE_IS_NONE = '图片为空' 17 | 18 | 19 | class ImageToolError(Exception): 20 | def show(self): 21 | error(format_exc()) 22 | print_exc() 23 | critical_win(str(self)) 24 | 25 | 26 | class FileNotFoundErr(ImageToolError): 27 | def __init__(self): 28 | super().__init__('文件不存在') 29 | 30 | 31 | class FilePathNotValidErr(ImageToolError): 32 | def __init__(self): 33 | super().__init__('文件路径不合法') 34 | 35 | 36 | class ImageFormatErr(ImageToolError): 37 | def __init__(self): 38 | super().__init__('图像格式错误') 39 | 40 | 41 | class ImageFormatNotSupportErr(ImageToolError): 42 | def __init__(self): 43 | super().__init__('图像格式不支持') 44 | 45 | 46 | class ImageReadErr(ImageToolError): 47 | def __init__(self): 48 | super().__init__('图像读取失败') 49 | 50 | 51 | class ImageNoneErr(ImageToolError): 52 | def __init__(self): 53 | super().__init__('图片为空') 54 | -------------------------------------------------------------------------------- /components/ui/help_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HelpWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | 帮助手册 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 微软雅黑 23 | 15 24 | 25 | 26 | 27 | false 28 | 29 | 30 | true 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 0 43 | 0 44 | 800 45 | 22 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # 图片查看工具 2 | 3 | 这是一款能够对 常见格式的图片和 YUV 格式的图片进行查看、分析和对比的工具。支持任意组图片对比,可以随意增删画面对比窗口,支持统计信息的查看。 4 | 5 | ## 特色 6 | 7 | 1. 支持任意组图片对比,可以随意增删画面对比窗口 8 | 2. 支持统计信息的查看,有直方图信噪比等专业信息,同时通过框选,调整统计信息区域 9 | 3. 支持 YUV 格式的图片查看,和 jpg 一样的体验,同时可以转换成 jpg 格式,方便他人查看 10 | 4. 支持按照时间先后顺序,查看前后两张图片的跳转,方便图像细节的对比。即使新增文件,也能立刻识别。 11 | 12 | ## 使用方法 13 | 14 | 1. 可以通过点击打开图像的按钮或者拖动图片到图像显示框里进行显示 15 | 2. 通过保存按钮可以保存当前的图像(可是是图像处理前后的) 16 | 3. 通过 YUV 图像格式设置按钮,可以设置 YUV 的图像格式,用于正常显示图片 17 | 4. 通过点击图像统计分析按钮可以获取到整幅图像的统计信息,包括直方图,RGB 均值与信噪比,转成 YUV 之后的均值和信噪比,窗口大小,以及 RGB 增益 18 | 5. 统计信息窗口不关闭的情况下,框选图像中的任意一块区域,都可以显示这块区域的统计信息 19 | 6. 统计信息窗口中的直方图,显示了 RGB 和 Y 通道的直方图,可以通过复选框选择是否显示该通道的直方图 20 | 7. 点击增加和减少对比窗口可以增加或减少对比窗口,每个窗口可以独立操作和移动 21 | 22 | ## 界面 23 | 24 | 1. 右侧有四个按钮,分为为:打开图像,保存图像,设置 YUV 图像格式,删除图片,查看统计数据,查看上一张图片,查看下一章图片,向右翻转,增加对比窗口,减少对比窗口 25 | 2. 左下角会显示当前图像鼠标位置像素点的信息,包括 RGB 值以及缩放比例 26 | 3. 点击右侧按钮,查看统计信息,会跳出统计信息窗口,可以通过框选,调整显示区域 27 | 4. 点击增加和减少对比窗口可以增加或减少对比窗口,如图,创建了 3 个对比窗口 28 | 29 | ![yuv查看工具](https://github.com/xiaoqinxing/ImageViewer/raw/main/test/resource/8.png) 30 | 31 | ![统计信息窗口](https://github.com/xiaoqinxing/ImageViewer/raw/main/test/resource/7.png) 32 | 33 | ## 将要实现的功能点 34 | 35 | - [x] 能够支持常见的 yuv 格式 36 | - [x] 打开或者拖动的时候,会提示选取 yuv 格式,并保存最近一次格式 37 | - [x] 能够保存成 jpg 格式 38 | - [x] 能够通过鼠标对图片放大和缩小 39 | - [x] 能够通过鼠标对像素点的信息进行显示 40 | - [x] 能够通过直方图等统计分析对选中区域进行分析 41 | - [x] 能够支持多张图片对比,按+号,可以添加图片窗口 42 | - [ ] 多张图片拖动与放大应该保持一致 43 | - [ ] 能够支持批量 yuv 图片转换成 jpg 的功能 44 | - [x] 能够按上下键去查看上下的 yuv 45 | - [ ] 能够支持多帧 yuv 的解析,通过数字或者滑动条去选择相应帧的图片显示 46 | - [ ] 支持多张图片的偏移调整 47 | -------------------------------------------------------------------------------- /components/logconfig.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import os 3 | import logging 4 | from PySide2.QtWidgets import QMessageBox 5 | 6 | # 设置日志存放路径 7 | LOGFILE_PATH = '.\\log\\' 8 | if not os.path.exists(LOGFILE_PATH): 9 | os.mkdir(LOGFILE_PATH) 10 | 11 | # 获取今天的日期 格式2019-08-01 12 | TODAY_DATE = str(datetime.date.today()) 13 | 14 | 15 | def init_log(): 16 | """ 17 | func: 初始化日志,只需要在主函数中初始化一次 18 | """ 19 | root_logger = logging.getLogger() 20 | root_logger.setLevel(logging.INFO) 21 | handler = logging.FileHandler( 22 | LOGFILE_PATH + TODAY_DATE + '.log', 'a', 'utf-8') 23 | formatter = logging.Formatter( 24 | '%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s') 25 | handler.setFormatter(formatter) 26 | root_logger.addHandler(handler) 27 | logging.info('logging module init is ok') 28 | 29 | 30 | def clean_old_log(): 31 | """ 32 | 删除除今天以外的日志 33 | """ 34 | # 遍历目录下的所有日志文件 i是文件名 35 | for i in os.listdir(LOGFILE_PATH): 36 | if i != TODAY_DATE + '.log': 37 | os.remove(LOGFILE_PATH + i) 38 | 39 | 40 | def critical_win(string: str, parent=None): 41 | if(string is not None): 42 | QMessageBox.critical( 43 | parent, '警告', string, QMessageBox.Yes, QMessageBox.Yes) 44 | return 45 | 46 | 47 | def info_win(string: str, parent=None): 48 | if(string is not None): 49 | QMessageBox.information( 50 | parent, '提示', string, QMessageBox.Yes, QMessageBox.Yes) 51 | return 52 | -------------------------------------------------------------------------------- /ImageViewer.iss: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | #define MyAppName "ImageViewer" 5 | #define MyAppVersion "1.0" 6 | #define MyAppPublisher "liqinxing, Inc." 7 | #define MyAppURL "https://www.qinxing.xyz/" 8 | #define MyAppExeName "ImageViewer.exe" 9 | 10 | [Setup] 11 | ; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. 12 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 13 | AppId={{12F34F85-9D0D-4F1B-9492-E8875EE23A31} 14 | AppName={#MyAppName} 15 | AppVersion={#MyAppVersion} 16 | ;AppVerName={#MyAppName} {#MyAppVersion} 17 | AppPublisher={#MyAppPublisher} 18 | AppPublisherURL={#MyAppURL} 19 | AppSupportURL={#MyAppURL} 20 | AppUpdatesURL={#MyAppURL} 21 | DefaultDirName=C:\{#MyAppName} 22 | DisableProgramGroupPage=yes 23 | ; Uncomment the following line to run in non administrative install mode (install for current user only.) 24 | ;PrivilegesRequired=lowest 25 | OutputDir=.\Output 26 | OutputBaseFilename=ImageViewer 27 | SetupIconFile=.\components\resource\main.ico 28 | Compression=lzma 29 | SolidCompression=yes 30 | WizardStyle=modern 31 | 32 | [Languages] 33 | Name: "english"; MessagesFile: "compiler:Default.isl" 34 | 35 | [Tasks] 36 | Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked 37 | 38 | [Files] 39 | Source: ".\dist\ImageViewer\ImageViewer.exe"; DestDir: "{app}"; Flags: ignoreversion 40 | Source: ".\dist\ImageViewer\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs 41 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 42 | 43 | [Icons] 44 | Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" 45 | Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon 46 | 47 | [Run] 48 | Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent 49 | 50 | [installDelete] 51 | Type: filesandordirs; Name:"{app}\config\*"; 52 | -------------------------------------------------------------------------------- /components/ui/help_window.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'help_window.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 5.15.2 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide2.QtCore import * 12 | from PySide2.QtGui import * 13 | from PySide2.QtWidgets import * 14 | 15 | 16 | class Ui_HelpWindow(object): 17 | def setupUi(self, HelpWindow): 18 | if not HelpWindow.objectName(): 19 | HelpWindow.setObjectName(u"HelpWindow") 20 | HelpWindow.resize(800, 600) 21 | self.centralwidget = QWidget(HelpWindow) 22 | self.centralwidget.setObjectName(u"centralwidget") 23 | self.gridLayout = QGridLayout(self.centralwidget) 24 | self.gridLayout.setObjectName(u"gridLayout") 25 | self.textBrowser = QTextBrowser(self.centralwidget) 26 | self.textBrowser.setObjectName(u"textBrowser") 27 | font = QFont() 28 | font.setFamily(u"\u5fae\u8f6f\u96c5\u9ed1") 29 | font.setPointSize(15) 30 | self.textBrowser.setFont(font) 31 | self.textBrowser.setAcceptRichText(False) 32 | self.textBrowser.setOpenExternalLinks(True) 33 | self.textBrowser.setOpenLinks(True) 34 | 35 | self.gridLayout.addWidget(self.textBrowser, 0, 0, 1, 1) 36 | 37 | HelpWindow.setCentralWidget(self.centralwidget) 38 | self.menubar = QMenuBar(HelpWindow) 39 | self.menubar.setObjectName(u"menubar") 40 | self.menubar.setGeometry(QRect(0, 0, 800, 22)) 41 | HelpWindow.setMenuBar(self.menubar) 42 | self.statusbar = QStatusBar(HelpWindow) 43 | self.statusbar.setObjectName(u"statusbar") 44 | HelpWindow.setStatusBar(self.statusbar) 45 | 46 | self.retranslateUi(HelpWindow) 47 | 48 | QMetaObject.connectSlotsByName(HelpWindow) 49 | # setupUi 50 | 51 | def retranslateUi(self, HelpWindow): 52 | HelpWindow.setWindowTitle(QCoreApplication.translate("HelpWindow", u"\u5e2e\u52a9\u624b\u518c", None)) 53 | # retranslateUi 54 | 55 | -------------------------------------------------------------------------------- /components/MatplotWidget.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtCore import QSize 2 | from PySide2.QtWidgets import QWidget 3 | from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT 4 | import matplotlib.pyplot as plt 5 | from matplotlib.figure import Figure 6 | 7 | 8 | class MplCanvas(FigureCanvasQTAgg): 9 | def __init__(self, parent=None, width=5, height=4, dpi=100): 10 | plt.rcParams['font.family'] = ['SimHei'] 11 | plt.rcParams['axes.unicode_minus'] = False 12 | fig = Figure(figsize=(width, height), dpi=dpi) 13 | self.axes = fig.add_subplot(111) 14 | # self.axes.hold(False) #每次绘图时都不保留上一次绘图的结果 15 | super(MplCanvas, self).__init__(fig) 16 | 17 | 18 | class MatplotlibLayout(QWidget): 19 | """ 20 | 自定义的matplot窗口 21 | """ 22 | 23 | def __init__(self, layout): 24 | self.plt = MplCanvas() 25 | self.layout = layout 26 | self.mpl_ntb = NavigationToolbar2QT(self.plt, parent=None) 27 | 28 | def draw(self, navigationBar=True): 29 | self.layout.addWidget(self.plt) 30 | if navigationBar == True: 31 | self.layout.addWidget(self.mpl_ntb) 32 | 33 | def clean(self, navigationBar=True): 34 | self.layout.removeWidget(self.plt) 35 | if navigationBar == True: 36 | self.layout.removeWidget(self.mpl_ntb) 37 | self.plt = MplCanvas() 38 | self.mpl_ntb = NavigationToolbar2QT(self.plt, parent=None) 39 | 40 | def input(self, x, y): 41 | self.plt.axes.plot(x, y) 42 | 43 | def input_2line(self, x, y1, y2): 44 | self.plt.axes.plot(x, y1, color='green') 45 | self.plt.axes.plot(x, y2, color='red') 46 | self.plt.axes.fill_between(x, y1, y2, color='blue', alpha=0.25) 47 | 48 | def label(self, string_x, string_y, enable_grid=True): 49 | self.plt.axes.set_xlabel(string_x) 50 | self.plt.axes.set_ylabel(string_y) 51 | if enable_grid == True: 52 | self.plt.axes.grid(True) 53 | 54 | 55 | class MatplotlibWidget(QWidget): 56 | """ 57 | 自定义的matplot窗口 58 | """ 59 | 60 | def __init__(self, layout): 61 | super().__init__() 62 | self.layout = layout 63 | self.plt = MplCanvas() 64 | self.first_draw = 0 65 | self.setMinimumSize(QSize(352, 0)) 66 | # self.mpl_ntb = NavigationToolbar2QT(self.plt, parent=None) 67 | 68 | def draw(self, navigationBar=True): 69 | self.layout.addWidget(self.plt, 1, 1, 1, 1) 70 | self.first_draw = 1 71 | 72 | def clean(self, navigationBar=True): 73 | if self.first_draw == 1: 74 | self.layout.removeWidget(self.plt) 75 | self.plt = MplCanvas() 76 | 77 | def input(self, x, y): 78 | self.plt.axes.plot(x, y) 79 | 80 | def input_2line(self, x, y1, y2): 81 | self.plt.axes.plot(x, y1, color='green') 82 | self.plt.axes.plot(x, y2, color='red') 83 | self.plt.axes.fill_between(x, y1, y2, color='blue', alpha=0.25) 84 | 85 | def input_r_hist(self, x, y): 86 | self.plt.axes.plot(x, y, color='red') 87 | 88 | def input_g_hist(self, x, y): 89 | self.plt.axes.plot(x, y, color='green') 90 | 91 | def input_b_hist(self, x, y): 92 | self.plt.axes.plot(x, y, color='blue') 93 | 94 | def input_y_hist(self, x, y): 95 | self.plt.axes.plot(x, y, color='black') 96 | 97 | def label(self, string_x, string_y, enable_grid=True): 98 | self.plt.axes.set_xlabel(string_x) 99 | self.plt.axes.set_ylabel(string_y) 100 | if enable_grid == True: 101 | self.plt.axes.grid(True) 102 | -------------------------------------------------------------------------------- /test/components/test_basic_image.py: -------------------------------------------------------------------------------- 1 | from os.path import samefile, isfile 2 | from components.BasicImage import ImageBasic 3 | from components.status_code_enum import StatusCode 4 | from components.status_code_enum import * 5 | 6 | 7 | def test_status_code(): 8 | ret = StatusCode.OK 9 | if ret is StatusCode.OK: 10 | assert True 11 | 12 | ret = StatusCode.FILE_NOT_FOUND 13 | if ret is StatusCode.OK: 14 | assert '文件不存在' == StatusCode.FILE_NOT_FOUND.value 15 | assert StatusCode.FILE_NOT_FOUND.name == 'FILE_NOT_FOUND' 16 | 17 | 18 | class TestBasicImage: 19 | def test_load_imagefile(self): 20 | img = ImageBasic() 21 | try: 22 | img.load_file("test/resource/5.jpg") 23 | assert False 24 | except FileNotFoundErr: 25 | assert True 26 | except Exception: 27 | assert False 28 | 29 | try: 30 | img.load_file("test/resource/1.jpg") 31 | assert True 32 | except Exception: 33 | assert False 34 | 35 | def test_save_and_remove_file(self): 36 | img = ImageBasic() 37 | try: 38 | img.save_image("test/resource/1-1.jpg") 39 | assert False 40 | except ImageNoneErr: 41 | assert True 42 | except Exception: 43 | assert False 44 | 45 | try: 46 | img.load_file("test/resource/1.jpg") 47 | img.save_image("test/resource/1-1.jpg") 48 | assert isfile("test/resource/1-1.jpg") 49 | img.remove_image() 50 | assert isfile("test/resource/1.jpg") is False 51 | assert img.img is None 52 | assert True 53 | except Exception: 54 | assert False 55 | 56 | try: 57 | img.load_file("test/resource/1-1.jpg") 58 | img.save_image("test/resource/1.jpg") 59 | img.save_image("test/resource/1.jpg") 60 | assert isfile("test/resource/1.jpg") 61 | img.remove_image() 62 | assert isfile("test/resource/1.jpg") 63 | assert img.img is None 64 | assert True 65 | except Exception: 66 | assert False 67 | 68 | def test_next_photo(self): 69 | img = ImageBasic() 70 | try: 71 | img.load_file("test/resource/2.jpg") 72 | next_photo_name, index, files_nums = img.find_next_time_photo(1) 73 | assert samefile(next_photo_name, "test/resource/3.png") 74 | assert index == 3 75 | assert files_nums == 5 76 | 77 | next_photo_name, index, files_nums = img.find_next_time_photo(-1) 78 | assert samefile(next_photo_name, 79 | "test/resource/星空背景 绘画 夜空 4k壁纸_彼岸图网.jpg") 80 | assert index == 1 81 | assert files_nums == 5 82 | 83 | img.load_file("test/resource/3.png") 84 | next_photo_name, index, files_nums = img.find_next_nat_photo(1) 85 | assert samefile(next_photo_name, "test/resource/6月壁纸.jpg") 86 | assert index == 3 87 | assert files_nums == 5 88 | 89 | next_photo_name, index, files_nums = img.find_next_nat_photo(-1) 90 | assert samefile(next_photo_name, "test/resource/2.jpg") 91 | assert index == 1 92 | assert files_nums == 5 93 | assert True 94 | except Exception: 95 | assert False 96 | 97 | def test_get_img_point(self): 98 | img = ImageBasic() 99 | try: 100 | img.load_file("test/resource/2.jpg") 101 | point = img.get_img_point(214, 190) 102 | assert (point == [218, 211, 255]).all() 103 | 104 | img.load_file("test/resource/3.png") 105 | point = img.get_img_point(217, 197) 106 | assert (point == [241, 192, 190]).all() 107 | assert True 108 | except Exception: 109 | assert False 110 | -------------------------------------------------------------------------------- /components/window.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QMessageBox, QMainWindow, QProgressBar, QLabel 2 | from components.ui.mainwindow import Ui_MainWindow 3 | import pickle 4 | import os 5 | 6 | CACHE_FILEPATH = './config' 7 | 8 | 9 | class MainWindow(QMainWindow): 10 | """对QMainWindow类重写,实现一些功能""" 11 | 12 | def __init__(self): 13 | super().__init__() 14 | self.sub_windows = list() 15 | self.filename = './config/ImageToolsSubWindows.tmp' 16 | self.sub_windows_list = list() 17 | self.ui = Ui_MainWindow() 18 | self.ui.setupUi(self) 19 | self.need_clear_cache = False 20 | if os.path.exists(self.filename): 21 | with open(self.filename, "rb") as fp: 22 | self.sub_windows_list = pickle.load(fp) 23 | 24 | def closeEvent(self, event): 25 | """ 26 | 重写closeEvent方法,实现dialog窗体关闭时执行一些代码 27 | :param event: close()触发的事件 28 | :return: None 29 | """ 30 | reply = QMessageBox.question(self, 31 | 'ImageTools', 32 | "是否要退出程序?", 33 | QMessageBox.Yes | QMessageBox.No, 34 | QMessageBox.No) 35 | if reply == QMessageBox.Yes: 36 | if self.need_clear_cache == False: 37 | if not os.path.exists(CACHE_FILEPATH): 38 | os.mkdir(CACHE_FILEPATH) 39 | sub_windows_list = list() 40 | while len(self.sub_windows) > 0: 41 | if (self.sub_windows[0].name is not None): 42 | sub_windows_list.append(self.sub_windows[0].name) 43 | self.sub_windows[0].close() 44 | with open(self.filename, "wb") as fp: 45 | pickle.dump(sub_windows_list, fp) 46 | else: 47 | # 清楚缓存 48 | if os.path.exists(CACHE_FILEPATH): 49 | for files in os.listdir(CACHE_FILEPATH): 50 | filepath = os.path.join(CACHE_FILEPATH, files) 51 | if os.path.isfile(filepath): 52 | os.remove(filepath) 53 | event.accept() 54 | else: 55 | event.ignore() 56 | 57 | 58 | class SubWindow(QMainWindow): 59 | """对QMainWindow类重写,实现一些功能""" 60 | 61 | def __init__(self, name, parent, ui_view, need_processBar=False): 62 | super().__init__(parent) 63 | self.parent = parent 64 | self.name = name 65 | self.filename = "./config/" + name + ".tmp" 66 | self.__saved_params = None 67 | self.ui = ui_view 68 | self.ui.setupUi(self) 69 | # add 进度条和详细信息显示 需要在ui里面加入statusBar 70 | if(need_processBar == True): 71 | self.progress_bar = QProgressBar() 72 | self.info_bar = QLabel() 73 | self.time_bar = QLabel() 74 | self.ui.statusBar.addPermanentWidget(self.info_bar, stretch=8) 75 | self.ui.statusBar.addPermanentWidget(self.time_bar, stretch=1) 76 | self.ui.statusBar.addPermanentWidget(self.progress_bar, stretch=2) 77 | self.progress_bar.setRange(0, 100) # 设置进度条的范围 78 | self.progress_bar.setValue(0) 79 | 80 | def load_params(self, init_value): 81 | """ 82 | 加载存储的类,返回的参数可以直接进行修改,会保存到本地,下一次打开会自动加载 83 | """ 84 | if os.path.exists(self.filename): 85 | with open(self.filename, "rb") as fp: 86 | self.__saved_params = pickle.load(fp) 87 | if (self.__saved_params is None): 88 | self.__saved_params = init_value 89 | return self.__saved_params 90 | 91 | def closeEvent(self, event): 92 | """ 93 | 重写closeEvent方法,实现dialog窗体关闭时执行一些代码 94 | :param event: close()触发的事件 95 | :return: None 96 | """ 97 | if not os.path.exists(CACHE_FILEPATH): 98 | os.mkdir(CACHE_FILEPATH) 99 | self.name = None 100 | with open(self.filename, "wb") as fp: 101 | pickle.dump(self.__saved_params, fp) 102 | try: 103 | self.parent.sub_windows.remove(self) 104 | except Exception: 105 | print('{}工具不支持记忆存储'.format(self.name)) 106 | event.accept() 107 | -------------------------------------------------------------------------------- /image_viewer.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtWidgets import QMainWindow, QLabel 2 | from ui.yuvviewer_window import Ui_YUVEditor 3 | from image_config import YUVConfig 4 | from components.customwidget import ImageView 5 | 6 | 7 | class ImageViewer(QMainWindow): 8 | def __init__(self): 9 | super().__init__() 10 | self.ui = Ui_YUVEditor() 11 | self.ui.setupUi(self) 12 | self.config = YUVConfig() 13 | self.info_bar = QLabel() 14 | self.focus_info_bar = QLabel() 15 | self.focus_index = 0 16 | self.ui.statusBar.addPermanentWidget(self.info_bar, stretch=8) 17 | self.ui.statusBar.addPermanentWidget(self.focus_info_bar, stretch=1) 18 | self.imageview_wins = [] 19 | self.add_compare() 20 | 21 | self.ui.openimage.triggered.connect(self.on_open_img) 22 | self.ui.actionstats.triggered.connect(self.on_calc_stats) 23 | self.ui.nextphoto.triggered.connect(self.switch_next_photo) 24 | self.ui.prephoto.triggered.connect(self.switch_pre_photo) 25 | self.ui.rotateright.triggered.connect(self.rotate_photo) 26 | self.ui.yuvconfig.triggered.connect(self.config.show) # 配置UI显示 27 | self.ui.add_compare.triggered.connect(self.add_compare) 28 | self.ui.delcompare.triggered.connect(self.del_compare) 29 | self.ui.saveimage.triggered.connect(self.on_save_photo) 30 | self.ui.deletephoto.triggered.connect(self.delete_photo) 31 | self.config.configUpdateEvent.connect(self.update_yuv_config) 32 | 33 | def add_compare(self): 34 | imgviewwin = ImageView(self.ui.horizontalLayout, self) 35 | imgviewwin.filenameUpdateEvent.connect(self.update_filename) 36 | imgviewwin.sigUpdatePointStatusEvent.connect(self.update_point_status) 37 | imgviewwin.focusOnEvent.connect(self.update_focus_index) 38 | self.imageview_wins.append(imgviewwin) 39 | 40 | def update_focus_index(self): 41 | for index, imgviewwin in enumerate(self.imageview_wins): 42 | if imgviewwin.isFocus is True: 43 | self.focus_index = index 44 | self.focus_info_bar.setText( 45 | '当前选中第{}个窗口'.format(index + 1)) 46 | return 47 | self.focus_info_bar.setText('当前选中第1个窗口') 48 | self.focus_index = 0 49 | 50 | def get_current_imageview_win(self): 51 | if self.focus_index >= len(self.imageview_wins): 52 | return self.imageview_wins[-1] 53 | return self.imageview_wins[self.focus_index] 54 | 55 | def update_filename(self): 56 | filenamelist = [] 57 | for imgviewwin in self.imageview_wins: 58 | if imgviewwin.imageFileName != '': 59 | filenamelist.append('【' + imgviewwin.imageFileName + '】') 60 | self.ui.photo_title.setTitle(' VS '.join(filenamelist)) 61 | 62 | def update_yuv_config(self): 63 | imgviewwin = self.get_current_imageview_win() 64 | imgviewwin.img.load_yuv_config(self.config.format) 65 | imgviewwin.reload_image() 66 | 67 | def del_compare(self): 68 | if len(self.imageview_wins) <= 1: 69 | return 70 | imgviewwin = self.imageview_wins.pop() 71 | imgviewwin.Exit(self.ui.horizontalLayout) 72 | 73 | def switch_next_photo(self): 74 | imgviewwin = self.get_current_imageview_win() 75 | imgviewwin.switch_next_photo() 76 | 77 | def switch_pre_photo(self): 78 | imgviewwin = self.get_current_imageview_win() 79 | imgviewwin.switch_pre_photo() 80 | 81 | def rotate_photo(self): 82 | imgviewwin = self.get_current_imageview_win() 83 | imgviewwin.rotate_photo(True) 84 | 85 | def delete_photo(self): 86 | imgviewwin = self.get_current_imageview_win() 87 | imgviewwin.delete_photo() 88 | 89 | def on_save_photo(self): 90 | imgviewwin = self.get_current_imageview_win() 91 | imgviewwin.save_image() 92 | 93 | def on_open_img(self): 94 | imgviewwin = self.get_current_imageview_win() 95 | imgviewwin.open_image() 96 | 97 | def update_point_status(self, point_status): 98 | self.info_bar.setText(point_status) 99 | 100 | def on_calc_stats(self): 101 | imgviewwin = self.get_current_imageview_win() 102 | imgviewwin.on_calc_stats() 103 | -------------------------------------------------------------------------------- /components/ui/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | Qt::NonModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 1140 13 | 857 14 | 15 | 16 | 17 | ImageTools 18 | 19 | 20 | 21 | :/tool_icon/resource/main.png:/tool_icon/resource/main.png 22 | 23 | 24 | 25 | 26 | 27 | 28 | true 29 | 30 | 31 | 0 32 | 33 | 34 | Qt::ScrollBarAsNeeded 35 | 36 | 37 | Qt::ScrollBarAsNeeded 38 | 39 | 40 | QMdiArea::TabbedView 41 | 42 | 43 | true 44 | 45 | 46 | true 47 | 48 | 49 | QTabWidget::Rounded 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 0 59 | 0 60 | 1140 61 | 22 62 | 63 | 64 | 65 | 66 | 工具 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ISP 77 | 78 | 79 | 80 | 81 | 82 | 83 | 关于 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 抖动测试工具 96 | 97 | 98 | 99 | 100 | 图片分析工具 101 | 102 | 103 | 104 | 105 | 关于 106 | 107 | 108 | 109 | 110 | raw图分析工具 111 | 112 | 113 | 114 | 115 | 视频对比工具 116 | 117 | 118 | 119 | 120 | PQtools转代码 121 | 122 | 123 | 124 | 125 | 镜头计算器 126 | 127 | 128 | 129 | 130 | 镜头曲线计算工具 131 | 132 | 133 | 134 | 135 | 用户手册 136 | 137 | 138 | 139 | 140 | 清理缓存 141 | 142 | 143 | 144 | 145 | 检查更新 146 | 147 | 148 | 149 | 150 | YUV查看工具 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /ui/yuvconfig.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | YUVConfig 4 | 5 | 6 | 7 | 0 8 | 0 9 | 212 10 | 175 11 | 12 | 13 | 14 | 图片查看工具配置 15 | 16 | 17 | 18 | 19 | 20 | YUV配置 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 格式 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | NV21 44 | 45 | 46 | 47 | 48 | NV12 49 | 50 | 51 | 52 | 53 | YUV420 54 | 55 | 56 | 57 | 58 | YUYV 59 | 60 | 61 | 62 | 63 | YVYU 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 8192 72 | 73 | 74 | 10 75 | 76 | 77 | 3840 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 8192 92 | 93 | 94 | 10 95 | 96 | 97 | 2160 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 旋转时保存图片 110 | 111 | 112 | true 113 | 114 | 115 | 116 | 117 | 118 | 119 | Qt::Horizontal 120 | 121 | 122 | QDialogButtonBox::Ok 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | buttonBox 132 | accepted() 133 | YUVConfig 134 | accept() 135 | 136 | 137 | 248 138 | 254 139 | 140 | 141 | 157 142 | 274 143 | 144 | 145 | 146 | 147 | buttonBox 148 | rejected() 149 | YUVConfig 150 | reject() 151 | 152 | 153 | 316 154 | 260 155 | 156 | 157 | 286 158 | 274 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /ui/yuvconfig.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'yuvconfig.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 5.15.2 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide2.QtCore import * 12 | from PySide2.QtGui import * 13 | from PySide2.QtWidgets import * 14 | 15 | 16 | class Ui_YUVConfig(object): 17 | def setupUi(self, YUVConfig): 18 | if not YUVConfig.objectName(): 19 | YUVConfig.setObjectName(u"YUVConfig") 20 | YUVConfig.resize(212, 175) 21 | self.verticalLayout = QVBoxLayout(YUVConfig) 22 | self.verticalLayout.setObjectName(u"verticalLayout") 23 | self.groupBox = QGroupBox(YUVConfig) 24 | self.groupBox.setObjectName(u"groupBox") 25 | self.verticalLayout_2 = QVBoxLayout(self.groupBox) 26 | self.verticalLayout_2.setObjectName(u"verticalLayout_2") 27 | self.formLayout = QFormLayout() 28 | self.formLayout.setObjectName(u"formLayout") 29 | self.label_2 = QLabel(self.groupBox) 30 | self.label_2.setObjectName(u"label_2") 31 | 32 | self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_2) 33 | 34 | self.label_3 = QLabel(self.groupBox) 35 | self.label_3.setObjectName(u"label_3") 36 | 37 | self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3) 38 | 39 | self.yuvformat = QComboBox(self.groupBox) 40 | self.yuvformat.addItem("") 41 | self.yuvformat.addItem("") 42 | self.yuvformat.addItem("") 43 | self.yuvformat.addItem("") 44 | self.yuvformat.addItem("") 45 | self.yuvformat.setObjectName(u"yuvformat") 46 | 47 | self.formLayout.setWidget(2, QFormLayout.FieldRole, self.yuvformat) 48 | 49 | self.width = QSpinBox(self.groupBox) 50 | self.width.setObjectName(u"width") 51 | self.width.setMaximum(8192) 52 | self.width.setSingleStep(10) 53 | self.width.setValue(3840) 54 | 55 | self.formLayout.setWidget(0, QFormLayout.FieldRole, self.width) 56 | 57 | self.label = QLabel(self.groupBox) 58 | self.label.setObjectName(u"label") 59 | 60 | self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label) 61 | 62 | self.height = QSpinBox(self.groupBox) 63 | self.height.setObjectName(u"height") 64 | self.height.setMaximum(8192) 65 | self.height.setSingleStep(10) 66 | self.height.setValue(2160) 67 | 68 | self.formLayout.setWidget(1, QFormLayout.FieldRole, self.height) 69 | 70 | 71 | self.verticalLayout_2.addLayout(self.formLayout) 72 | 73 | 74 | self.verticalLayout.addWidget(self.groupBox) 75 | 76 | self.saveimg_in_rotate = QCheckBox(YUVConfig) 77 | self.saveimg_in_rotate.setObjectName(u"saveimg_in_rotate") 78 | self.saveimg_in_rotate.setChecked(True) 79 | 80 | self.verticalLayout.addWidget(self.saveimg_in_rotate) 81 | 82 | self.buttonBox = QDialogButtonBox(YUVConfig) 83 | self.buttonBox.setObjectName(u"buttonBox") 84 | self.buttonBox.setOrientation(Qt.Horizontal) 85 | self.buttonBox.setStandardButtons(QDialogButtonBox.Ok) 86 | 87 | self.verticalLayout.addWidget(self.buttonBox) 88 | 89 | 90 | self.retranslateUi(YUVConfig) 91 | self.buttonBox.accepted.connect(YUVConfig.accept) 92 | self.buttonBox.rejected.connect(YUVConfig.reject) 93 | 94 | QMetaObject.connectSlotsByName(YUVConfig) 95 | # setupUi 96 | 97 | def retranslateUi(self, YUVConfig): 98 | YUVConfig.setWindowTitle(QCoreApplication.translate("YUVConfig", u"\u56fe\u7247\u67e5\u770b\u5de5\u5177\u914d\u7f6e", None)) 99 | self.groupBox.setTitle(QCoreApplication.translate("YUVConfig", u"YUV\u914d\u7f6e", None)) 100 | self.label_2.setText(QCoreApplication.translate("YUVConfig", u"\u5bbd", None)) 101 | self.label_3.setText(QCoreApplication.translate("YUVConfig", u"\u683c\u5f0f", None)) 102 | self.yuvformat.setItemText(0, QCoreApplication.translate("YUVConfig", u"NV21", None)) 103 | self.yuvformat.setItemText(1, QCoreApplication.translate("YUVConfig", u"NV12", None)) 104 | self.yuvformat.setItemText(2, QCoreApplication.translate("YUVConfig", u"YUV420", None)) 105 | self.yuvformat.setItemText(3, QCoreApplication.translate("YUVConfig", u"YUYV", None)) 106 | self.yuvformat.setItemText(4, QCoreApplication.translate("YUVConfig", u"YVYU", None)) 107 | 108 | self.label.setText(QCoreApplication.translate("YUVConfig", u"\u9ad8", None)) 109 | self.saveimg_in_rotate.setText(QCoreApplication.translate("YUVConfig", u"\u65cb\u8f6c\u65f6\u4fdd\u5b58\u56fe\u7247", None)) 110 | # retranslateUi 111 | 112 | -------------------------------------------------------------------------------- /components/histview.py: -------------------------------------------------------------------------------- 1 | from components.ui.histgramview import Ui_HistgramView 2 | from PySide2.QtWidgets import QGraphicsView, QDialog 3 | from components.MatplotWidget import MatplotlibWidget 4 | import numpy as np 5 | import cv2 6 | 7 | 8 | class HistView(QDialog): 9 | def __init__(self, parent): 10 | """ 11 | func: 初始化直方图统计信息UI,把父类的指针变成选中方框模式 12 | """ 13 | super().__init__(parent) 14 | self.parent = parent 15 | self.parent.setDragMode(QGraphicsView.RubberBandDrag) 16 | self.ui = Ui_HistgramView() 17 | self.ui.setupUi(self) 18 | self.ui.r_enable.stateChanged.connect( 19 | self.on_r_hist_enable) 20 | self.ui.g_enable.stateChanged.connect( 21 | self.on_g_hist_enable) 22 | self.ui.b_enable.stateChanged.connect( 23 | self.on_b_hist_enable) 24 | self.ui.y_enable.stateChanged.connect( 25 | self.on_y_hist_enable) 26 | self.histview = MatplotlibWidget( 27 | self.ui.gridLayout_10) 28 | self.x_axis = np.linspace(0, 255, num=256) 29 | self.r_hist_visible = 2 30 | self.g_hist_visible = 2 31 | self.b_hist_visible = 2 32 | self.y_hist_visible = 2 33 | self.enable = True 34 | 35 | def update_rect_data(self, img, rect): 36 | """ 37 | func: 更新方框内的图像统计信息 38 | """ 39 | (rect, image) = self.update_rect(img, rect) 40 | self.calcHist(image) 41 | self.hist_show() 42 | self.stats_show(self.calcStatics(image, rect)) 43 | 44 | def closeEvent(self, event): 45 | """ 46 | func: 关闭窗口的时候,把鼠标还原 47 | """ 48 | self.parent.setDragMode(QGraphicsView.ScrollHandDrag) 49 | self.enable = False 50 | return super().closeEvent(event) 51 | 52 | def update_rect(self, img, rect): 53 | [x1, y1, x2, y2] = rect 54 | i1 = max(x1, 0) 55 | i2 = min(x2, img.shape[1]) 56 | j1 = max(y1, 0) 57 | j2 = min(img.shape[0], y2) 58 | if (i2 > i1 and j2 > j1): 59 | img = img[j1:j2, i1:i2][:, :, :3] 60 | rect = [j1, i1, j2, i2] 61 | return (rect, img) 62 | 63 | def calcStatics(self, img, rect): 64 | [j1, i1, j2, i2] = rect 65 | (average_rgb, stddv_rgb) = cv2.meanStdDev(img) 66 | # TODO 信噪比的公式有些问题,当标准差为0的时候,信噪比该是无穷大 67 | snr_rgb = 20 * np.log10(average_rgb/stddv_rgb) 68 | img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) 69 | (average_yuv, stddv_yuv) = cv2.meanStdDev(img) 70 | snr_yuv = 20 * np.log10(average_yuv/stddv_yuv) 71 | rgb_ratio = [0.0, 0.0] 72 | awb_gain = [0.0, 0.0, 0.0] 73 | rgb_ratio[0] = average_rgb[2]/average_rgb[1] 74 | rgb_ratio[1] = average_rgb[0]/average_rgb[1] 75 | awb_gain[0] = 1/rgb_ratio[0] 76 | awb_gain[1] = 1 77 | awb_gain[2] = 1/rgb_ratio[1] 78 | enable_rect = [i1, j1, i2-i1, j2-j1] 79 | return (average_rgb, snr_rgb, average_yuv, snr_yuv, rgb_ratio, awb_gain, enable_rect) 80 | 81 | def calcHist(self, img): 82 | chans = cv2.split(img) 83 | self.b_hist = (cv2.calcHist([chans[0]], [0], None, [ 84 | 256], [0, 256])) 85 | self.g_hist = (cv2.calcHist([chans[1]], [0], None, [ 86 | 256], [0, 256])) 87 | self.r_hist = (cv2.calcHist([chans[2]], [0], None, [ 88 | 256], [0, 256])) 89 | # 转为灰度图,然后算亮度直方图 90 | img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 91 | self.y_hist = (cv2.calcHist([img], [0], None, [ 92 | 256], [0, 256])) 93 | self.r_hist.reshape(1, 256) 94 | self.g_hist.reshape(1, 256) 95 | self.b_hist.reshape(1, 256) 96 | self.y_hist.reshape(1, 256) 97 | 98 | def on_r_hist_enable(self, type): 99 | self.r_hist_visible = type 100 | self.hist_show() 101 | 102 | def on_g_hist_enable(self, type): 103 | self.g_hist_visible = type 104 | self.hist_show() 105 | 106 | def on_b_hist_enable(self, type): 107 | self.b_hist_visible = type 108 | self.hist_show() 109 | 110 | def on_y_hist_enable(self, type): 111 | self.y_hist_visible = type 112 | self.hist_show() 113 | 114 | def hist_show(self): 115 | self.histview.clean() 116 | self.histview.label("亮度", "数量") 117 | if (self.r_hist_visible == 2): 118 | self.histview.input_r_hist(self.x_axis, self.r_hist) 119 | if (self.g_hist_visible == 2): 120 | self.histview.input_g_hist(self.x_axis, self.g_hist) 121 | if (self.b_hist_visible == 2): 122 | self.histview.input_b_hist(self.x_axis, self.b_hist) 123 | if (self.y_hist_visible == 2): 124 | self.histview.input_y_hist(self.x_axis, self.y_hist) 125 | self.histview.draw() 126 | 127 | def stats_show(self, value): 128 | (average_rgb, snr_rgb, average_yuv, snr_yuv, 129 | rgb_ratio, awb_gain, enable_rect) = value 130 | self.ui.average_r.setValue(average_rgb[2]) 131 | self.ui.average_g.setValue(average_rgb[1]) 132 | self.ui.average_b.setValue(average_rgb[0]) 133 | self.ui.average_y.setValue(average_yuv[0]) 134 | self.ui.average_cr.setValue(average_yuv[1]) 135 | self.ui.average_cb.setValue(average_yuv[2]) 136 | self.ui.rg_ratio.setValue(rgb_ratio[0]) 137 | self.ui.bg_ratio.setValue(rgb_ratio[1]) 138 | self.ui.r_gain.setValue(awb_gain[0]) 139 | self.ui.g_gain.setValue(awb_gain[1]) 140 | self.ui.b_gain.setValue(awb_gain[2]) 141 | self.ui.section_x.setValue(enable_rect[0]) 142 | self.ui.section_y.setValue(enable_rect[1]) 143 | self.ui.section_height.setValue(enable_rect[2]) 144 | self.ui.section_width.setValue(enable_rect[3]) 145 | self.ui.snr_r.setValue(snr_rgb[2]) 146 | self.ui.snr_g.setValue(snr_rgb[1]) 147 | self.ui.snr_b.setValue(snr_rgb[0]) 148 | self.ui.snr_y.setValue(snr_yuv[0]) 149 | self.ui.snr_cr.setValue(snr_yuv[1]) 150 | self.ui.snr_cb.setValue(snr_yuv[2]) 151 | -------------------------------------------------------------------------------- /components/ui/mainwindow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'mainwindow.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 5.15.2 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide2.QtCore import * 12 | from PySide2.QtGui import * 13 | from PySide2.QtWidgets import * 14 | 15 | 16 | class Ui_MainWindow(object): 17 | def setupUi(self, MainWindow): 18 | if not MainWindow.objectName(): 19 | MainWindow.setObjectName(u"MainWindow") 20 | MainWindow.setWindowModality(Qt.NonModal) 21 | MainWindow.resize(1140, 857) 22 | icon = QIcon() 23 | icon.addFile(u":/tool_icon/resource/main.png", QSize(), QIcon.Normal, QIcon.Off) 24 | MainWindow.setWindowIcon(icon) 25 | self.shake_tool = QAction(MainWindow) 26 | self.shake_tool.setObjectName(u"shake_tool") 27 | self.imageeditor = QAction(MainWindow) 28 | self.imageeditor.setObjectName(u"imageeditor") 29 | self.about = QAction(MainWindow) 30 | self.about.setObjectName(u"about") 31 | self.rawimageeditor = QAction(MainWindow) 32 | self.rawimageeditor.setObjectName(u"rawimageeditor") 33 | self.video_compare = QAction(MainWindow) 34 | self.video_compare.setObjectName(u"video_compare") 35 | self.pqtools2code = QAction(MainWindow) 36 | self.pqtools2code.setObjectName(u"pqtools2code") 37 | self.field_depth_tool = QAction(MainWindow) 38 | self.field_depth_tool.setObjectName(u"field_depth_tool") 39 | self.af_calc_tool = QAction(MainWindow) 40 | self.af_calc_tool.setObjectName(u"af_calc_tool") 41 | self.userguide = QAction(MainWindow) 42 | self.userguide.setObjectName(u"userguide") 43 | self.clearcache = QAction(MainWindow) 44 | self.clearcache.setObjectName(u"clearcache") 45 | self.checkupdate = QAction(MainWindow) 46 | self.checkupdate.setObjectName(u"checkupdate") 47 | self.yuv_viewer = QAction(MainWindow) 48 | self.yuv_viewer.setObjectName(u"yuv_viewer") 49 | self.centralwidget = QWidget(MainWindow) 50 | self.centralwidget.setObjectName(u"centralwidget") 51 | self.gridLayout_2 = QGridLayout(self.centralwidget) 52 | self.gridLayout_2.setObjectName(u"gridLayout_2") 53 | self.mdiArea = QMdiArea(self.centralwidget) 54 | self.mdiArea.setObjectName(u"mdiArea") 55 | self.mdiArea.setAcceptDrops(True) 56 | self.mdiArea.setLineWidth(0) 57 | self.mdiArea.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 58 | self.mdiArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) 59 | self.mdiArea.setViewMode(QMdiArea.TabbedView) 60 | self.mdiArea.setTabsClosable(True) 61 | self.mdiArea.setTabsMovable(True) 62 | self.mdiArea.setTabShape(QTabWidget.Rounded) 63 | 64 | self.gridLayout_2.addWidget(self.mdiArea, 0, 0, 1, 1) 65 | 66 | MainWindow.setCentralWidget(self.centralwidget) 67 | self.menubar = QMenuBar(MainWindow) 68 | self.menubar.setObjectName(u"menubar") 69 | self.menubar.setGeometry(QRect(0, 0, 1140, 22)) 70 | self.menu_2 = QMenu(self.menubar) 71 | self.menu_2.setObjectName(u"menu_2") 72 | self.menuISP = QMenu(self.menubar) 73 | self.menuISP.setObjectName(u"menuISP") 74 | self.menu = QMenu(self.menubar) 75 | self.menu.setObjectName(u"menu") 76 | MainWindow.setMenuBar(self.menubar) 77 | 78 | self.menubar.addAction(self.menu_2.menuAction()) 79 | self.menubar.addAction(self.menuISP.menuAction()) 80 | self.menubar.addAction(self.menu.menuAction()) 81 | self.menu_2.addAction(self.shake_tool) 82 | self.menu_2.addAction(self.imageeditor) 83 | self.menu_2.addAction(self.rawimageeditor) 84 | self.menu_2.addAction(self.video_compare) 85 | self.menu_2.addAction(self.yuv_viewer) 86 | self.menuISP.addAction(self.pqtools2code) 87 | self.menuISP.addAction(self.field_depth_tool) 88 | self.menu.addAction(self.userguide) 89 | self.menu.addAction(self.clearcache) 90 | self.menu.addAction(self.checkupdate) 91 | 92 | self.retranslateUi(MainWindow) 93 | 94 | QMetaObject.connectSlotsByName(MainWindow) 95 | # setupUi 96 | 97 | def retranslateUi(self, MainWindow): 98 | MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"ImageTools", None)) 99 | self.shake_tool.setText(QCoreApplication.translate("MainWindow", u"\u6296\u52a8\u6d4b\u8bd5\u5de5\u5177", None)) 100 | self.imageeditor.setText(QCoreApplication.translate("MainWindow", u"\u56fe\u7247\u5206\u6790\u5de5\u5177", None)) 101 | self.about.setText(QCoreApplication.translate("MainWindow", u"\u5173\u4e8e", None)) 102 | self.rawimageeditor.setText(QCoreApplication.translate("MainWindow", u"raw\u56fe\u5206\u6790\u5de5\u5177", None)) 103 | self.video_compare.setText(QCoreApplication.translate("MainWindow", u"\u89c6\u9891\u5bf9\u6bd4\u5de5\u5177", None)) 104 | self.pqtools2code.setText(QCoreApplication.translate("MainWindow", u"PQtools\u8f6c\u4ee3\u7801", None)) 105 | self.field_depth_tool.setText(QCoreApplication.translate("MainWindow", u"\u955c\u5934\u8ba1\u7b97\u5668", None)) 106 | self.af_calc_tool.setText(QCoreApplication.translate("MainWindow", u"\u955c\u5934\u66f2\u7ebf\u8ba1\u7b97\u5de5\u5177", None)) 107 | self.userguide.setText(QCoreApplication.translate("MainWindow", u"\u7528\u6237\u624b\u518c", None)) 108 | self.clearcache.setText(QCoreApplication.translate("MainWindow", u"\u6e05\u7406\u7f13\u5b58", None)) 109 | self.checkupdate.setText(QCoreApplication.translate("MainWindow", u"\u68c0\u67e5\u66f4\u65b0", None)) 110 | self.yuv_viewer.setText(QCoreApplication.translate("MainWindow", u"YUV\u67e5\u770b\u5de5\u5177", None)) 111 | self.menu_2.setTitle(QCoreApplication.translate("MainWindow", u"\u5de5\u5177", None)) 112 | self.menuISP.setTitle(QCoreApplication.translate("MainWindow", u"ISP", None)) 113 | self.menu.setTitle(QCoreApplication.translate("MainWindow", u"\u5173\u4e8e", None)) 114 | # retranslateUi 115 | 116 | -------------------------------------------------------------------------------- /ui/yuvviewer_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | YUVEditor 4 | 5 | 6 | Qt::WindowModal 7 | 8 | 9 | 10 | 0 11 | 0 12 | 800 13 | 600 14 | 15 | 16 | 17 | YUV图片查看工具 18 | 19 | 20 | 21 | :/tool_icon/resource/main.png:/tool_icon/resource/main.png 22 | 23 | 24 | 25 | 26 | 27 | -1 28 | 29 | 30 | Qt::LeftToRight 31 | 32 | 33 | Qt::ToolButtonIconOnly 34 | 35 | 36 | true 37 | 38 | 39 | QTabWidget::Rounded 40 | 41 | 42 | QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::GroupedDragging|QMainWindow::VerticalTabs 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | Qt::AlignCenter 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | true 66 | 67 | 68 | 69 | 70 | 71 | 0 72 | 0 73 | 74 | 75 | 76 | toolBar_2 77 | 78 | 79 | Qt::LeftToRight 80 | 81 | 82 | Qt::AllToolBarAreas 83 | 84 | 85 | Qt::Vertical 86 | 87 | 88 | RightToolBarArea 89 | 90 | 91 | false 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | :/tool_icon/resource/save_icon.png:/tool_icon/resource/save_icon.png 108 | 109 | 110 | save 111 | 112 | 113 | Ctrl+S 114 | 115 | 116 | 117 | 118 | 119 | :/tool_icon/resource/open.png:/tool_icon/resource/open.png 120 | 121 | 122 | open 123 | 124 | 125 | open 126 | 127 | 128 | 129 | 130 | 131 | :/tool_icon/resource/stats.png:/tool_icon/resource/stats.png 132 | 133 | 134 | 统计信息 135 | 136 | 137 | 统计信息 138 | 139 | 140 | 141 | 142 | 143 | :/tool_icon/resource/down.png:/tool_icon/resource/down.png 144 | 145 | 146 | 下一个图片 147 | 148 | 149 | Down 150 | 151 | 152 | 153 | 154 | 155 | :/tool_icon/resource/up.png:/tool_icon/resource/up.png 156 | 157 | 158 | 上一张图片 159 | 160 | 161 | Up 162 | 163 | 164 | 165 | 166 | 167 | :/tool_icon/resource/delete.png:/tool_icon/resource/delete.png 168 | 169 | 170 | 删除 171 | 172 | 173 | 删除 174 | 175 | 176 | Del 177 | 178 | 179 | 180 | 181 | 182 | :/tool_icon/resource/add.png:/tool_icon/resource/add.png 183 | 184 | 185 | 添加对比图片 186 | 187 | 188 | 189 | 190 | 191 | :/tool_icon/resource/right.png:/tool_icon/resource/right.png 192 | 193 | 194 | 顺时针旋转 195 | 196 | 197 | 198 | 199 | 200 | :/tool_icon/resource/config.png:/tool_icon/resource/config.png 201 | 202 | 203 | YUV配置 204 | 205 | 206 | 207 | 208 | 209 | :/tool_icon/resource/subtract.png:/tool_icon/resource/subtract.png 210 | 211 | 212 | 减少对比图片 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /components/BasicImage.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from PySide2.QtGui import QPixmap, QImage 4 | from os import listdir, remove 5 | from os.path import isfile, join, getmtime, dirname, basename, isdir, splitext 6 | from natsort import natsorted 7 | from components.status_code_enum import * 8 | 9 | YUV_FORMAT_MAP = { 10 | 'NV21': cv2.COLOR_YUV2BGR_NV21, 11 | 'NV12': cv2.COLOR_YUV2BGR_NV12, 12 | 'YCrCb': cv2.COLOR_YCrCb2BGR, 13 | 'YUV420': cv2.COLOR_YUV2BGR_I420, 14 | 'YUV422': cv2.COLOR_YUV2BGR_Y422, 15 | 'UYVY': cv2.COLOR_YUV2BGR_UYVY, 16 | 'YUYV': cv2.COLOR_YUV2BGR_YUYV, 17 | 'YVYU': cv2.COLOR_YUV2BGR_YVYU, 18 | } 19 | 20 | 21 | class YuvParam: 22 | """YUV图像参数""" 23 | 24 | def __init__(self): 25 | self.height = 2160 26 | self.width = 3840 27 | self.yuv_format = 'NV21' 28 | 29 | 30 | class ImageBasic: 31 | """ 32 | 基础图像组件 33 | 具有加载图片,显示,以及基本的图像旋转等操作 34 | """ 35 | 36 | def __init__(self): 37 | self.img = None 38 | self.imgpath = '' # 图片路径 39 | self.height = 0 40 | self.width = 0 41 | self.depth = 0 # 通道数 42 | self.yuv_param = YuvParam() 43 | 44 | def __update_attr(self): 45 | if (self.img is not None): 46 | self.height = self.img.shape[0] 47 | self.width = self.img.shape[1] 48 | self.depth = self.img.shape[2] 49 | 50 | def get_dir(self): 51 | if self.imgpath == '': 52 | return '.' 53 | return dirname(self.imgpath) 54 | 55 | def get_basename(self): 56 | if self.imgpath == '': 57 | return '' 58 | return basename(self.imgpath) 59 | 60 | def remove_image(self): 61 | self.img = None 62 | if isfile(self.imgpath) is False: 63 | return 64 | remove(self.imgpath) 65 | 66 | def load_yuv_config(self, yuv_param: YuvParam): 67 | self.yuv_param = yuv_param 68 | 69 | def load_file(self, filename): 70 | if isfile(filename) is False: 71 | raise FileNotFoundErr 72 | if splitext(filename)[-1] in ['.jpg', '.png', '.bmp']: 73 | self.__load_imagefile(filename) 74 | elif splitext(filename)[-1] in ['.yuv']: 75 | self.__load_yuvfile(filename) 76 | else: 77 | raise ImageFormatNotSupportErr 78 | self.imgpath = filename 79 | self.__update_attr() 80 | 81 | def __load_imagefile(self, filename): 82 | # 防止有中文,因此不使用imread 83 | self.img = cv2.imdecode(np.fromfile(filename, dtype=np.uint8), 1) 84 | if self.img is None: 85 | raise ImageReadErr 86 | 87 | def __load_yuvfile(self, filename): 88 | yuv_format = YUV_FORMAT_MAP.get(self.yuv_param.yuv_format) 89 | if yuv_format is None: 90 | raise ImageFormatNotSupportErr 91 | 92 | yuvdata = np.fromfile(filename, dtype=np.uint8) 93 | if yuvdata is None: 94 | raise ImageNoneErr 95 | if self.yuv_param.yuv_format in ['NV21', 'NV12', 'YUV420']: 96 | if len(yuvdata) != self.yuv_param.height * self.yuv_param.width * 3 / 2: 97 | raise ImageFormatErr 98 | yuvdata = yuvdata.reshape( 99 | self.yuv_param.height * 3 // 2, self.yuv_param.width) 100 | elif self.yuv_param.yuv_format in ['YUYV', 'YVYU']: 101 | if len(yuvdata) != self.yuv_param.height * self.yuv_param.width * 2: 102 | raise ImageFormatErr 103 | px = self.yuv_param.height * self.yuv_param.width 104 | y = yuvdata[0: px] 105 | u = yuvdata[px: px * 3 // 2] 106 | v = yuvdata[px * 3 // 2: px * 2] 107 | uv = np.zeros_like(y) 108 | uv[0::2] = u 109 | uv[1::2] = v 110 | y = y.reshape(self.yuv_param.height, self.yuv_param.width) 111 | uv = uv.reshape(self.yuv_param.height, self.yuv_param.width) 112 | yuvdata = cv2.merge((y, uv)) 113 | else: 114 | raise ImageFormatNotSupportErr 115 | 116 | try: 117 | self.img = cv2.cvtColor(yuvdata, yuv_format) 118 | except Exception: 119 | raise ImageFormatErr 120 | 121 | # display 122 | def display_in_scene(self, scene): 123 | """ 124 | return: true or error string 125 | """ 126 | scene.clear() 127 | if self.img is not None: 128 | # numpy转qimage的标准流程 129 | if len(self.img.shape) == 2: 130 | bytes_per_line = self.img.shape[1] 131 | qimg = QImage( 132 | self.img, self.img.shape[1], self.img.shape[0], bytes_per_line, QImage.Format_Grayscale8) 133 | elif self.img.shape[2] == 3: 134 | bytes_per_line = 3 * self.img.shape[1] 135 | qimg = QImage( 136 | self.img, self.img.shape[1], self.img.shape[0], bytes_per_line, QImage.Format_BGR888) 137 | elif self.img.shape[2] == 4: 138 | bytes_per_line = 4 * self.img.shape[1] 139 | qimg = QImage( 140 | self.img, self.img.shape[1], self.img.shape[0], bytes_per_line, QImage.Format_RGBA8888) 141 | else: 142 | raise ImageFormatNotSupportErr 143 | scene.addPixmap(QPixmap.fromImage(qimg)) 144 | return 145 | raise ImageNoneErr 146 | 147 | # proc 148 | def save_image(self, filename): 149 | if self.img is None: 150 | raise ImageNoneErr 151 | if isdir(dirname(filename)) is False: 152 | raise FilePathNotValidErr 153 | # 解决中文路径的问题, 不使用imwrite 154 | if filename.split('.')[-1] == "jpg": 155 | cv2.imencode('.jpg', self.img)[1].tofile(filename) 156 | elif filename.split('.')[-1] == "png": 157 | cv2.imencode('.png', self.img)[1].tofile(filename) 158 | else: 159 | raise ImageFormatNotSupportErr 160 | 161 | def get_img_point(self, x, y): 162 | """ 163 | 获取图像中一个点的RGB值,注意颜色顺序是BGR 164 | """ 165 | if(x > 0 and x < self.width and y > 0 and y < self.height): 166 | return self.img[y, x] 167 | else: 168 | return None 169 | 170 | def rotate90(self): 171 | """ 172 | 顺时针旋转90度 173 | """ 174 | if self.img is None: 175 | raise ImageNoneErr 176 | self.img = cv2.rotate(self.img, cv2.ROTATE_90_CLOCKWISE) 177 | self.__update_attr() 178 | 179 | def find_next_time_photo(self, nextIndex): 180 | """ 181 | 获取下一个或者上一个图片(按照时间顺序排列) 182 | """ 183 | next_photo_name = '' 184 | index = 0 185 | path = dirname(self.imgpath) 186 | img_name = basename(self.imgpath) 187 | filelist = [f for f in listdir(path) if isfile( 188 | join(path, f)) and f.split('.')[-1] in ["jpg", "png", "bmp", "yuv"]] 189 | filelist = sorted( 190 | filelist, key=lambda x: getmtime(join(path, x))) 191 | files_nums = len(filelist) 192 | if img_name in filelist: 193 | index = filelist.index(img_name) + nextIndex 194 | if(index > len(filelist) - 1): 195 | index = 0 196 | elif(index < 0): 197 | index = len(filelist) - 1 198 | next_photo_name = join(path, filelist[index]) 199 | return (next_photo_name, index, files_nums) 200 | 201 | def find_next_nat_photo(self, nextIndex): 202 | """ 203 | 获取下一个或者上一个图片(按照自然顺序排列) 204 | """ 205 | next_photo_name = '' 206 | index = 0 207 | path = dirname(self.imgpath) 208 | img_name = basename(self.imgpath) 209 | filelist = [f for f in listdir(path) if isfile( 210 | join(path, f)) and f.split('.')[-1] in ["jpg", "png", "bmp", "yuv"]] 211 | natsorted(filelist) 212 | files_nums = len(filelist) 213 | if img_name in filelist: 214 | index = filelist.index(img_name) + nextIndex 215 | if(index > len(filelist) - 1): 216 | index = 0 217 | elif(index < 0): 218 | index = len(filelist) - 1 219 | next_photo_name = join(path, filelist[index]) 220 | return (next_photo_name, index, files_nums) 221 | -------------------------------------------------------------------------------- /components/customwidget.py: -------------------------------------------------------------------------------- 1 | from PySide2.QtCore import Signal, QPointF, Qt 2 | from PySide2.QtWidgets import QGraphicsView, QAbstractScrollArea, QLabel, QFileDialog 3 | from PySide2.QtWidgets import QMessageBox, QGraphicsScene 4 | from components.BasicImage import ImageBasic 5 | from components.status_code_enum import ImageToolError 6 | from components.histview import HistView 7 | 8 | 9 | class ImageView(QGraphicsView): 10 | """ 11 | 自定义的图片显示(可以获取到鼠标位置和放大比例) 12 | """ 13 | sigUpdatePointStatusEvent = Signal(str) # 注意 signal不能嵌套 14 | filenameUpdateEvent = Signal() 15 | sigRectDataEvent = Signal(list) 16 | sceneMousePos = QPointF() 17 | startRectPos = QPointF() 18 | endRectPos = QPointF() 19 | focusOnEvent = Signal() 20 | 21 | def __init__(self, layout, parent=None): 22 | self.img = ImageBasic() 23 | self.rect = [0, 0, 0, 0] 24 | self.scale_ratio = 1.0 25 | self.img_index_str = '' 26 | self.hist_window = None 27 | self.imageFileName = '' 28 | self.isFocus = False 29 | self.scene = QGraphicsScene() 30 | super().__init__(self.scene, parent) 31 | self.setUi() 32 | layout.addWidget(self) 33 | 34 | def Exit(self, layout): 35 | layout.removeWidget(self) 36 | self.setParent(None) 37 | 38 | def setUi(self): 39 | self.setMouseTracking(True) 40 | self.setAcceptDrops(True) 41 | self.setDragMode(QGraphicsView.ScrollHandDrag) 42 | self.setToolTipDuration(-1) 43 | self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) 44 | self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) 45 | self.setSizeAdjustPolicy( 46 | QAbstractScrollArea.AdjustToContents) 47 | self.setTransformationAnchor( 48 | QGraphicsView.AnchorViewCenter) 49 | self.setResizeAnchor(QGraphicsView.AnchorViewCenter) 50 | self.setFocusPolicy(Qt.ClickFocus) 51 | 52 | def focusInEvent(self, QFocusEvent): 53 | self.isFocus = True 54 | self.focusOnEvent.emit() 55 | return super().focusInEvent(QFocusEvent) 56 | 57 | def focusOutEvent(self, QFocusEvent): 58 | self.isFocus = False 59 | return super().focusOutEvent(QFocusEvent) 60 | 61 | def mousePressEvent(self, event): 62 | self.startRectPos = self.mapToScene(event.pos()) 63 | return super().mousePressEvent(event) 64 | 65 | def mouseMoveEvent(self, event): 66 | self.sceneMousePos = self.mapToScene(event.pos()) 67 | self.__update_point_stats() 68 | return super().mouseMoveEvent(event) 69 | 70 | def mouseReleaseEvent(self, event): 71 | if self.dragMode() == QGraphicsView.RubberBandDrag: 72 | self.endRectPos = self.mapToScene(event.pos()) 73 | self.rect = [int(self.startRectPos.x()), int(self.startRectPos.y()), int( 74 | self.endRectPos.x()), int(self.endRectPos.y())] 75 | self.sigRectDataEvent.emit(self.rect) 76 | if self.img.img is not None and self.hist_window is not None and self.hist_window.enable is True: 77 | self.hist_window.update_rect_data(self.img.img, self.rect) 78 | return super().mouseReleaseEvent(event) 79 | 80 | def wheelEvent(self, event): 81 | angle = event.angleD.y() 82 | self.sceneMousePos = self.mapToScene(event.pos()) 83 | self.centerOn(self.sceneMousePos) 84 | if angle > 0: 85 | self.scale(1.25, 1.25) 86 | self.scale_ratio *= 1.25 87 | elif self.scale_ratio > 0.05: 88 | self.scale(0.8, 0.8) 89 | self.scale_ratio *= 0.8 90 | self.__update_point_stats() 91 | return super().wheelEvent(event) 92 | 93 | def dragEnterEvent(self, event): 94 | event.accept() 95 | 96 | def dragMoveEvent(self, event): 97 | event.accept() 98 | 99 | def dropEvent(self, event): 100 | if event.mimeData().hasUrls(): 101 | urls = event.mimeData().urls() 102 | filename = urls[-1].path()[1:] 103 | self.init_image(filename) 104 | return super().dropEvent(event) 105 | 106 | def __update_point_stats(self): 107 | if self.img.img is not None: 108 | int_x = int(self.sceneMousePos.x()) 109 | int_y = int(self.sceneMousePos.y()) 110 | rgb = self.img.get_img_point(int_x, int_y) 111 | if rgb is not None: 112 | scale_ratio = int(self.scale_ratio * 100) 113 | self.sigUpdatePointStatusEvent.emit("x:{},y:{} : R:{} G:{} B:{} 缩放比例:{}%".format( 114 | int_x, int_y, rgb[2], rgb[1], rgb[0], scale_ratio)) 115 | 116 | def display(self): 117 | try: 118 | if self.img.img is not None: 119 | self.img.display_in_scene(self.scene) 120 | self.imageFileName = self.img_index_str + self.img.get_basename() 121 | self.filenameUpdateEvent.emit() 122 | if self.dragMode() == QGraphicsView.RubberBandDrag: 123 | self.sigRectDataEvent.emit(self.rect) 124 | if self.hist_window is not None and self.hist_window.enable is True: 125 | self.hist_window.update_rect_data(self.img.img, self.rect) 126 | except ImageToolError as err: 127 | err.show() 128 | 129 | def init_image(self, filename): 130 | try: 131 | self.img.load_file(filename) 132 | _, index, files_nums = self.img.find_next_time_photo(0) 133 | self.img_index_str = "({}/{})".format(index + 1, files_nums) 134 | self.display() 135 | except ImageToolError as err: 136 | err.show() 137 | 138 | def open_image(self): 139 | try: 140 | imagepath = QFileDialog.getOpenFileName( 141 | None, '打开图片', self.img.get_dir(), "Images (*.jpg *.png *.bmp *.yuv)") 142 | if imagepath[0] != '': 143 | self.init_image(imagepath[0]) 144 | except ImageToolError as err: 145 | err.show() 146 | 147 | def save_image(self): 148 | try: 149 | imagepath = QFileDialog.getSaveFileName( 150 | None, '保存图片', self.img.get_dir(), "JPEG Images (*.jpg);;PNG Images (*.png)") 151 | if imagepath[0] != '': 152 | self.img.save_image(imagepath[0]) 153 | except ImageToolError as err: 154 | err.show() 155 | 156 | def reload_image(self): 157 | if self.img.img is not None: 158 | self.init_image(self.img.imgpath) 159 | 160 | def rotate_photo(self, need_saveimg_in_rotate): 161 | try: 162 | self.img.rotate90() 163 | self.display() 164 | if need_saveimg_in_rotate is True: 165 | self.img.save_image(self.img.imgpath) 166 | except ImageToolError as err: 167 | err.show() 168 | 169 | def delete_photo(self): 170 | next_photo, index, files_nums = self.img.find_next_time_photo(1) 171 | self.img_index_str = "({}/{})".format(index, files_nums - 1) 172 | self.img.remove_image() 173 | self.init_image(next_photo) 174 | 175 | def switch_next_photo(self): 176 | next_photo, index, files_nums = self.img.find_next_time_photo(1) 177 | self.img_index_str = "({}/{})".format(index + 1, files_nums) 178 | self.init_image(next_photo) 179 | 180 | def switch_pre_photo(self): 181 | pre_photo, index, files_nums = self.img.find_next_time_photo(-1) 182 | self.img_index_str = "({}/{})".format(index + 1, files_nums) 183 | self.init_image(pre_photo) 184 | 185 | def on_calc_stats(self): 186 | """打开统计信息的窗口""" 187 | if self.img.img is not None: 188 | self.hist_window = HistView(self) 189 | self.rect = [0, 0, self.img.width, self.img.height] 190 | self.hist_window.update_rect_data(self.img.img, self.rect) 191 | self.hist_window.show() 192 | 193 | 194 | class VideoView(QLabel): 195 | sigDragEvent = Signal(str) 196 | 197 | def __init__(self, parent=None): 198 | super().__init__(parent) 199 | self.setAcceptDrops(True) 200 | 201 | def dragEnterEvent(self, event): 202 | event.accept() 203 | 204 | def dragMoveEvent(self, event): 205 | event.accept() 206 | 207 | def dropEvent(self, event): 208 | if event.mimeData().hasUrls(): 209 | try: 210 | for url in event.mimeData().urls(): 211 | self.sigDragEvent.emit(url.path()[1:]) 212 | except Exception as e: 213 | print(e) 214 | 215 | 216 | def critical_win(string: str, parent=None): 217 | if(string is not None): 218 | QMessageBox.critical( 219 | parent, '警告', string, QMessageBox.Yes, QMessageBox.Yes) 220 | return 221 | 222 | 223 | def info_win(string: str, parent=None): 224 | if(string is not None): 225 | QMessageBox.information( 226 | parent, '提示', string, QMessageBox.Yes, QMessageBox.Yes) 227 | return 228 | -------------------------------------------------------------------------------- /ui/yuvviewer_window.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'yuvviewer_window.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 5.15.2 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide2.QtCore import * 12 | from PySide2.QtGui import * 13 | from PySide2.QtWidgets import * 14 | 15 | import resource_rc 16 | 17 | class Ui_YUVEditor(object): 18 | def setupUi(self, YUVEditor): 19 | if not YUVEditor.objectName(): 20 | YUVEditor.setObjectName(u"YUVEditor") 21 | YUVEditor.setWindowModality(Qt.WindowModal) 22 | YUVEditor.resize(800, 600) 23 | icon = QIcon() 24 | icon.addFile(u":/tool_icon/resource/main.png", QSize(), QIcon.Normal, QIcon.Off) 25 | YUVEditor.setWindowIcon(icon) 26 | YUVEditor.setToolTipDuration(-1) 27 | YUVEditor.setLayoutDirection(Qt.LeftToRight) 28 | YUVEditor.setToolButtonStyle(Qt.ToolButtonIconOnly) 29 | YUVEditor.setAnimated(True) 30 | YUVEditor.setTabShape(QTabWidget.Rounded) 31 | YUVEditor.setDockOptions(QMainWindow.AllowTabbedDocks|QMainWindow.AnimatedDocks|QMainWindow.GroupedDragging|QMainWindow.VerticalTabs) 32 | self.saveimage = QAction(YUVEditor) 33 | self.saveimage.setObjectName(u"saveimage") 34 | icon1 = QIcon() 35 | icon1.addFile(u":/tool_icon/resource/save_icon.png", QSize(), QIcon.Normal, QIcon.Off) 36 | self.saveimage.setIcon(icon1) 37 | self.openimage = QAction(YUVEditor) 38 | self.openimage.setObjectName(u"openimage") 39 | icon2 = QIcon() 40 | icon2.addFile(u":/tool_icon/resource/open.png", QSize(), QIcon.Normal, QIcon.Off) 41 | self.openimage.setIcon(icon2) 42 | self.actionstats = QAction(YUVEditor) 43 | self.actionstats.setObjectName(u"actionstats") 44 | icon3 = QIcon() 45 | icon3.addFile(u":/tool_icon/resource/stats.png", QSize(), QIcon.Normal, QIcon.Off) 46 | self.actionstats.setIcon(icon3) 47 | self.nextphoto = QAction(YUVEditor) 48 | self.nextphoto.setObjectName(u"nextphoto") 49 | icon4 = QIcon() 50 | icon4.addFile(u":/tool_icon/resource/down.png", QSize(), QIcon.Normal, QIcon.Off) 51 | self.nextphoto.setIcon(icon4) 52 | self.prephoto = QAction(YUVEditor) 53 | self.prephoto.setObjectName(u"prephoto") 54 | icon5 = QIcon() 55 | icon5.addFile(u":/tool_icon/resource/up.png", QSize(), QIcon.Normal, QIcon.Off) 56 | self.prephoto.setIcon(icon5) 57 | self.deletephoto = QAction(YUVEditor) 58 | self.deletephoto.setObjectName(u"deletephoto") 59 | icon6 = QIcon() 60 | icon6.addFile(u":/tool_icon/resource/delete.png", QSize(), QIcon.Normal, QIcon.Off) 61 | self.deletephoto.setIcon(icon6) 62 | self.add_compare = QAction(YUVEditor) 63 | self.add_compare.setObjectName(u"add_compare") 64 | icon7 = QIcon() 65 | icon7.addFile(u":/tool_icon/resource/add.png", QSize(), QIcon.Normal, QIcon.Off) 66 | self.add_compare.setIcon(icon7) 67 | self.rotateright = QAction(YUVEditor) 68 | self.rotateright.setObjectName(u"rotateright") 69 | icon8 = QIcon() 70 | icon8.addFile(u":/tool_icon/resource/right.png", QSize(), QIcon.Normal, QIcon.Off) 71 | self.rotateright.setIcon(icon8) 72 | self.yuvconfig = QAction(YUVEditor) 73 | self.yuvconfig.setObjectName(u"yuvconfig") 74 | icon9 = QIcon() 75 | icon9.addFile(u":/tool_icon/resource/config.png", QSize(), QIcon.Normal, QIcon.Off) 76 | self.yuvconfig.setIcon(icon9) 77 | self.delcompare = QAction(YUVEditor) 78 | self.delcompare.setObjectName(u"delcompare") 79 | icon10 = QIcon() 80 | icon10.addFile(u":/tool_icon/resource/subtract.png", QSize(), QIcon.Normal, QIcon.Off) 81 | self.delcompare.setIcon(icon10) 82 | self.centralwidget = QWidget(YUVEditor) 83 | self.centralwidget.setObjectName(u"centralwidget") 84 | self.gridLayout_2 = QGridLayout(self.centralwidget) 85 | self.gridLayout_2.setObjectName(u"gridLayout_2") 86 | self.photo_title = QGroupBox(self.centralwidget) 87 | self.photo_title.setObjectName(u"photo_title") 88 | self.photo_title.setAlignment(Qt.AlignCenter) 89 | self.gridLayout_3 = QGridLayout(self.photo_title) 90 | self.gridLayout_3.setObjectName(u"gridLayout_3") 91 | self.horizontalLayout = QHBoxLayout() 92 | self.horizontalLayout.setObjectName(u"horizontalLayout") 93 | 94 | self.gridLayout_3.addLayout(self.horizontalLayout, 0, 0, 1, 1) 95 | 96 | 97 | self.gridLayout_2.addWidget(self.photo_title, 0, 0, 1, 1) 98 | 99 | YUVEditor.setCentralWidget(self.centralwidget) 100 | self.statusBar = QStatusBar(YUVEditor) 101 | self.statusBar.setObjectName(u"statusBar") 102 | self.statusBar.setMouseTracking(True) 103 | YUVEditor.setStatusBar(self.statusBar) 104 | self.toolBar = QToolBar(YUVEditor) 105 | self.toolBar.setObjectName(u"toolBar") 106 | sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) 107 | sizePolicy.setHorizontalStretch(0) 108 | sizePolicy.setVerticalStretch(0) 109 | sizePolicy.setHeightForWidth(self.toolBar.sizePolicy().hasHeightForWidth()) 110 | self.toolBar.setSizePolicy(sizePolicy) 111 | self.toolBar.setLayoutDirection(Qt.LeftToRight) 112 | self.toolBar.setAllowedAreas(Qt.AllToolBarAreas) 113 | self.toolBar.setOrientation(Qt.Vertical) 114 | YUVEditor.addToolBar(Qt.RightToolBarArea, self.toolBar) 115 | 116 | self.toolBar.addAction(self.openimage) 117 | self.toolBar.addAction(self.saveimage) 118 | self.toolBar.addAction(self.yuvconfig) 119 | self.toolBar.addAction(self.deletephoto) 120 | self.toolBar.addAction(self.actionstats) 121 | self.toolBar.addAction(self.prephoto) 122 | self.toolBar.addAction(self.nextphoto) 123 | self.toolBar.addAction(self.rotateright) 124 | self.toolBar.addAction(self.add_compare) 125 | self.toolBar.addAction(self.delcompare) 126 | 127 | self.retranslateUi(YUVEditor) 128 | 129 | QMetaObject.connectSlotsByName(YUVEditor) 130 | # setupUi 131 | 132 | def retranslateUi(self, YUVEditor): 133 | YUVEditor.setWindowTitle(QCoreApplication.translate("YUVEditor", u"YUV\u56fe\u7247\u67e5\u770b\u5de5\u5177", None)) 134 | #if QT_CONFIG(tooltip) 135 | YUVEditor.setToolTip("") 136 | #endif // QT_CONFIG(tooltip) 137 | self.saveimage.setText(QCoreApplication.translate("YUVEditor", u"save", None)) 138 | #if QT_CONFIG(shortcut) 139 | self.saveimage.setShortcut(QCoreApplication.translate("YUVEditor", u"Ctrl+S", None)) 140 | #endif // QT_CONFIG(shortcut) 141 | self.openimage.setText(QCoreApplication.translate("YUVEditor", u"open", None)) 142 | #if QT_CONFIG(tooltip) 143 | self.openimage.setToolTip(QCoreApplication.translate("YUVEditor", u"open", None)) 144 | #endif // QT_CONFIG(tooltip) 145 | self.actionstats.setText(QCoreApplication.translate("YUVEditor", u"\u7edf\u8ba1\u4fe1\u606f", None)) 146 | #if QT_CONFIG(tooltip) 147 | self.actionstats.setToolTip(QCoreApplication.translate("YUVEditor", u"\u7edf\u8ba1\u4fe1\u606f", None)) 148 | #endif // QT_CONFIG(tooltip) 149 | self.nextphoto.setText(QCoreApplication.translate("YUVEditor", u"\u4e0b\u4e00\u4e2a\u56fe\u7247", None)) 150 | #if QT_CONFIG(shortcut) 151 | self.nextphoto.setShortcut(QCoreApplication.translate("YUVEditor", u"Down", None)) 152 | #endif // QT_CONFIG(shortcut) 153 | self.prephoto.setText(QCoreApplication.translate("YUVEditor", u"\u4e0a\u4e00\u5f20\u56fe\u7247", None)) 154 | #if QT_CONFIG(shortcut) 155 | self.prephoto.setShortcut(QCoreApplication.translate("YUVEditor", u"Up", None)) 156 | #endif // QT_CONFIG(shortcut) 157 | self.deletephoto.setText(QCoreApplication.translate("YUVEditor", u"\u5220\u9664", None)) 158 | #if QT_CONFIG(tooltip) 159 | self.deletephoto.setToolTip(QCoreApplication.translate("YUVEditor", u"\u5220\u9664", None)) 160 | #endif // QT_CONFIG(tooltip) 161 | #if QT_CONFIG(shortcut) 162 | self.deletephoto.setShortcut(QCoreApplication.translate("YUVEditor", u"Del", None)) 163 | #endif // QT_CONFIG(shortcut) 164 | self.add_compare.setText(QCoreApplication.translate("YUVEditor", u"\u6dfb\u52a0\u5bf9\u6bd4\u56fe\u7247", None)) 165 | self.rotateright.setText(QCoreApplication.translate("YUVEditor", u"\u987a\u65f6\u9488\u65cb\u8f6c", None)) 166 | self.yuvconfig.setText(QCoreApplication.translate("YUVEditor", u"YUV\u914d\u7f6e", None)) 167 | self.delcompare.setText(QCoreApplication.translate("YUVEditor", u"\u51cf\u5c11\u5bf9\u6bd4\u56fe\u7247", None)) 168 | self.photo_title.setTitle("") 169 | self.toolBar.setWindowTitle(QCoreApplication.translate("YUVEditor", u"toolBar_2", None)) 170 | # retranslateUi 171 | 172 | -------------------------------------------------------------------------------- /components/ui/histgramview.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ################################################################################ 4 | ## Form generated from reading UI file 'histgramview.ui' 5 | ## 6 | ## Created by: Qt User Interface Compiler version 5.15.0 7 | ## 8 | ## WARNING! All changes made in this file will be lost when recompiling UI file! 9 | ################################################################################ 10 | 11 | from PySide2.QtCore import (QCoreApplication, QDate, QDateTime, QMetaObject, 12 | QObject, QPoint, QRect, QSize, QTime, QUrl, Qt) 13 | from PySide2.QtGui import (QBrush, QColor, QConicalGradient, QCursor, QFont, 14 | QFontDatabase, QIcon, QKeySequence, QLinearGradient, QPalette, QPainter, 15 | QPixmap, QRadialGradient) 16 | from PySide2.QtWidgets import * 17 | 18 | 19 | class Ui_HistgramView(object): 20 | def setupUi(self, HistgramView): 21 | if not HistgramView.objectName(): 22 | HistgramView.setObjectName(u"HistgramView") 23 | HistgramView.resize(777, 482) 24 | sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(HistgramView.sizePolicy().hasHeightForWidth()) 28 | HistgramView.setSizePolicy(sizePolicy) 29 | HistgramView.setSizeGripEnabled(True) 30 | self.gridLayout = QGridLayout(HistgramView) 31 | self.gridLayout.setObjectName(u"gridLayout") 32 | self.groupBox = QGroupBox(HistgramView) 33 | self.groupBox.setObjectName(u"groupBox") 34 | self.groupBox.setMaximumSize(QSize(16777215, 16777215)) 35 | self.gridLayout_9 = QGridLayout(self.groupBox) 36 | self.gridLayout_9.setObjectName(u"gridLayout_9") 37 | self.gridLayout_7 = QGridLayout() 38 | self.gridLayout_7.setObjectName(u"gridLayout_7") 39 | self.groupBox_2 = QGroupBox(self.groupBox) 40 | self.groupBox_2.setObjectName(u"groupBox_2") 41 | self.groupBox_2.setMaximumSize(QSize(16777215, 16777215)) 42 | self.gridLayout_3 = QGridLayout(self.groupBox_2) 43 | self.gridLayout_3.setObjectName(u"gridLayout_3") 44 | self.horizontalLayout_8 = QHBoxLayout() 45 | self.horizontalLayout_8.setObjectName(u"horizontalLayout_8") 46 | self.verticalLayout_5 = QVBoxLayout() 47 | self.verticalLayout_5.setObjectName(u"verticalLayout_5") 48 | self.horizontalLayout_9 = QHBoxLayout() 49 | self.horizontalLayout_9.setObjectName(u"horizontalLayout_9") 50 | self.label_7 = QLabel(self.groupBox_2) 51 | self.label_7.setObjectName(u"label_7") 52 | 53 | self.horizontalLayout_9.addWidget(self.label_7) 54 | 55 | self.snr_r = QDoubleSpinBox(self.groupBox_2) 56 | self.snr_r.setObjectName(u"snr_r") 57 | self.snr_r.setButtonSymbols(QAbstractSpinBox.NoButtons) 58 | self.snr_r.setMaximum(256.000000000000000) 59 | 60 | self.horizontalLayout_9.addWidget(self.snr_r) 61 | 62 | 63 | self.verticalLayout_5.addLayout(self.horizontalLayout_9) 64 | 65 | self.horizontalLayout_10 = QHBoxLayout() 66 | self.horizontalLayout_10.setObjectName(u"horizontalLayout_10") 67 | self.label_8 = QLabel(self.groupBox_2) 68 | self.label_8.setObjectName(u"label_8") 69 | 70 | self.horizontalLayout_10.addWidget(self.label_8) 71 | 72 | self.snr_g = QDoubleSpinBox(self.groupBox_2) 73 | self.snr_g.setObjectName(u"snr_g") 74 | self.snr_g.setButtonSymbols(QAbstractSpinBox.NoButtons) 75 | self.snr_g.setMaximum(256.000000000000000) 76 | 77 | self.horizontalLayout_10.addWidget(self.snr_g) 78 | 79 | 80 | self.verticalLayout_5.addLayout(self.horizontalLayout_10) 81 | 82 | self.horizontalLayout_11 = QHBoxLayout() 83 | self.horizontalLayout_11.setObjectName(u"horizontalLayout_11") 84 | self.label_9 = QLabel(self.groupBox_2) 85 | self.label_9.setObjectName(u"label_9") 86 | 87 | self.horizontalLayout_11.addWidget(self.label_9) 88 | 89 | self.snr_b = QDoubleSpinBox(self.groupBox_2) 90 | self.snr_b.setObjectName(u"snr_b") 91 | self.snr_b.setButtonSymbols(QAbstractSpinBox.NoButtons) 92 | self.snr_b.setMaximum(256.000000000000000) 93 | 94 | self.horizontalLayout_11.addWidget(self.snr_b) 95 | 96 | 97 | self.verticalLayout_5.addLayout(self.horizontalLayout_11) 98 | 99 | 100 | self.horizontalLayout_8.addLayout(self.verticalLayout_5) 101 | 102 | self.verticalLayout_6 = QVBoxLayout() 103 | self.verticalLayout_6.setObjectName(u"verticalLayout_6") 104 | self.verticalLayout_6.setSizeConstraint(QLayout.SetMaximumSize) 105 | self.horizontalLayout_12 = QHBoxLayout() 106 | self.horizontalLayout_12.setObjectName(u"horizontalLayout_12") 107 | self.label_10 = QLabel(self.groupBox_2) 108 | self.label_10.setObjectName(u"label_10") 109 | 110 | self.horizontalLayout_12.addWidget(self.label_10) 111 | 112 | self.snr_y = QDoubleSpinBox(self.groupBox_2) 113 | self.snr_y.setObjectName(u"snr_y") 114 | self.snr_y.setButtonSymbols(QAbstractSpinBox.NoButtons) 115 | self.snr_y.setMaximum(256.000000000000000) 116 | 117 | self.horizontalLayout_12.addWidget(self.snr_y) 118 | 119 | 120 | self.verticalLayout_6.addLayout(self.horizontalLayout_12) 121 | 122 | self.horizontalLayout_13 = QHBoxLayout() 123 | self.horizontalLayout_13.setObjectName(u"horizontalLayout_13") 124 | self.label_11 = QLabel(self.groupBox_2) 125 | self.label_11.setObjectName(u"label_11") 126 | 127 | self.horizontalLayout_13.addWidget(self.label_11) 128 | 129 | self.snr_cr = QDoubleSpinBox(self.groupBox_2) 130 | self.snr_cr.setObjectName(u"snr_cr") 131 | self.snr_cr.setButtonSymbols(QAbstractSpinBox.NoButtons) 132 | self.snr_cr.setMaximum(256.000000000000000) 133 | 134 | self.horizontalLayout_13.addWidget(self.snr_cr) 135 | 136 | 137 | self.verticalLayout_6.addLayout(self.horizontalLayout_13) 138 | 139 | self.horizontalLayout_14 = QHBoxLayout() 140 | self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") 141 | self.label_12 = QLabel(self.groupBox_2) 142 | self.label_12.setObjectName(u"label_12") 143 | 144 | self.horizontalLayout_14.addWidget(self.label_12) 145 | 146 | self.snr_cb = QDoubleSpinBox(self.groupBox_2) 147 | self.snr_cb.setObjectName(u"snr_cb") 148 | self.snr_cb.setButtonSymbols(QAbstractSpinBox.NoButtons) 149 | self.snr_cb.setMaximum(256.000000000000000) 150 | 151 | self.horizontalLayout_14.addWidget(self.snr_cb) 152 | 153 | 154 | self.verticalLayout_6.addLayout(self.horizontalLayout_14) 155 | 156 | 157 | self.horizontalLayout_8.addLayout(self.verticalLayout_6) 158 | 159 | 160 | self.gridLayout_3.addLayout(self.horizontalLayout_8, 0, 0, 1, 1) 161 | 162 | 163 | self.gridLayout_7.addWidget(self.groupBox_2, 0, 0, 1, 1) 164 | 165 | self.groupBox_3 = QGroupBox(self.groupBox) 166 | self.groupBox_3.setObjectName(u"groupBox_3") 167 | self.groupBox_3.setMaximumSize(QSize(16777215, 16777215)) 168 | self.groupBox_3.setFlat(False) 169 | self.gridLayout_2 = QGridLayout(self.groupBox_3) 170 | self.gridLayout_2.setObjectName(u"gridLayout_2") 171 | self.horizontalLayout_7 = QHBoxLayout() 172 | self.horizontalLayout_7.setObjectName(u"horizontalLayout_7") 173 | self.horizontalLayout_7.setSizeConstraint(QLayout.SetMaximumSize) 174 | self.verticalLayout_3 = QVBoxLayout() 175 | self.verticalLayout_3.setObjectName(u"verticalLayout_3") 176 | self.horizontalLayout = QHBoxLayout() 177 | self.horizontalLayout.setObjectName(u"horizontalLayout") 178 | self.label = QLabel(self.groupBox_3) 179 | self.label.setObjectName(u"label") 180 | 181 | self.horizontalLayout.addWidget(self.label) 182 | 183 | self.average_r = QDoubleSpinBox(self.groupBox_3) 184 | self.average_r.setObjectName(u"average_r") 185 | self.average_r.setButtonSymbols(QAbstractSpinBox.NoButtons) 186 | self.average_r.setMaximum(256.000000000000000) 187 | 188 | self.horizontalLayout.addWidget(self.average_r) 189 | 190 | 191 | self.verticalLayout_3.addLayout(self.horizontalLayout) 192 | 193 | self.horizontalLayout_2 = QHBoxLayout() 194 | self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") 195 | self.label_2 = QLabel(self.groupBox_3) 196 | self.label_2.setObjectName(u"label_2") 197 | 198 | self.horizontalLayout_2.addWidget(self.label_2) 199 | 200 | self.average_g = QDoubleSpinBox(self.groupBox_3) 201 | self.average_g.setObjectName(u"average_g") 202 | self.average_g.setButtonSymbols(QAbstractSpinBox.NoButtons) 203 | self.average_g.setMaximum(256.000000000000000) 204 | 205 | self.horizontalLayout_2.addWidget(self.average_g) 206 | 207 | 208 | self.verticalLayout_3.addLayout(self.horizontalLayout_2) 209 | 210 | self.horizontalLayout_3 = QHBoxLayout() 211 | self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") 212 | self.label_3 = QLabel(self.groupBox_3) 213 | self.label_3.setObjectName(u"label_3") 214 | 215 | self.horizontalLayout_3.addWidget(self.label_3) 216 | 217 | self.average_b = QDoubleSpinBox(self.groupBox_3) 218 | self.average_b.setObjectName(u"average_b") 219 | self.average_b.setButtonSymbols(QAbstractSpinBox.NoButtons) 220 | self.average_b.setMaximum(256.000000000000000) 221 | 222 | self.horizontalLayout_3.addWidget(self.average_b) 223 | 224 | 225 | self.verticalLayout_3.addLayout(self.horizontalLayout_3) 226 | 227 | 228 | self.horizontalLayout_7.addLayout(self.verticalLayout_3) 229 | 230 | self.verticalLayout_4 = QVBoxLayout() 231 | self.verticalLayout_4.setObjectName(u"verticalLayout_4") 232 | self.horizontalLayout_4 = QHBoxLayout() 233 | self.horizontalLayout_4.setObjectName(u"horizontalLayout_4") 234 | self.label_4 = QLabel(self.groupBox_3) 235 | self.label_4.setObjectName(u"label_4") 236 | 237 | self.horizontalLayout_4.addWidget(self.label_4) 238 | 239 | self.average_y = QDoubleSpinBox(self.groupBox_3) 240 | self.average_y.setObjectName(u"average_y") 241 | self.average_y.setButtonSymbols(QAbstractSpinBox.NoButtons) 242 | self.average_y.setMaximum(256.000000000000000) 243 | 244 | self.horizontalLayout_4.addWidget(self.average_y) 245 | 246 | 247 | self.verticalLayout_4.addLayout(self.horizontalLayout_4) 248 | 249 | self.horizontalLayout_5 = QHBoxLayout() 250 | self.horizontalLayout_5.setObjectName(u"horizontalLayout_5") 251 | self.label_5 = QLabel(self.groupBox_3) 252 | self.label_5.setObjectName(u"label_5") 253 | 254 | self.horizontalLayout_5.addWidget(self.label_5) 255 | 256 | self.average_cr = QDoubleSpinBox(self.groupBox_3) 257 | self.average_cr.setObjectName(u"average_cr") 258 | self.average_cr.setButtonSymbols(QAbstractSpinBox.NoButtons) 259 | self.average_cr.setMaximum(256.000000000000000) 260 | 261 | self.horizontalLayout_5.addWidget(self.average_cr) 262 | 263 | 264 | self.verticalLayout_4.addLayout(self.horizontalLayout_5) 265 | 266 | self.horizontalLayout_6 = QHBoxLayout() 267 | self.horizontalLayout_6.setObjectName(u"horizontalLayout_6") 268 | self.label_6 = QLabel(self.groupBox_3) 269 | self.label_6.setObjectName(u"label_6") 270 | 271 | self.horizontalLayout_6.addWidget(self.label_6) 272 | 273 | self.average_cb = QDoubleSpinBox(self.groupBox_3) 274 | self.average_cb.setObjectName(u"average_cb") 275 | self.average_cb.setButtonSymbols(QAbstractSpinBox.NoButtons) 276 | self.average_cb.setMaximum(256.000000000000000) 277 | 278 | self.horizontalLayout_6.addWidget(self.average_cb) 279 | 280 | 281 | self.verticalLayout_4.addLayout(self.horizontalLayout_6) 282 | 283 | 284 | self.horizontalLayout_7.addLayout(self.verticalLayout_4) 285 | 286 | 287 | self.gridLayout_2.addLayout(self.horizontalLayout_7, 0, 0, 1, 1) 288 | 289 | 290 | self.gridLayout_7.addWidget(self.groupBox_3, 1, 0, 1, 1) 291 | 292 | self.groupBox_4 = QGroupBox(self.groupBox) 293 | self.groupBox_4.setObjectName(u"groupBox_4") 294 | self.groupBox_4.setMaximumSize(QSize(16777215, 16777215)) 295 | self.gridLayout_6 = QGridLayout(self.groupBox_4) 296 | self.gridLayout_6.setObjectName(u"gridLayout_6") 297 | self.verticalLayout_11 = QVBoxLayout() 298 | self.verticalLayout_11.setObjectName(u"verticalLayout_11") 299 | self.verticalLayout_11.setSizeConstraint(QLayout.SetMaximumSize) 300 | self.horizontalLayout_18 = QHBoxLayout() 301 | self.horizontalLayout_18.setObjectName(u"horizontalLayout_18") 302 | self.label_15 = QLabel(self.groupBox_4) 303 | self.label_15.setObjectName(u"label_15") 304 | 305 | self.horizontalLayout_18.addWidget(self.label_15) 306 | 307 | self.r_gain = QDoubleSpinBox(self.groupBox_4) 308 | self.r_gain.setObjectName(u"r_gain") 309 | self.r_gain.setButtonSymbols(QAbstractSpinBox.NoButtons) 310 | self.r_gain.setDecimals(3) 311 | 312 | self.horizontalLayout_18.addWidget(self.r_gain) 313 | 314 | 315 | self.verticalLayout_11.addLayout(self.horizontalLayout_18) 316 | 317 | self.horizontalLayout_19 = QHBoxLayout() 318 | self.horizontalLayout_19.setObjectName(u"horizontalLayout_19") 319 | self.label_16 = QLabel(self.groupBox_4) 320 | self.label_16.setObjectName(u"label_16") 321 | 322 | self.horizontalLayout_19.addWidget(self.label_16) 323 | 324 | self.g_gain = QDoubleSpinBox(self.groupBox_4) 325 | self.g_gain.setObjectName(u"g_gain") 326 | self.g_gain.setButtonSymbols(QAbstractSpinBox.NoButtons) 327 | self.g_gain.setDecimals(3) 328 | 329 | self.horizontalLayout_19.addWidget(self.g_gain) 330 | 331 | 332 | self.verticalLayout_11.addLayout(self.horizontalLayout_19) 333 | 334 | self.horizontalLayout_20 = QHBoxLayout() 335 | self.horizontalLayout_20.setObjectName(u"horizontalLayout_20") 336 | self.label_17 = QLabel(self.groupBox_4) 337 | self.label_17.setObjectName(u"label_17") 338 | 339 | self.horizontalLayout_20.addWidget(self.label_17) 340 | 341 | self.b_gain = QDoubleSpinBox(self.groupBox_4) 342 | self.b_gain.setObjectName(u"b_gain") 343 | self.b_gain.setButtonSymbols(QAbstractSpinBox.NoButtons) 344 | self.b_gain.setDecimals(3) 345 | 346 | self.horizontalLayout_20.addWidget(self.b_gain) 347 | 348 | 349 | self.verticalLayout_11.addLayout(self.horizontalLayout_20) 350 | 351 | 352 | self.gridLayout_6.addLayout(self.verticalLayout_11, 0, 0, 1, 1) 353 | 354 | 355 | self.gridLayout_7.addWidget(self.groupBox_4, 0, 1, 1, 1) 356 | 357 | self.groupBox_5 = QGroupBox(self.groupBox) 358 | self.groupBox_5.setObjectName(u"groupBox_5") 359 | self.groupBox_5.setMaximumSize(QSize(16777215, 16777215)) 360 | self.gridLayout_5 = QGridLayout(self.groupBox_5) 361 | self.gridLayout_5.setObjectName(u"gridLayout_5") 362 | self.verticalLayout_12 = QVBoxLayout() 363 | self.verticalLayout_12.setObjectName(u"verticalLayout_12") 364 | self.verticalLayout_12.setSizeConstraint(QLayout.SetMaximumSize) 365 | self.horizontalLayout_16 = QHBoxLayout() 366 | self.horizontalLayout_16.setObjectName(u"horizontalLayout_16") 367 | self.label_13 = QLabel(self.groupBox_5) 368 | self.label_13.setObjectName(u"label_13") 369 | 370 | self.horizontalLayout_16.addWidget(self.label_13) 371 | 372 | self.rg_ratio = QDoubleSpinBox(self.groupBox_5) 373 | self.rg_ratio.setObjectName(u"rg_ratio") 374 | self.rg_ratio.setButtonSymbols(QAbstractSpinBox.NoButtons) 375 | self.rg_ratio.setDecimals(3) 376 | 377 | self.horizontalLayout_16.addWidget(self.rg_ratio) 378 | 379 | 380 | self.verticalLayout_12.addLayout(self.horizontalLayout_16) 381 | 382 | self.horizontalLayout_17 = QHBoxLayout() 383 | self.horizontalLayout_17.setObjectName(u"horizontalLayout_17") 384 | self.label_14 = QLabel(self.groupBox_5) 385 | self.label_14.setObjectName(u"label_14") 386 | 387 | self.horizontalLayout_17.addWidget(self.label_14) 388 | 389 | self.bg_ratio = QDoubleSpinBox(self.groupBox_5) 390 | self.bg_ratio.setObjectName(u"bg_ratio") 391 | self.bg_ratio.setButtonSymbols(QAbstractSpinBox.NoButtons) 392 | self.bg_ratio.setDecimals(3) 393 | 394 | self.horizontalLayout_17.addWidget(self.bg_ratio) 395 | 396 | 397 | self.verticalLayout_12.addLayout(self.horizontalLayout_17) 398 | 399 | 400 | self.gridLayout_5.addLayout(self.verticalLayout_12, 0, 0, 1, 1) 401 | 402 | 403 | self.gridLayout_7.addWidget(self.groupBox_5, 1, 1, 1, 1) 404 | 405 | 406 | self.gridLayout_9.addLayout(self.gridLayout_7, 2, 1, 1, 1) 407 | 408 | self.groupBox_6 = QGroupBox(self.groupBox) 409 | self.groupBox_6.setObjectName(u"groupBox_6") 410 | self.groupBox_6.setMaximumSize(QSize(16777215, 153)) 411 | self.gridLayout_4 = QGridLayout(self.groupBox_6) 412 | self.gridLayout_4.setObjectName(u"gridLayout_4") 413 | self.gridLayout_8 = QGridLayout() 414 | self.gridLayout_8.setObjectName(u"gridLayout_8") 415 | self.label_18 = QLabel(self.groupBox_6) 416 | self.label_18.setObjectName(u"label_18") 417 | 418 | self.gridLayout_8.addWidget(self.label_18, 0, 0, 1, 1) 419 | 420 | self.section_y = QSpinBox(self.groupBox_6) 421 | self.section_y.setObjectName(u"section_y") 422 | self.section_y.setButtonSymbols(QAbstractSpinBox.NoButtons) 423 | self.section_y.setMaximum(10000) 424 | 425 | self.gridLayout_8.addWidget(self.section_y, 1, 1, 1, 1) 426 | 427 | self.section_x = QSpinBox(self.groupBox_6) 428 | self.section_x.setObjectName(u"section_x") 429 | self.section_x.setButtonSymbols(QAbstractSpinBox.NoButtons) 430 | self.section_x.setMaximum(10000) 431 | 432 | self.gridLayout_8.addWidget(self.section_x, 0, 1, 1, 1) 433 | 434 | self.label_19 = QLabel(self.groupBox_6) 435 | self.label_19.setObjectName(u"label_19") 436 | 437 | self.gridLayout_8.addWidget(self.label_19, 1, 0, 1, 1) 438 | 439 | self.label_20 = QLabel(self.groupBox_6) 440 | self.label_20.setObjectName(u"label_20") 441 | 442 | self.gridLayout_8.addWidget(self.label_20, 0, 2, 1, 1) 443 | 444 | self.section_width = QSpinBox(self.groupBox_6) 445 | self.section_width.setObjectName(u"section_width") 446 | self.section_width.setButtonSymbols(QAbstractSpinBox.NoButtons) 447 | self.section_width.setMaximum(10000) 448 | 449 | self.gridLayout_8.addWidget(self.section_width, 0, 3, 1, 1) 450 | 451 | self.label_21 = QLabel(self.groupBox_6) 452 | self.label_21.setObjectName(u"label_21") 453 | 454 | self.gridLayout_8.addWidget(self.label_21, 1, 2, 1, 1) 455 | 456 | self.section_height = QSpinBox(self.groupBox_6) 457 | self.section_height.setObjectName(u"section_height") 458 | self.section_height.setButtonSymbols(QAbstractSpinBox.NoButtons) 459 | self.section_height.setMaximum(10000) 460 | 461 | self.gridLayout_8.addWidget(self.section_height, 1, 3, 1, 1) 462 | 463 | 464 | self.gridLayout_4.addLayout(self.gridLayout_8, 1, 0, 1, 1) 465 | 466 | 467 | self.gridLayout_9.addWidget(self.groupBox_6, 1, 1, 1, 1) 468 | 469 | 470 | self.gridLayout.addWidget(self.groupBox, 0, 1, 1, 1) 471 | 472 | self.groupBox_7 = QGroupBox(HistgramView) 473 | self.groupBox_7.setObjectName(u"groupBox_7") 474 | self.groupBox_7.setMinimumSize(QSize(437, 0)) 475 | self.gridLayout_10 = QGridLayout(self.groupBox_7) 476 | self.gridLayout_10.setObjectName(u"gridLayout_10") 477 | self.widget = QWidget(self.groupBox_7) 478 | self.widget.setObjectName(u"widget") 479 | sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) 480 | sizePolicy1.setHorizontalStretch(1) 481 | sizePolicy1.setVerticalStretch(0) 482 | sizePolicy1.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) 483 | self.widget.setSizePolicy(sizePolicy1) 484 | self.widget.setMinimumSize(QSize(352, 0)) 485 | 486 | self.gridLayout_10.addWidget(self.widget, 1, 1, 1, 1) 487 | 488 | self.verticalLayout_7 = QVBoxLayout() 489 | self.verticalLayout_7.setObjectName(u"verticalLayout_7") 490 | self.verticalLayout_7.setSizeConstraint(QLayout.SetFixedSize) 491 | self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) 492 | 493 | self.verticalLayout_7.addItem(self.verticalSpacer_3) 494 | 495 | self.verticalLayout = QVBoxLayout() 496 | self.verticalLayout.setObjectName(u"verticalLayout") 497 | self.r_enable = QCheckBox(self.groupBox_7) 498 | self.r_enable.setObjectName(u"r_enable") 499 | self.r_enable.setMinimumSize(QSize(31, 0)) 500 | self.r_enable.setMaximumSize(QSize(60, 16777215)) 501 | self.r_enable.setChecked(True) 502 | 503 | self.verticalLayout.addWidget(self.r_enable) 504 | 505 | self.g_enable = QCheckBox(self.groupBox_7) 506 | self.g_enable.setObjectName(u"g_enable") 507 | self.g_enable.setMinimumSize(QSize(31, 0)) 508 | self.g_enable.setMaximumSize(QSize(60, 16777215)) 509 | self.g_enable.setChecked(True) 510 | 511 | self.verticalLayout.addWidget(self.g_enable) 512 | 513 | self.b_enable = QCheckBox(self.groupBox_7) 514 | self.b_enable.setObjectName(u"b_enable") 515 | self.b_enable.setMinimumSize(QSize(31, 0)) 516 | self.b_enable.setMaximumSize(QSize(60, 16777215)) 517 | self.b_enable.setChecked(True) 518 | 519 | self.verticalLayout.addWidget(self.b_enable) 520 | 521 | self.y_enable = QCheckBox(self.groupBox_7) 522 | self.y_enable.setObjectName(u"y_enable") 523 | self.y_enable.setMinimumSize(QSize(31, 0)) 524 | self.y_enable.setMaximumSize(QSize(60, 16777215)) 525 | self.y_enable.setChecked(True) 526 | 527 | self.verticalLayout.addWidget(self.y_enable) 528 | 529 | 530 | self.verticalLayout_7.addLayout(self.verticalLayout) 531 | 532 | self.verticalSpacer_4 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) 533 | 534 | self.verticalLayout_7.addItem(self.verticalSpacer_4) 535 | 536 | 537 | self.gridLayout_10.addLayout(self.verticalLayout_7, 1, 2, 1, 1) 538 | 539 | 540 | self.gridLayout.addWidget(self.groupBox_7, 0, 0, 1, 1) 541 | 542 | 543 | self.retranslateUi(HistgramView) 544 | 545 | QMetaObject.connectSlotsByName(HistgramView) 546 | # setupUi 547 | 548 | def retranslateUi(self, HistgramView): 549 | HistgramView.setWindowTitle(QCoreApplication.translate("HistgramView", u"\u7edf\u8ba1\u4fe1\u606f", None)) 550 | self.groupBox.setTitle(QCoreApplication.translate("HistgramView", u"\u8be6\u7ec6\u4fe1\u606f", None)) 551 | self.groupBox_2.setTitle(QCoreApplication.translate("HistgramView", u"\u4fe1\u566a\u6bd4(db)", None)) 552 | self.label_7.setText(QCoreApplication.translate("HistgramView", u"R:", None)) 553 | self.label_8.setText(QCoreApplication.translate("HistgramView", u"G:", None)) 554 | self.label_9.setText(QCoreApplication.translate("HistgramView", u"B:", None)) 555 | self.label_10.setText(QCoreApplication.translate("HistgramView", u"Y:", None)) 556 | self.label_11.setText(QCoreApplication.translate("HistgramView", u"cr:", None)) 557 | self.label_12.setText(QCoreApplication.translate("HistgramView", u"Cb:", None)) 558 | self.groupBox_3.setTitle(QCoreApplication.translate("HistgramView", u"\u5e73\u5747\u503c", None)) 559 | self.label.setText(QCoreApplication.translate("HistgramView", u"R:", None)) 560 | self.label_2.setText(QCoreApplication.translate("HistgramView", u"G:", None)) 561 | self.label_3.setText(QCoreApplication.translate("HistgramView", u"B:", None)) 562 | self.label_4.setText(QCoreApplication.translate("HistgramView", u"Y:", None)) 563 | self.label_5.setText(QCoreApplication.translate("HistgramView", u"cr:", None)) 564 | self.label_6.setText(QCoreApplication.translate("HistgramView", u"Cb:", None)) 565 | self.groupBox_4.setTitle(QCoreApplication.translate("HistgramView", u"\u767d\u5e73\u8861\u589e\u76ca", None)) 566 | self.label_15.setText(QCoreApplication.translate("HistgramView", u"R:", None)) 567 | self.label_16.setText(QCoreApplication.translate("HistgramView", u"G:", None)) 568 | self.label_17.setText(QCoreApplication.translate("HistgramView", u"B:", None)) 569 | self.groupBox_5.setTitle(QCoreApplication.translate("HistgramView", u"\u6bd4\u503c", None)) 570 | self.label_13.setText(QCoreApplication.translate("HistgramView", u"R/G", None)) 571 | self.label_14.setText(QCoreApplication.translate("HistgramView", u"B/G", None)) 572 | self.groupBox_6.setTitle(QCoreApplication.translate("HistgramView", u"\u9009\u533a\u5927\u5c0f", None)) 573 | self.label_18.setText(QCoreApplication.translate("HistgramView", u"X:", None)) 574 | self.label_19.setText(QCoreApplication.translate("HistgramView", u"Y:", None)) 575 | self.label_20.setText(QCoreApplication.translate("HistgramView", u"\u5bbd", None)) 576 | self.label_21.setText(QCoreApplication.translate("HistgramView", u"\u9ad8", None)) 577 | self.groupBox_7.setTitle(QCoreApplication.translate("HistgramView", u"\u76f4\u65b9\u56fe", None)) 578 | self.r_enable.setText(QCoreApplication.translate("HistgramView", u"R", None)) 579 | self.g_enable.setText(QCoreApplication.translate("HistgramView", u"G", None)) 580 | self.b_enable.setText(QCoreApplication.translate("HistgramView", u"B", None)) 581 | self.y_enable.setText(QCoreApplication.translate("HistgramView", u"Y", None)) 582 | # retranslateUi 583 | 584 | -------------------------------------------------------------------------------- /components/ui/histgramview.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | HistgramView 4 | 5 | 6 | 7 | 0 8 | 0 9 | 777 10 | 482 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 统计信息 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | 16777215 31 | 16777215 32 | 33 | 34 | 35 | 详细信息 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 16777215 45 | 16777215 46 | 47 | 48 | 49 | 信噪比(db) 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | R: 62 | 63 | 64 | 65 | 66 | 67 | 68 | QAbstractSpinBox::NoButtons 69 | 70 | 71 | 256.000000000000000 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | G: 83 | 84 | 85 | 86 | 87 | 88 | 89 | QAbstractSpinBox::NoButtons 90 | 91 | 92 | 256.000000000000000 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | B: 104 | 105 | 106 | 107 | 108 | 109 | 110 | QAbstractSpinBox::NoButtons 111 | 112 | 113 | 256.000000000000000 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | QLayout::SetMaximumSize 125 | 126 | 127 | 128 | 129 | 130 | 131 | Y: 132 | 133 | 134 | 135 | 136 | 137 | 138 | QAbstractSpinBox::NoButtons 139 | 140 | 141 | 256.000000000000000 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | cr: 153 | 154 | 155 | 156 | 157 | 158 | 159 | QAbstractSpinBox::NoButtons 160 | 161 | 162 | 256.000000000000000 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | Cb: 174 | 175 | 176 | 177 | 178 | 179 | 180 | QAbstractSpinBox::NoButtons 181 | 182 | 183 | 256.000000000000000 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 16777215 201 | 16777215 202 | 203 | 204 | 205 | 平均值 206 | 207 | 208 | false 209 | 210 | 211 | 212 | 213 | 214 | QLayout::SetMaximumSize 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | R: 224 | 225 | 226 | 227 | 228 | 229 | 230 | QAbstractSpinBox::NoButtons 231 | 232 | 233 | 256.000000000000000 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | G: 245 | 246 | 247 | 248 | 249 | 250 | 251 | QAbstractSpinBox::NoButtons 252 | 253 | 254 | 256.000000000000000 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | B: 266 | 267 | 268 | 269 | 270 | 271 | 272 | QAbstractSpinBox::NoButtons 273 | 274 | 275 | 256.000000000000000 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | Y: 291 | 292 | 293 | 294 | 295 | 296 | 297 | QAbstractSpinBox::NoButtons 298 | 299 | 300 | 256.000000000000000 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | cr: 312 | 313 | 314 | 315 | 316 | 317 | 318 | QAbstractSpinBox::NoButtons 319 | 320 | 321 | 256.000000000000000 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | Cb: 333 | 334 | 335 | 336 | 337 | 338 | 339 | QAbstractSpinBox::NoButtons 340 | 341 | 342 | 256.000000000000000 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 16777215 360 | 16777215 361 | 362 | 363 | 364 | 白平衡增益 365 | 366 | 367 | 368 | 369 | 370 | QLayout::SetMaximumSize 371 | 372 | 373 | 374 | 375 | 376 | 377 | R: 378 | 379 | 380 | 381 | 382 | 383 | 384 | QAbstractSpinBox::NoButtons 385 | 386 | 387 | 3 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | G: 399 | 400 | 401 | 402 | 403 | 404 | 405 | QAbstractSpinBox::NoButtons 406 | 407 | 408 | 3 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | B: 420 | 421 | 422 | 423 | 424 | 425 | 426 | QAbstractSpinBox::NoButtons 427 | 428 | 429 | 3 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 16777215 445 | 16777215 446 | 447 | 448 | 449 | 比值 450 | 451 | 452 | 453 | 454 | 455 | QLayout::SetMaximumSize 456 | 457 | 458 | 459 | 460 | 461 | 462 | R/G 463 | 464 | 465 | 466 | 467 | 468 | 469 | QAbstractSpinBox::NoButtons 470 | 471 | 472 | 3 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | B/G 484 | 485 | 486 | 487 | 488 | 489 | 490 | QAbstractSpinBox::NoButtons 491 | 492 | 493 | 3 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 16777215 511 | 153 512 | 513 | 514 | 515 | 选区大小 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | X: 524 | 525 | 526 | 527 | 528 | 529 | 530 | QAbstractSpinBox::NoButtons 531 | 532 | 533 | 10000 534 | 535 | 536 | 537 | 538 | 539 | 540 | QAbstractSpinBox::NoButtons 541 | 542 | 543 | 10000 544 | 545 | 546 | 547 | 548 | 549 | 550 | Y: 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | QAbstractSpinBox::NoButtons 565 | 566 | 567 | 10000 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | QAbstractSpinBox::NoButtons 582 | 583 | 584 | 10000 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 437 601 | 0 602 | 603 | 604 | 605 | 直方图 606 | 607 | 608 | 609 | 610 | 611 | QLayout::SetFixedSize 612 | 613 | 614 | 615 | 616 | Qt::Vertical 617 | 618 | 619 | 620 | 20 621 | 40 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 31 633 | 0 634 | 635 | 636 | 637 | 638 | 60 639 | 16777215 640 | 641 | 642 | 643 | R 644 | 645 | 646 | true 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 31 655 | 0 656 | 657 | 658 | 659 | 660 | 60 661 | 16777215 662 | 663 | 664 | 665 | G 666 | 667 | 668 | true 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 31 677 | 0 678 | 679 | 680 | 681 | 682 | 60 683 | 16777215 684 | 685 | 686 | 687 | B 688 | 689 | 690 | true 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 31 699 | 0 700 | 701 | 702 | 703 | 704 | 60 705 | 16777215 706 | 707 | 708 | 709 | Y 710 | 711 | 712 | true 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | Qt::Vertical 722 | 723 | 724 | 725 | 20 726 | 40 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 1 738 | 0 739 | 740 | 741 | 742 | 743 | 352 744 | 0 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | -------------------------------------------------------------------------------- /resource_rc.py: -------------------------------------------------------------------------------- 1 | # Resource object code (Python 3) 2 | # Created by: object code 3 | # Created by: The Resource Compiler for Qt version 5.15.2 4 | # WARNING! All changes made in this file will be lost! 5 | 6 | from PySide2 import QtCore 7 | 8 | qt_resource_data = b"\ 9 | \x00\x00\x02\xab\ 10 | \x89\ 11 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 12 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 13 | \x00\x00\x02rIDATXG\xcd\xd7Mh\x13A\ 14 | \x14\x07\xf0\xfflz\xb0;\x09\x1eD\xacP\x94f\x82\ 15 | BQ\xc4\x83\xa7Rh=\x08V\xf0\xe0\xa1&\xb3T\ 16 | \xbc\x88R\x14\x04\xc1\x83\x08m\x0f\x22\x88\x17\x0fE\xe8\ 17 | Il\xb3\x91\x08z\xf0\xe3\x22h\x91\xa2\x88 R,\ 18 | H\xccL\x14\xa9X\x0f\x22&\xdbRI\xf7I\x0b\x0d\ 19 | \xd5M\xe3\x122\xa6{\xdc\x9dy\xef\xb7\x8f\xb7\xb33\ 20 | \x0cM\xbeX\x93\xf3cc\x01\x8a\xe9\xf8p\xad\x8aD\ 21 | \x80i\xdb\xd1\xf7\x1aY\xb5J\x05Jn|\x82\x819\ 22 | \xff\x08\xbe\xe0/\xb1\xbe\xd8@~\xb2Q\x88\x0a\xc0s\ 23 | \x05\x85\x0c:K\xf0\xfb\xa2\xb20\x1dr|\xcda\xf5\ 24 | \x00\xea\xc9\xfb\x11\x16\x9d\xe3I\xfd\xf0\xef\xc9\xff\x0b\x00\ 25 | 0\xdc\xe5)\xd5\xdf4\x00\x03&m\xa9z\xc3\x02\x16\ 26 | \x19\xf0\xb2\x9eZ\xd7\x9a\x13\x12@\xaf\xb0d\x0d\xf2\x81\ 27 | \xfc\x9bF\x03\xaa\xc5\x0b\xf4\x80O4\x12s\xf4\xcaz\ 28 | \xe0e\xe2C&\x10<\xa5GV\xe3\x06\x01`\xc7c\ 29 | 2\x9f\x0d\xb9.\xd4\xeb\x9b\xe1R\xedY\x9e\x1c\x04X\ 30 | \xd8\x1bK\xaaw\xf3\xaexO\xc0\xeez3\xd4\x9cG\ 31 | T\xe0\x8e\x8eW\x01\xb0\xefv.\xbf\xb5\xd4\x99\xd8b\ 32 | \x95\xe9\x9b\x91\xe4+A\xe9\x01\x97\xfah\xb5\x0aLq\ 33 | \xa9\xba\x7ff:\xba#d=7\x08\xb8\xca\xa5\xbe\x14\ 34 | \x04\x10\xc6\xb8\xa3N{\x13\xe2\x14,\x8c\x99\x02X\x8c\ 35 | \x9c\xd6\x94v\x03\x00\x22:\x1fu\xf4\x8dyW\x5c'\ 36 | \xe0\x82)\x00\xc1\xdf\xb7\xfa/\xf9\xa3\x09\x09\xfe\xa1\xa8\ 37 | ,<\xf12\xe21\x08\x87\x0d\x01~\xd99\xd5\xca\x86\ 38 | \xe1\x07*\xc0Z\x22\xedv\x7fn\xd6s\xc5g\x00\xed\ 39 | f\x00\xf4\x96K\xbd\xbf\xda:P\xe0Rux\xe3;\ 40 | \xb7#\xd2\xf2\xc5Lr\x80\x11sm'_\xd9w\xac\ 41 | \xd9\x90\x88GQ\xa9\x8e\x14\xd3\xa2\xd7bxj\x0a\x00\ 42 | \xe02\x97\xeaJ\xa0\x02\xf3\xae\xb8fKu\xd1s\x13\ 43 | \x83\x00\x8d\x9a\x020\x86cvJ\xdd\x0f\x00Jiq\ 44 | 2\xea\xa8[^Z\xdc\x04\xc3\x19S\x80\x08\xd1\xaeM\ 45 | \x8e\xfe\x10\xec\x81;\xf1\x03<\xa9_{i1\x05\x86\ 46 | .C\x809.U\xdb\xda\xd8\x95\x1e\xf8z{\x1bo\ 47 | ;1\xe7y\x19\xf1\x03\x84\xcd&\x00\x0cxfKu\ 48 | \xb0*`\xf9\xe6B6\xbe\xc3/\xb3O&\x92\xaf|\ 49 | \xf3\x8cF\xed\x94>\xbb.`1\x9b\xe8,\x97i\xc6\ 50 | \x1c\x00]vJ\xbdX\x17\xb0\xfc\xa08\x9e\xe8\x81\xe5\ 51 | \xf74\x1c\xe1[\x93\xd5\xce\x13\x1b\xebh\xd6\xf0\xb7\x0e\ 52 | \x11\xb0\xe9\x15\xf8\x0d\x81\xee\xfa!\xb0f]g\x00\x00\ 53 | \x00\x00IEND\xaeB`\x82\ 54 | \x00\x00\x02t\ 55 | \x89\ 56 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 57 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 58 | \x00\x00\x02;IDATXG\xcd\x97\x811\x04A\ 59 | \x10E\xffE\x80\x08\x10\x01\x22@\x06.\x02D\x80\x08\ 60 | \x10\x012 \x022\xe0\x22p\x17\x81\xcb\x00\x11PO\ 61 | M_\xf5\xee\xed\xect\xedn\xd5\x9a\xaa\xabUk\xb6\ 62 | \xfb\xf7\xef?=\xdd\x13\xc5\xd7\xa6\xa4CI'\x92v\ 63 | \xdc\x0f\x0bK\xf7{\x914\x93\xf4\x151=\x09l\xc2\ 64 | \xd9\xb5\xa4\xb3\xc0^\xbf\xe5Q\xd2m\x02\x96\xfd\xb4\x0d\ 65 | \x00\x11\xe3\xf8\xd2}MdD8w\x11\xf3\xef}I\ 66 | \xec\xe7\x09\xd0=\xf7\xcd\x8d\xa4\x87\x1c#9\x00\x18{\ 67 | M\x06\xb1\xf5$\x09CP\x1dY\xb0\xc6\xfe\xd3\xb4\x19\ 68 | \xc0\xc7M \x9a\x00\x10\x05\xce\x01\xb1H\x11a\xa0\xcb\ 69 | \xc2\x16\x8cm'\xe7\x80\xa8\xd8\xaa\x03\xc0\xe9Gr\x0e\ 70 | \xdd\x08.$\xa6\x16t\xd8\x04\x04\x02\xc6\xd6\xae\xb7\xe9\ 71 | \x01x\xdaq~\xd4%\xe4\x96o\xde\x12\x88J:<\ 72 | \x80{I\x17\x89v\x9c\xf7\x8d\xbc\x8e\x85\x00qN:\ 73 | 8\x1dhD\x06\x00\xd1@=\xeb\xa0\x9e\xa7\x01\x99@\ 74 | \x13\xef\xc9\x1e\xa9X\x1a\x00\xce,\x8aE\xed\xa5\xf3\x0e\ 75 | \x95?I\xd5\x1e[\xee}\x1d\x7f\xc5\x17\x00\xa0\xe6\xd3\ 76 | \xa3*D\x8cs\xcf\x9em\xcf\xbd\xaf\x9b\xf3lo\x01\ 77 | \x00\xa5?\xa7\xf2\x19\x11^_\x00\x00B\x0b\x14\xab)\ 78 | \x00\x8c\x92+I\x08\xb1\xb4\x86\x00@u\xbd#\xe5\x00\ 79 | \xb0\xe3A\x91\xe0\xef\xd2\x1a\x02\x00LS\xecf\x00\xa0\ 80 | \xbcr4\xfeTY\xf2\x9e\x04\xd8G\x03|k\xa7a\ 81 | \x0e\x80\xa8xJb\xebd\xe7_\x00\x183\x05\x8b\x7f\ 82 | !\xc2\xd1\x8f\xe1\xe8\x85h\xccR<\xe9z\x19q$\ 83 | \xebe\xdb\x8aX\xa9\x9c\xaf]F\x18\x1b\xfd:\x06\x04\ 84 | \x0d\x02]p\xb6\x81\x0cT\xc9\xb6-\xa4\x9a^\x80`\ 85 | \xd7\x1a\x12>d\x034rK\xf1\xe4n\x18r\xd9\x0d\ 86 | H\xa3\xbb\xea\xb8\x9a\x9aR\x0a\xd3F\x021\x1d\xa05\ 87 | #0\xae{\x9c~'\x06V\xed^\xae-\x87\x01@\ 88 | \x80\xfa\xbcG\x8b\xc6\xa5\x83sh\xc79 Z\xdbr\ 89 | \xa3\xdc\xa7\x83w\xa11\xcb\xe5\xab>\xceUh\xf7y\ 90 | -\x8df4\x0e\x08\xd3\x16\xe8\x01\xc3\x93\x88,\x1a\x22\ 91 | \x851\x1b\xcdx\xdaBp4:\x8d]vt8\xf5\ 92 | cVT\x98\xa1q.\x02\xc0\xa7\x85\x1c\xdaxN\x9a\ 93 | l\x08\x85b\x22D\xc0LAh(4W\xfc\x02\x9d\ 94 | \xa8\xaf.%jA(\x00\x00\x00\x00IEND\xae\ 95 | B`\x82\ 96 | \x00\x00\x02\xc2\ 97 | \x89\ 98 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 99 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 100 | \x00\x00\x02\x89IDATXG\xd5\x96?\x88\x13A\ 101 | \x14\xc6\xbf\xb7\x84\x14\x82'VZ\x1cr\x8dX\x08\x16\ 102 | \x16\x07\x9e\x88\xca\x81&\xe6m\x10$`\xa1\xc2uV\ 103 | \x8a(\xc8\xa1\x22(\x1c\xa2h\xa1\x88\x85\x8d(j#\ 104 | \x82;/\x1b\x13\xae8,lT\xc4?\x85\x85\xd55\ 105 | j\xa5\xa2\x12L\xc8\x8c\xac\xe4bL6\x99\xd9\x9c!\ 106 | \xb8\xed~\xef{\xbf\xfdf\xde\xcc\x12F\xfc\xd0\x88\xfb\ 107 | \xe3\xff\x06`\xe6i\xad\xf5\xf7F\xa3\xb1X.\x97?\ 108 | \x0c\x92\xe6\xb2\x12`\xe6'\x00\xb65\x1b/\x02(\x03\ 109 | \xb8'\x22\x0b\xae0\x03\x03\xe4\xf3\xf9\x0dZ\xeb\x9bm\ 110 | \x00\xad\x9eD\xf4\x98\x88\xce\x04A\xf0\xdc\x06\xe2\x0c\xc0\ 111 | \xcc\xeb\x88h\xab1f\x8a\x886\x19c\xce\x028\x17\ 112 | \x07\xd0\xd6\xf4\xa8\x88\x5c\xed\x07\xe1\x04\xc0\xcc\xa7\x01\x9c\ 113 | \xef0\xda\xe9\x00\x00\x22\x9aSJ\x9d\xea\x05a\x05`\ 114 | \xe6\x10@6\xc6\xc0\x09\xa0Y7+\x22\x17\xe2 \xfa\ 115 | \x020\xf3\x17\x00\xabz\xd0'\x01\x88,v\x8bH\xa5\ 116 | \xd3\xab'\x003\xdf\x00p\xb8\xcf\xfa%\x05x)\x22\ 117 | \x9b\x9d\x00\xa2\xf9\x060o\xd9\xc1I\x01\xa2\xfd0\xa3\ 118 | \x94\xba\xd5\xee\xdb\x95@>\x9f_\xa9\xb5\x8e\x9aO\xfe\ 119 | k\x00\x00\x0b\x22\x12\x81\xff\x19\xd9\xce&\xbe\xef\x1f4\ 120 | \xc6\xdc\xb6\xcd/\x80\xc4\x09D\x9e\x9e\xe7\xad\x0d\x82\xe0\ 121 | \xd3\x92\x7fW\x02\xb9\x5c\xee\x12\x11\x9d\x18\x16\x80\xd6z\ 122 | o\x18\x86\x8fz\x020st\x9c\xee\x1a\x16\x00\x80\x93\ 123 | \x22r\xb1\x1f\xc0G\x00k\x86\x08pYDZ\x09w\ 124 | -\x013\x7f\x050\xe6\x02`\x8cy\xe5\xa0\xeb\x92\x14\ 125 | \x8b\xc5\xcf\xfd\x12x\x0b`\xa3\x83\xb1\xf3\x8d\x17y\x11\ 126 | \xd1C\xa5\xd45\xeb9\xc0\xcc\xf7\x01\xecw\x00H$\ 127 | \xf1\x07.\xee\x02\xc0\xce\xbcI\x1a\x07\xb4\ 156 | @\xe32\x06\x00^Q\xde\xc6\xdd%\xe0\x001\x91\xc4\ 157 | \xef\x89\xa3u\x16\x02@\xe9G\x83\xf2\x85\xa4G\xc7-\ 158 | \x97!\x80\xc6\x22\x02t+\x83\x06J\x08R\xf6!+\ 159 | \x00^3n\x9fI\xbat\x17\xe4,>p\xbc\xef\x16\ 160 | \xb8\xe5\x17\x05\x5cN\xd0\xc5\xe4\xdc]Zpg\xbd\x85\ 161 | \xe0%{\xb2b\x14\xe4\x5c\x0fo\xa4T\x17\x81\xeb\xdb\ 162 | \xdcA\x03\x80\x82\xe3\xc8\xc6.\x96\xfb\xd7\xa0\x1c\x10I\ 163 | 1\x00\x9f\x91\xc0\x83s\xf8\xec\x22\xc5i\x0c\x00\x22\xf2\ 164 | !\xa2\x85\xbc%b\xbbH\x11\xff\x5c\x0c\x80\x98\xfbI\ 165 | 5\xd2\xaa\x8f`\x18\x1f^L\xa5\xe6\x02\x00X\xb9\x1f\ 166 | h\xbaq%\xb8\x0f\x00\xff,\xc6\x00\x84z\xc1\xaf\xa5\ 167 | \xe8\x14\x00\xb1\xdc\xef\x13\xf9\xad@\x03\xe0{\xcd\xfc\xff\ 168 | ?\x00\xd4\xf3\xb0l\x0eE\x01\x95\x91\x0c\xa9\xdb\xf4_\ 169 | \x05!\xb4\xc4J\xfd8\x95\x86\x8cV;\xad\xc8l\xde\ 170 | L\x97\x0dS\xbb\xca\x82!\x0aQ\x08\x87\xd4c\xc6\x08\ 171 | eb\xa5\x18N6\x82U\xea\x03\xd5p\x1d\x82\xf2\xb0\ 172 | \xac\x7f\xe1\x91\xa1\x9bQ\x8a{\xfe\x7fO\xa3\xf2\xdb1\ 173 | \xbc\x87^`c\x9f\x8c\xc8\xb5cbl\xee\x8fd\xb9\ 174 | \x81\x84\xd4\xa1<\xb7\x91\xd3\xcc\x10\xc3\xb8\x8e\xbe\xaa\x19\ 175 | \xf9\x12\xab\x09\xb6NLp\xb0\xa9C\xc25\x93U\xaa\ 176 | \x95\xbf\xbb\xb5\xea\xe1\x12\x1bJST\x18\x10\xd6\xc3\xa1\ 177 | \x94\xf4\xa2\xd1\xd8\xab)\xe5)\x02\x8f}\xdcQIj\ 178 | ,\xc7\xcaX<\xb4\xa1 \xdc\x8br\xbcb\x93t\x12\ 179 | \x00\x0bL4\x80(\x99lK@\xe1v\xbcS[\x9e\ 180 | \xf3\x80\xad\x01\x82\xe0\xe3\xeb\xe3\x8d:\xe0bH\x9b\xde\ 181 | \x86\x9c\x81_\x22\x16\x0bJ\x81\xe0n&-\xde\x85+\ 182 | V\xfb@J\x00\xf8\xfbm\xcc\xb2\xe7\xb9Q\xc4\x08\x87\ 183 | \x22\xf8\x85:\xbe\xa2\xe7\xf9\x0f\x14\x89{\x1b\xa1\x07\x0e\ 184 | l\x00\x00\x00\x00IEND\xaeB`\x82\ 185 | \x00\x00\x01\x80\ 186 | \x89\ 187 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 188 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 189 | \x00\x00\x01GIDATXG\xed\xd6\xb1.\x05Q\ 190 | \x10\x06\xe0\xef>\x80B\xa2\x91(\x14\x1a5\x85\xd0\xd0\ 191 | x\x01\xe1\x01\x14\x12\x0f@\xa2B\x87B\xad\xe0\x05H\ 192 | \xf4**\x15\xadN%\x0aQh\xf4\xe4$Nrr\ 193 | sw\xcf\xae\xbd\xeeF\xb2\x93l6\xd9\x99\xfd\xe7\x9f\ 194 | \x7f\xf6\xcclO\xcb\xd6k9\xbf\x8e@]\x05\x8e\xb1\ 195 | \x9bi\xdb\x1a\xae\xab\xb6\xb6.\x81[,g\xc0\x0fq\ 196 | \xf0W\x04F\xae\xc0\x16&+T\x13\x95\x8c\xf7/\x84\ 197 | +\xd8+\xce\x8b0\xcaZp\x81\xcd\x0a\xc9\xab\x84\x9c\ 198 | a{P`\x19\x81XA\x95\x04\xb9\x98;\xac\xfc;\ 199 | \x02\xb9\xaa\x86\xe2\xcf\x1d\xc3x\xe4rqEdB\x1b\ 200 | \x83\xfc\x85\x96\x03\x0e\x04\xc2\xd9O\xed\x01\xf3?\x0f>\ 201 | 0\x9e8C\xb2\xfe9Q\x9a\xa3.\x81+l\xe0\x05\ 202 | SX\xc4\x02N\x11}\x97XOH\x0d\x95@\x9cr\ 203 | q\x22\x06\xf0\xa8R\xf4\xed\xf7M\xc2\x8e@\xa7\xc0\xc8\ 204 | \x14\x08+8\xfd\x10\xe3A\xe8\x08\xb4\xaa\xc0'\xc6\x9a\ 205 | \x8c\xe2Y<%\x00e\x83h\xd07\xf0\x8c\x99&\x04\ 206 | &\xf0\x9e\x00\xd4\x1d\xc5\xf7XjB \xbc{\x83\xd5\ 207 | \x04\xe4\x11s\x15\x97\xd1\x1e\x8e\x9a\x12\x98\xc6I\xdf\x82\ 208 | \xc9\xfd\x0b\xbc!T\xbf\x83\xd0\x86_\xaf\xe3\x5c\xa2\xc6\ 209 | \xfe\xdc:n\x9c \x07\xd0\x11\xf8\x06\x9b\x14j!K\ 210 | w{\x9d\x00\x00\x00\x00IEND\xaeB`\x82\ 211 | \x00\x00\x02\x1e\ 212 | \x89\ 213 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 214 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 215 | \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x01\ 216 | \xd8IDATXG\xed\x96\xbfK\x1cA\x14\xc7\xbf\ 217 | o\xce\xc8M\x14R\x09\x82I!)rw\x11\x11-\ 218 | l\xb5\xb5\x11\x22'\x08)b\x13A\x11\xc4=mM\ 219 | Z\xef\x07Xj\xa1\xfdY\xfa\x07\xe8\x1f\x10H\xe7n\ 220 | \x91V\x0d\x04D\x08\xe7-\x11\xf7+\xb7b\x08q\xd7\ 221 | \x9d9O\x0e\xe1\xb6\x9c\x99\xf7\xe6\xb3\xdf\xf7\x9d\x99'\ 222 | h\xf3'm\xde\x1f\x1d\x80X\x052\xc5\xda\x17I\xa5\ 223 | \xa6A\x8e\xd8\x97\x89\xbf\x00u\xe4:\xe9\xd9\xa4\xd8H\ 224 | \x80\x5c\xf92OH\x15\x90\xdf\x0c\xae+\xb1I\x94b\ 225 | \xd4\x9c\x80\xef\x00\x99#\xa4\xe49\xe9\xb5\x87 \x22\x01\ 226 | \xb2e\xbf\x0a0\xef:\xbai\x8fd\xcb\x97+\xa48\ 227 | ^A\xbf\xb1\x07\xa8\xd4\x0f\x1bA\xee\xaa\x9eL\x920\ 228 | n>S\xacO\x88\xc2a\xd2OD+\xd0\x01h\x81\ 229 | \x02\xc3\xc5\x9f=\x7f\xd4\xab\x82\xe7\xe8\xaf\x8f\xf6\xc0\xf7\ 230 | 3\xe6)X\x8cK4\xda/M{\xc5\xc8\x036\x00\ 231 | \xe1\xfd\xa1\xd4\x06\x81y\x81L\x09X;v\xf4|\x1c\ 232 | \xbc\x11\x80\xe9I\x08\x9d\x9f\x92e\x90\x1f\xfe\x899a\ 233 | \x80\x8f\xde\x9a>\x8a\xbe3\x22F\xb3Mx`h\xd3\ 234 | \x7f{\x9d\xe2\x8f0\x1d\x83\xa5\xab\xee`\xbf\xeb\xea\xc5\ 235 | \xb8\x80\x07\xe1\x98p\xdd]}Y\xfc\x7f;#\x05L\ 236 | J\x90)\xd5\xc6D\xd47\x00\xa7\xae\xa3\x07\xee6\xfa\ 237 | [\x12\xca\x82WH\xef\x88,\x02\xb2\x9f\xd4\x19\xc76\x9d\xb7\x9d\xb1\xda\ 244 | \x00\xf8\xde\x16\x00\xe09\xa1v\x93:\xe2\xf0\x8d\xb2O\ 245 | \xde\xda\x88\x0e@\xdb\x15\xb8\x01b\xc2)0\xa1\x86b\ 246 | !\x00\x00\x00\x00IEND\xaeB`\x82\ 247 | \x00\x00\x02d\ 248 | \x89\ 249 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 250 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 251 | \x00\x00\x02+IDATXG\xcdW\xbdn\xd3`\ 252 | \x14=\xf7\xb3a`\xa1}\x02Z&\x98@b\xae\xea\ 253 | n\x8c\xb0!\x12\x89\xb0\xb0 G\x84\x17hy\x82 \ 254 | ,\x06&R\x14#\xb62\xc2\x84\xf3\x00H\xf0\x02`\ 255 | f\x90\x080\xd6\xf6A\x9fK\x22\xff%v\x1b;&\ 256 | \x83\xa5\xc8\xd7\xf7\x9es\xef\xfd\xee=\x9f\xa0\xe5\x9f\xb4\ 257 | \x1c\x1f\xa7\x02pg\xc8-\xe3\x1cv\x11E\x96\x88l\ 258 | %\xc1\x93\xf4\xa1\x94\x17\x1ec\xf2f ~Ub\x95\ 259 | \x00t\x1dZ\x00\xf7\x01X\x15\x1d{\x80<\x19\xdb\xe2\ 260 | \x95\xd9/\x05\xa0\x19\x9b&_\x9e\x22p6\x9e\x17\x04\ 261 | r\x7fYF\x16\x02\x88Y\x93G\x10l\x94\xb1X\xfa\ 262 | \x9e\x98F\x86\xec\xbd~(\x9f\x8a\xec\x0a\x01t\x1d\xde\ 263 | \x02x\xb4R\xe0\xdc\xc7\xb2WT\x92\x1c\x80\xbb\xcfy\ 264 | ]\x85\xfc\xb02\xf3,\x80\x05\x99\xc8\x01\xe88\x91/\ 265 | \xc0\xa5z\xd9\x9fx#\xe1\xbb}\xb5\x9d\xf4\x9d\x02\xd0\ 266 | y\xc6G\x22\x1c6\x11|\xe6\x93\x94\x81\xdb\x97\xa7\xb3\ 267 | \xffs\x00\xbd!7\x02\x83_kO}A)\xccP\ 268 | \xb6G\x03\x99\xeaWs\x00\xcd4\xde\xa2\x5c\xca\xed\xb1\ 269 | -oS\x00:N8\x12\xc8\xbd&\xd3?/\x03x\ 270 | \xe8\xdaF/\x03 \x9a\x0apq\x1d\x00@L\xc7}\ 271 | \xb5\x99)A\xc4d\xf0\x9d+\xc0\xce\xd5J\x93\xba\x14\ 272 | \xf3\xfb\xcf\xc4\xc7/i\xb3\xb1\xadb\xe7\xf1#n@\ 273 | \x93?\x93&/\x1e\x08.\x9c/\xf5]\xc9\xe0\xfbo\ 274 | \xe0\xf1\xab\x14?\x98\x81l\xeaF\x5c\x0b\x80\x1f\x7f\x80\ 275 | \xc1\xe1\x12\x00\x9aF\xd7I\x97\xe0\xc6e\xe0\xe6\xb5z\ 276 | J\xf0\xae\xac\x04\x1a@\xc7Y_\x13\x12\xf8\xe5\xda*\ 277 | ^rs\x8a\xad\x1f\xc3\xd6\x07\x91>\x09\xc7&\xf5\x22\ 278 | jt\x16$\xd3\x9f*A\xdc\x07m.\xa3\xd9\x81n\ 279 | t\x1d\x03\xdf\x5c[\xa5\xc4l\xa1 \x91\x88^\xdd\xa5\ 280 | \xd0\xa9\xa7\x12++\xcd\xfe?I6+\x85\x96fu\ 281 | db\x11\xf3\x9c )\x1a\xea\xb1,78\x82`\xb7\ 282 | \xd2\xd0\xcf\x8b\x8fI\x10J\xefL\xb2<\xe9\xeb\x9fD\ 283 | ?\xa8\x0c\x84\x98@\xe4`\xe5\x8bI\x96\x90\xce\x882\ 284 | `\x89D\x960s5\x13\xfa\xa4\xf2\xa2\x10^\xedW\ 285 | \xb33\xa5\xbf\xe2G\xf5\xac\xbb\x8a\xc1\x8a\xcc\xfe\x02U\ 286 | \x95\xf5!\xa9\xc2jN\x00\x00\x00\x00IEND\xae\ 287 | B`\x82\ 288 | \x00\x00\x01\x84\ 289 | \x89\ 290 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 291 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 292 | \x00\x00\x01KIDATXG\xed\xd4\xbf+\x85a\ 293 | \x18\xc6\xf1\xcf\x19\x94\x7f\xc2`Pv\xb3\x85\x12\xf9\xb1\ 294 | \x11\x03I\x92l6\x85Ea\xb5\xc9 \xc5@\x8c\xa2\ 295 | \x0cR\xf2/\xb0\x19\xfc\x0d\x06\x8b\xa2\xa7\xce[\xc7\xe9\ 296 | \xfd}\xce\xdbI\x9d{{\x9f\xe7\xb9\xaf\xeb\xfb\x5c\xdd\ 297 | \xcf[\xd3\xe1\xaau\xd8_\x17\xa0\x9b\xc0\xbfO`\x02\ 298 | \x9fx)\xfb\x9aZI\xe0\x12\xf3u\xe3+,\x94\x81\ 299 | (\x0bp\x88\xad&\xc3\x03l\x17\x85(\x03\xb0\x86\x93\ 300 | \x04\xa3U\x9c\x16\x81(\x0a0\x86\x87\x0c\x83\x11<\xe5\ 301 | \x85(\x020\x80G\xf4e\x88\x7f`\x14\xefy \xf2\ 302 | \x02\xf4\xd4\xcd\x87\xf3\x88\xd6\x13\x08i}g\x9d\xcf\x0b\ 303 | p\x8e\xc5,\xb1\xa6\xfd0\x0ba&R+\x0f\xc0\x1e\ 304 | v\xb3\x84\x12\xf6w\xb0\x9f\xd6\x9b\x05\xb0Rt\xaac\ 305 | \xcc\x96p\x91\x04\x91\x06\x10\xa6\xf9\x0e\xbd%o\x1f\xb5\ 306 | }a\x1c\xcfq:I\x00\xfd\xb8\xc7`\x8b\xe6Q\xfb\ 307 | +&\x11^\xc8\x9f\x8a\x03\x08k\xc1F:\x0a\xff\xf6s<\x9a\x80\x91_C\xf5P/\ 351 | $\x22\xaa#BS1jP\xa9g\x86\xbb\xc0>%\ 352 | SJ\x5cH4\xc4\xf1\xfa\x9d\xceJ6\xf4R/\xa5\ 353 | \xc4G\x93H\x9c\xd69\x04\xf6I\x96'ZJG\x10\ 354 | :\x1dh\x99\xachQ\x10\x04\xbfQf*S\xad\xe5\ 355 | ~\x85\xfa\xc7\x04R7\xdd\x96H\xec\x12\xac\xfbW\xaf\ 356 | \xb8(\x19\xfd\x19\xf9\xd3byR\xa1\xb0\x04b~\x08\ 357 | \xa4<\x05\xc4\x15\x8a\xe3\xc1k\x9d\xfb\xaf\x99\xe9t\x9c\ 358 | Fn\xa2\x08Lc \xe9\xcc\x1f=\x1b]0h\x1c\ 359 | \xc3\x8d\x00\x00\x00\x00IEND\xaeB`\x82\ 360 | \x00\x00\x02\xce\ 361 | \x89\ 362 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 363 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 364 | \x00\x00\x02\x95IDATXG\xed\x97Qn\xda@\ 365 | \x10\x86g\xbc\xeb\xe7\xa6'(7\x08}C`\xab\xf4\ 366 | \x06\xb9A\xe1\x04\x98\x13\x00'\x08\x9c \xc9\x09Jo\ 367 | `\xe4\x05\xf1Ho\xd0\x9e\xa0\xf4y\xcdN5\xd6Z\ 368 | 2\x8e\xd7\x18h\x94<\xc4/\x96\xd0\xec\xf8\xdb\xf9\xff\ 369 | \x99]\x10^\xf9\xc1W\xfe>\xbc\x03\xbc\x8d\x0at:\ 370 | \x9d\x96\xef\xfb\x13cL\xbc^\xaf\x9f\xea|\x11\x86\xe1\ 371 | \x80\x88>\x01\xc0J)\x15_\xeb\xa1\xac\x02A\x10\xcc\ 372 | \x11q`\x93\xfd\x01\x80q\x92$\xcbrr\xfe8\x00\ 373 | <\x10\xd1OD\xbc%\xa28M\xd3\xe1v\xbb\xfdu\ 374 | )H\x0e\x90\xed$M\xd3\x81\xef\xfbS\x00\xf8\xc6\xc9\ 375 | \x8d1\xe3\xcdf\xb3\xcb\x93\x87a\xb8$\xa2\x1b\xa5T\ 376 | ?\x08\x82>\x000\xf8-\xbf\x85\x10\xb38\x8e\xf7\xe7\ 377 | \x82\x1c\x01pb[\x11~O\x11\xf1\x0b\x00<\x0a!\ 378 | \xc6\x9c\xdcV`_\xac\x8e\xfdm\x0e\x00DDs\xa5\ 379 | \xd4\xec\x1c\x88J\x80\xc2\x8eYo\x06\xf9\xc0\xc9\xa5\x94\ 380 | \x8b\xaa]\xf6\xfb\xfd\x9b4M#D\x8c\x00\xc0)a\ 381 | \x15X-\x00/('7\xc6L]F\xb5fvJ\ 382 | x\x11@\xbe\x88A\x0e\x87\x03\x97:\xf3\x07\x00\xcc\x5c\ 383 | ]`\xfd\xf1L\xc2\xab\x00\xf2\xc5\xddn\xb7\xedy\x1e\ 384 | \x9b/\xf3\x87\xd6z\xe6\xea\x02\xdb\xb2\xb5\x12\x9e\x94\xc0\ 385 | e\xa80\x0c\xef\xd8\x17\xe7\xfa\xa3,\xe1\xc5\x009X\ 386 | \x10\x04\xbcC6\x1f\x01\xc0\xb0j~\xe4^*H\xb8\ 387 | \x94R\x0e\xd9\xd0W\x03\x14\x8c\xca #\x22\xfaZ7\ 388 | !YB!\x04\xcf\x186\xf3\xfc\xbf\x00X\xd3M\x10\ 389 | \xf1\xb3\xd6\xba]7\x19-\xc0wc\xcc\xe2j\x80\xfc\ 390 | \x0c\x01\x00\x9e\x17+cLT\x9c\x9cE\xff\xd8.\xba\ 391 | \xcfc\xa5\x94w\x17K`g\xc3\x08\x11\xa7D\xf4\x9b\ 392 | =\xe0\xd2\xdeN\xd6\x5c\x9e\xbf\xbc&I\x92\xc7\x1c\xee\ 393 | l\x09\xec\xe8\xe5\x9d`\xaec]\xa7\x00\x00\xc7~\xb4\ 394 | \x93t^\x9e\xa4\x8d\x01\xac\xce\xf7\x88\xd8&\xa2\x85\x94\ 395 | r\xea:|\x0a\x9e\xe03\xe5Ik=u\xf9\xe2$\ 396 | \x00\xeb,\xa5\xe4\x0fs\xdf\xaf\xf8\xc4t%+{\x82\ 397 | \x0f\xb4Sw\x06'@Yg6\x8f+Y!6\x22\ 398 | \x22\xd6\xb9\xd6\x13E\xc9*\x01z\xbd^\xe4y\xde\xa4\ 399 | \xac\xb3\x9d~\xfb\x22\x88\xf5\x04\xc7f:+\xa5\xf80\ 400 | j\xfc\x1c\x01\xd8;\xc0\x03\x00\xb4\x88h&\xa5<2\ 401 | M\xc5\x85\x84{?\xd3Y\x08\x11]s!\xe1\x99>\ 402 | \xb2\xd8?\xb4\xd6Q\x95\xce\x85+\xd9\xce\x9a\xb1\xb6\xf7\ 403 | \x9b\x94!\xab\x00k\xa8\xb5\x1e \xe2\xee\x94i\xec\x09\ 404 | \xd7\x02\x80\xf8Tlc\x80&\x81/\x15\xf36\xfe\x17\ 405 | \xbc\xd4\xee\x9a\xe4}\xaf\xc0?\x03\x19\x0d?\x97\xd4\x11\ 406 | \x02\x00\x00\x00\x00IEND\xaeB`\x82\ 407 | \x00\x00\x024\ 408 | \x89\ 409 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 410 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 411 | \x00\x00\x01\xfbIDATXG\xcd\x97\x811\x03Q\ 412 | \x10\x86\xffT\x80\x0aP\x01*@\x05\xa8@:@\x05\ 413 | \xa8\x00\x15\xa0\x02T@*\x90T\x80\x0e\xa2\x02\xe6\xbb\ 414 | \xb9\xbdys\xee\xde\xed^.&;\x93\x99\xccd\xdf\ 415 | \xdbo\xff\xdd\xf7\xf6e\xa4\x98\x1dK:\x92\xb4%i\ 416 | ]\xd2n\xb9|*i.\xe9S\xd2\xb3\xa4\x17\xef\xb6\ 417 | #\x87#\xc1.%\x11\x9c\xa0\x1e\x03\x06\x90\x8b\x12\xac\ 418 | uM\x17\xc0\x95\xa4\xb3@\xe0z @n%]\xb7\ 419 | \x11\xb4\x01\x90\xe9k\x22\xb1'\xeb\x9c\x0f%:lR\ 420 | \xa3\x09\x80\xba\x12\xdc+\xb7\x17\x0e5\x80\x00\xa6\xb2:\ 421 | \x00A?\x96\x10\xdc\x02\x02\xb1\x9d*\x91\x02\x0c-{\ 422 | \x9b2(\xb0g?\xa6\x004\x1c\xdd\xfe\x1fFS\x12\ 423 | O\x06\xc0Q{\x0fH\xcf9G\xb1\xfd\x9e\xb4U)\ 424 | \x0c\xe0A\xd2\xa9s\xb3\xaf\xf2\x22\xc2}\x11\xd5\x1e%\ 425 | \x8d\x0d\x00\xa25'\xc0D\xd2A\xe2\xcbw\x12\xd8t\ 426 | \xaeO\x1br\x03\x00n\xb8\xa7\xc0\xe2:\x00K)\x07\ 427 | \x10\x5c\xd3\x11;\x01 \x22?\x9b7\x01X\xd0sI\ 428 | 7\x01\x82;\x00\xde\x82\xcd\x94\x03 6\x17\x19I\xed\ 429 | 8@&\x00p.=\xce\xb6_\x17\x80\x95\x84\x19\xd0\ 430 | \xd5\xd8S\x00~\x1c\xa4\xa9\x8b\x07\xc0\xfc\x99\x88\xd9\xbe\ 431 | X\x09\x80e\x95\x80f\x1cw\xa8;[V\x13\xde;\ 432 | Gy\xd1\x84C\x1fC\xe6\x89w\x94\x17\xc7p\xa8\x8b\ 433 | \x88\xac\xd9+b\xc5E\x84-z\x15\x13\x9c\x81\x16\xb1\ 434 | o\x94\xea3\x8cx\xf9\xf2\xa8\xc0\x06\x1bF\xd4\x8c\x8d\ 435 | \xbd\x03\x89\xf3\xcd\x9at(E\xb3G\xb1\xf9\xcaz'D\xb26\xdfYzD\x9b\x1e\xa5\x91R\ 437 | D\x01h\xbcBz[\xd8\xf6,gBz\xfb\xc1\x0b\ 438 | Apz&\xfb,\xb7\xcdh0 \x22S2\x07\x82\ 439 | \xec\x04\xaf2\xcf)\x90n\xc41\xe3\x91\xd1W\x0d\xb2\ 440 | f,\x17/\xe0&\xeb\xfao\xc8\x1a\xd4`\x13n9\ 441 | /\x08\x819\xaa\xc0\xff\xc9:\x05\xf1\x00\xa4\xfe@\xf0\ 442 | \xb1\xbf\xe7V\x22$&\x10\xf5\xa5t\x04w\xd9/\xa2\ 443 | \xd9l\xfe\x97\x0ak\xf9\x00\x00\x00\x00IEND\xae\ 444 | B`\x82\ 445 | \x00\x00\x02\xcb\ 446 | \x89\ 447 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 448 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 449 | \x00\x00\x02\x92IDATXG\xed\x96Qn\xda@\ 450 | \x10\x86g\xec\xf5s\xd3\x13\xb47(\x8f\x08l\xc57\ 451 | hz\x82&'\xc0\x9c \xe6\x04\x81\x13\x04n\xc0\x0d\ 452 | \xea\xca\x0b\xe2\xad\xe9\x0d\xb8A\xdbg\x8c\xa7\xfa\xad\xb5\ 453 | \xe48\xf6b\x87JHU\xfc\x08\xe3\xd9\xcf\xff\xfc3\ 454 | \xb3L\x17~\xf8\xc2\xe7\xd3\x1b\xc0\xff\xa1\x80\xef\xfb!\ 455 | \x11]\x8b\xc8~\xb3\xd9\xacl\xbe\x0a\x82\xe0\x16\xb1\xae\ 456 | \xebN\x93$\xf9}\x96\x02\xc3\xe1\xf0\xa3R\xea\x91\x99\ 457 | C\x11\xf9\xc9\xcc\x9f\x88\xe8.M\xd3e\x1d\x22\x08\x82\ 458 | \x1b\x22z \xa2\xf7\xf8OD\x96Z\xeb\xe8U\x00a\ 459 | \x18^\x1d\x8fG$\xbb\xc5\xc1D\x14i\xad\x13\xdf\xf7\ 460 | \x13f\xde\xa7i\x8a\xaf,\x9e\xd1h4p\x1c\xe7\x01\ 461 | \x90D\xb4:\x1c\x0e\xb1R\xaa\x00\xd4Z\x87\xbd\x01|\ 462 | \xdf\x8f\x99y\x22\x22\x7f\x989\xae~\xad\xf9\xca+\xfc\ 463 | V\x83\xfcND1 q0@{\x03T%\x14\x91\ 464 | \xb9Rj\x8e\x1a\xd6\xa5\xc6\xc1Y\x96M\x989j\x82\ 465 | \xec\x0d\xd0$\xe1n\xb7\xdb7\x19\xcd\x18\xec\x1eu\xb6\ 466 | AvR\x00\x06\xf3<\x0f\xc9P\xe7g\x12\xd6\x0f7\ 467 | ]p_\xd6\xd9u\xdd\xa8I\x9d\xf2=+@\x17\x09\ 468 | \xcbDu\xc8<\xcf\xa3\xedv\xfbtj\xbc\xb7\x02\xd4\ 469 | %\xd4Z\xc7M\xc9\x1a \xa34M\xd7\xa7\x0enU\ 470 | \xc0$D?\xa3WW6\x09\x8d\x19\x1f\x89\x88Q\xe7\ 471 | 6H\x1b\xcc\x0b\x05\xc6\xe3q\x04\xd7\xe6y~c\x93\ 472 | \x10\xb5f\xe6o\x22\xb2PJ\xc5\xb6:\xf7\x06p\x1c\ 473 | gr<\x1e\xbf\xd8\x00\xd0\x11\xae\xeb&\x22\xf2\x83\x88\ 474 | fe_w\x95\xfeT\x09\xd6\xcc|MD\xcbrN\ 475 | 7%6m9/c\x0f\x87\xc3\xac\xad-\xdb\xc0\xac\ 476 | &\x14\x11L\xbaw\xa6\xbe\xb3\xb6$\xf0\x02b\xcaX\ 477 | \xa5\xd4\xa2kI\xba\xb4a\xe1\x09\x22\xfaEDS\x9b\ 478 | \xc3\xcdhF\xac\xa0\x0dOm\xc3\xce\x93\xd0\xf48\xda\ 479 | \xf0\xab\x88$y\x9eO\xdb\xfca\xba\xa8\xdc\x11\x98\x03\ 480 | S\x9b?:M\xc2\x8aa\xb0\xc5\x90\xbc\xf0\x87\xad\xe6\ 481 | f=/\x11+\x22\xeb,\xcb\xa6M\xfe\xe8\x05P\x82\ 482 | \xf4\xa9\xb9\x19\xcd\x00\xf9\x00O\xd5\xfd\xf1*\x80\x8a\x22\ 483 | P\xa3\xf0G\x9e\xe7q\xb5\xe6\xe6`\xec\xf9b\xddb\ 484 | \xbe8\x8e\x832\x0a@\xb4\xd6\x8b\xce\x1e\xb0\xf5\xb6\xd9\ 485 | \xf5\xf3\xd2\x1f\xe5Lh\xba\x90\x18\x7f\xc0\xd4Xl{\ 486 | \x11\xb9CI{\xdf\x07N\xcd\x04\x11yb\xe6A\xdb\ 487 | \x95\xcc\x98\x1a\xd0\x9f\x91KD0\xc8\xe2\xde7\xa2&\ 488 | \x10#=\xc64\xaec/\xee\x83\xd5w\x10+\x22\x03\ 489 | \xcf\xf3\x96g_J\xfb\x8e\xe0\xa6\xf8\x7f\xa2\xc09 \ 490 | o\x00\x17W\xe0/)\x89\xf40\xe2\xe6\x0bI\x00\x00\ 491 | \x00\x00IEND\xaeB`\x82\ 492 | \x00\x00\x02p\ 493 | \x89\ 494 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 495 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 496 | \x00\x00\x027IDATXG\xed\x97\xcbN\xdb@\ 497 | \x14\x86\x7f\x8f'\x86\x00\x0e\xc5\xa4\x8d\x04\xa1\xa9\x92H\ 498 | \xbd\x08Q\xa9R\x17l*\xf5e\xe83\x95\x97\xe9\xb2\ 499 | \x1b6\xbd\xa9\x5c\x12Z\x14\x856\x111nH\x02\xbe\ 500 | \x8c\xa7\x9a\x0cm\x19\xc5\x94\xc6qB\x179\x1b/f\ 501 | |\xce\xa73\xff?>\xd6p\xcb\xa1\x89\xfaG]\xbe\ 502 | E\x80\xadI\xb2\x84\xc0va^\xdb\xbe\x0a\xf0z\xc2\ 503 | \x00\xaf\x22\x01\x1a\x9dp\xac\x1c\xb9\x05\xd2\xcf\x1f\x02\xd1\ 504 | \x00o\x8f\xbc\xb1\x02l\x16\x8cd\x00^\x1c\xf8pu\ 505 | \xc9\xca\xa0a\xa7H\xff\x09<\x11\x00\xab\xcb\xb1Y\x0b\ 506 | ~\x17\x0c=\x8e7\x8fR\xb80\xfa\x92\xfak$\x02\ 507 | *\xbc\xdc\xf31\xebrp\x06\xd43\x04\x1fJc\ 508 | \xee\x00e\xc0]'\x84G\x01\xc7$`\x04X\xecp\ 509 | P\xc6\xd1Z$`\x1c8\xbd`\xa0\x04\xc8\x18:\xc8\ 510 | 5\xcd\x88\xd5\x81\x85s\x8e\x8d\x8a\x0f\xf1\x14\xd1\x9e\xd3\ 511 | \xb0\xfb\x80\xc2\xb9Tt\xcf\x0f\xb1o{\xe8\x05\xd2A\ 512 | \xf3)\x82\xe2\x1d\x03\xa6!\x15\x7f5b\x01\xe4\x9b\x0c\ 513 | O\xbe\xfe9s\x91\xf0\xcb\x8a\x8e\x83\xbcl{\xa3\x1b\ 514 | \xa0\xea\xa8\xee\xc9\x9b)\xdc\xcf\xa4\x92\x01X?\x0c\xb0\ 515 | r\xc2\x94d\x0d\x8b\xe0]Y\x16\xa8\x9czh\xf6T\ 516 | \xc0\xe5\xb4\x8e\x87\xd6L2\x00Y'\xc4\xb3}_I\ 517 | \xf6\xb1Hq\x9c\x95>\x14g\xff\xb9\xe5*\xeb\xe5%\ 518 | \x03\xf7\xe6\x06\x85\x19\xeb\x08\x84\x00\x0b\xdf\x19r6\x83\ 519 | G54-\x82o\xcb:\xfc\xcb\xfc,\xe48\xee\x04\ 520 | h\x9d3P\x1d\xc8\xa6)\xb2i\x1d4B\x89\xb1\x00\ 521 | n\xf2\xf60\xeb#\x01Xg!\xb8\xb0[fP\xdd\ 522 | }w\xb8\xd2\x05\x99\x99\xe8u\xb1\x16\x1b\xe0\xf9\xae\x8f\ 523 | \xa5\xb6,`\x9b\x04;\x8fU\x85\x7f:q\xf1\xc3\x95\ 524 | B\x15\x00\xeb\xd9\xd9\xc8\xc6\xc4\x02\xc8\xd9!\x9eVT\ 525 | \x11\x0a\x07\x08'\x88\x10g\xbfg\xab\x22\x14\x0e\x10N\ 526 | H\xe4\x1e(\xd5\x03\x94\xea\xaa\x0d\xab\xab:\xaa\xabR\ 527 | \x85\xb5\xb6\x8f\xda\x99\x0a\xb8f\xa6\xb0\x96\xd4=0\x05\ 528 | \x98v`\xa2\x1d\x88\x1aJ\xadJ\xf4\x9ch\x97\xe5|\ 529 | \xf7\xbe\xa1Z\xf0\x97\xf56r\x83\x1f\xa3\x1b\x87\xd2a\ 530 | \xae\xd5Q\xf6^;\x15\x8f\x92t\x98w\xa7\x00\xffe\ 531 | \x07n\xef\xe7t\x18\xf1$\xbd\xf7'\xc7^\xd20\xe1\ 532 | Z\xe1\xa7\x00\x00\x00\x00IEND\xaeB`\x82\ 533 | \x00\x00\x01\x99\ 534 | \x89\ 535 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 536 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 537 | \x00\x00\x01`IDATXG\xed\xd41/eQ\ 538 | \x14\xc5\xf1\x9fB\xe2K(\x14\x12\xbdz\x1a\x93\x08\x19\ 539 | t\x84\xc2DDDt\xbaI\xd0H\xd0\xead\x0a\x91\ 540 | P\x10J!Q\x88D|\x05:\x85\xcf\xa0\xd0Lb\ 541 | \xb2\xe5=\xe1\xc6}\xe7\xde\xfb\xde\x0b\xc5;\xe5\xbd{\ 542 | \xaf\xf5?\xeb\xecs\xba|\xf1\xea\xfab\x7f\x1d\x80N\ 543 | \x02\xdf2\x81A\x8c\x97\xb8\x1d/%jOq\xff\xbe\ 544 | >\x9b\xc0$NJ\x08V)\x9dB\x80\xbc\xae,@\ 545 | \x98\x07D;\xd7\x19&\xf2\x00\xe6\xb0\xdfNw\xac`\ 546 | '\x0f \xbe\xefb\xa9M\x10\xa1\xbd\xdch\x06\xea\xc7\ 547 | r\x81\x91\x16C\x84\xe6\x18>\x0cm\xde5\xecC4\ 548 | \x0c\xb4\x08\xe2\x0e\xbf\xf0\x98\xd5k\xf4\x0e\x0c\xe1\x1c=\ 549 | MB<\xd7\xd2\xbc\xf9L'\xf5\x10\xcdc\xafI\x80\ 550 | \xdf8\xcc\xd3H\x01D\xdf\x06\xd6+B\xaca\xb3Q\ 551 | o\x11\x80\xe8?\xc0lI\x88Hn!\xd5S\x14\xa0\ 552 | \x1bW\xf8\x91\x12\xac\xfd\xbf\xc60\xfe\xa5\xea\x8b\x02\x84\ 553 | N\x7f\x0d\xa27!\x1a\x93\xfe\x13\x0f)\xf3\xcf\x9e\xe2\ 554 | TO\xec\xea2Q\x14\xb7'\x12(\xb4\xca$P\x17\ 555 | \x5c\xc4\xdf\x1c\xf58\xf3R\xb7\xa6\x0a@xo\xe3O\ 556 | \x06b\x0b\xab\x85\xb6\xfd\xae\xa8*@H\x1ca\xba\xa6\ 557 | u\x8c\x99\xb2\xe6Uf \xeb1\x8a'\xdcV1o\ 558 | \x05@U\xdf\xb7\xbef\x8e\xa0i\xf3N\x02\x9d\x04\xbe\ 559 | E\x02\xff\x01i\x15*!U\x88\xae\x06\x00\x00\x00\x00\ 560 | IEND\xaeB`\x82\ 561 | \x00\x00\x05\x91\ 562 | \x89\ 563 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 564 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 565 | \x00\x00\x05XIDATXG\xadWkl\x14U\ 566 | \x14\xfe\xbe\xd9\xf8\x80\xddE\x10\xb0\x01)\x02\x1d\x8a\xa2\ 567 | )\x86\xee\x16\x05\xd1\x88A\x83\x16\xda\x10\xdaDc\x04\ 568 | \xbb\x8b\ 595 | \xb0)\x99\x98\x96\x00\xb5\xd5\xa8\x99?\xaal\x17`\xa7\ 596 | [\xf7.\xcbEn\x81\xd8\x93\x10R\x03\xb2\x22\xe9v\ 597 | \x80g\x01\xb3\x92\xbe`\x935\xf7\xd3\xf2\x02\xc4b\xfb\ 598 | \xaf\x16\x96\x16u\x8f\x99\xae\x86.\x8b\xa9=\xa4\xb6\xa8\ 599 | % z\xaa\xe5C\x11Y\x11w\xbd\xe6q\xea\xc5\xad\ 600 | 7$\x80\xf8\xad\x87\x1c\x17\x01V\xd0\x17\xb0\x5c.{\ 601 | K\xc7\xa3\x9b\x07\x00L7\xddc\xd05}i<\x1b\ 602 | \xc8\x1d\xce\x02\xcfJK@\xc4\x08\x9d\x01\x90?\xd0\xd5\ 603 | \xf7\xf6@B.q\x19\x22\x15\xf4\x05\x8f\xc4\xe7,\x18\ 604 | \x0b\x88\x22/I.\xa8\xabhq\x8b9\xe2\x1e\x0f\xc1\ 605 | \xbf\x9d\xba\xe7nFN7?\x88\x18\x7f\x1aH\xe2\xd9\ 606 | \xbd\x92\x1e\x02\x8b\xee\x0aD[D\x7f\xe0\xa0\xf5U7\ 607 | o4\xc4\xf1\x0d\xc0\x99=v\xf2zd\xf6\xfa6j\ 608 | \xfcZ\x8di\x1af0l\xb4\xac&d\x0b\xc1\x88S\ 609 | \xf7\xb8\xfbs}\xf2\x7fZ\x12\x021\xc0Z\xb9Z-\ 610 | \xe4\x93\xf2\xe10c\x0d\x00z\x8a\x0f\xb1\x96U\x8d\x9b\ 611 | \x13\x1e\x8f\x02\x18\x0a\xc1\xcb\x8c\xb4\x87\xf6\x80\xa8\x02y\ 612 | \xc4U\xe0yj\xc0\x02\xb2TB\xd9^\xe1\xc2\xedW\ 613 | \x14\xf9\x9c\x14\x96\x22\xf27~\x90\xfc\xee<\xd1p\xce\ 614 | t\x8d\xcd\x83\xa0\x8eQ#\xd4$\xb0N\xb8\xcf]\xba\ 615 | \xf7\x85\xff#@\xb6\xce\xbb\x0d\xae[\x1a b_\xc8\ 616 | j\xfa\x1akS\x9e\xab\x9b_\x7fuJyEw^\ 617 | \x91:E\x8f1b\x84\xce\x03\xaa\xf2q\xb3K\xf7\xac\ 618 | \xbdY\x01\xf8\xcb\xf3\x16\xf2[\x03\x00\x9eIa\x90+\ 619 | Y\x15\xd8a'\x87\xa0\xe2\xda\xa4\xb9\xb8\x9e\xff0`\ 620 | v\x87\x07O\x80Fu2\x96\xf7\x90c\x19\xab\x1aw\ 621 | f\x92\xab\xef\x94\x00\xe0\xc2\xe0\x84\x00\xfc\x0a\x90E)\ 622 | r\x8d>\xbe\x18\xa8\xeb\x8b\x5c\x8duy\x96\x1f3\x9d\ 623 | w\xcd\x8a\x87`0\x920m\x7fr\x09\xfd\x81\xbd\xd9\ 624 | \xc8!\x5c\x12}|\xfds\x10y\xd2J\xc2\x9b\xde\x86\ 625 | i\xa58I\xc7\xe7\xe9\x0b|\x91\x83\xdcG\x7f\xa0.\ 626 | b\x84l\xdbp\xb0\x0a\x91\xf0Y\xfa\x03_f%\x87\ 627 | \xbcD_pW\xb8\xadyaZ!J\x14\x86D)\ 628 | \xe6n\xb7\xee\x89\x17\xeb~\x9e\xdc\x0d\xc9|\xd5\x0f\xa4\ 629 | \xba)@V\xd0\x17\xfcHA\x86\x8d\x96]\xaa[J\ 630 | \x95b5\x185B\xb5\x02\xacR\xef\x0ehOdv\ 631 | ?}i\xc9\xde\x90\xf4\x22_E_p\xbb\x95|F\ 632 | \xeb\x9c\x18\xcco\xd5;\x81mN\xdd[m\x1dF\x9d\ 633 | Fs\xbePk\x12\x91\xf1\x04\x02N\xdd[v3\x1e\ 634 | \x90\xba\x0cr\xca\x1aV\x05\xb7&\xb1\xa2F\xa8A\x80\ 635 | \x05$\xcfP\xccG\x86\xea%\x1d\xf6\x86d\x15\x01\xab\ 636 | bev-\x03\xf1\x00\x1c\x9c\x9a\xe6\xf6\x8c\xf2\x1bn\ 637 | ?^CjV\x03#@\xb5[\xf7nKx\xa2\x07\ 638 | \xde\xde\x09\xf7\xd7\x15\xa5\x85\x80\xd8\x97A\xbe\x96\xfe\xf8\ 639 | \xc1c\xc5\xddF\x0e\xc1\xfb\xae\xc9\xdeWR\xfb&s\ 640 | u\x91\xf6\xe6\x0e\x90\xe3,\xa59Z\xb3\xde\xc7q\x02\ 641 | I\xf0\x1a\xfd\x8dV\xebe\xe5Wz{\xff\xabK\xf7\ 642 | \x16\xd99\x07\xa7-\xefA\x5cG_\xe3\xbb\xc9\x843\ 643 | a\xaeQ1\x8f/f\x80my\x16\xe5\xc8y1\xb1\ 644 | \x8c\xb8\x9e\xbe\xc0\xdb\x83r1I\xc5\xce\x08\xad#\xa0\ 645 | \x8e\xe8\xf8\xed\x22\xfe\xdc\xc8\xd5\xacM\x80\xcf\xdc\xbaw\ 646 | Sf\xa8\xb3\xe6@\xe6D\xe9\xe8\x18\x12\xb9\xf6\xcfb\ 647 | B\x16B07\x1bPZ\x5c\x89F\x13<\xe4\xba5\ 648 | o/\xf3\xf3\xbbr\xd9\xf4{;\xb6\x1b\xabz\x11\x03\ 649 | \xcbHL\x82`\x14\x89\x91\x89\xf8^\x04q\x81`\x1b\ 650 | \x1chpN\xf0\x9c\x1d\x88P5\xe7?\x82\x14\xd7:\ 651 | qS3%\x00\x00\x00\x00IEND\xaeB`\x82\ 652 | \ 653 | \x00\x00\x02\x1c\ 654 | \x89\ 655 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 656 | \x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ 657 | \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x01\ 658 | \xd6IDATXG\xed\xd7\xcf\x8bNQ\x18\x07\xf0\ 659 | \xcfl\xec\x09+\xc9\x82\x0dI)\xd6d\xe1G\x94\x12\ 660 | Q,&\xb2\xb5\xf0k\x89\x8d\xc4_`7)\x11\xa5\ 661 | \xc6LM6\xd8\xc8BJ\xb3\x94\x05\x0b\x9b!dc\ 662 | I_\x9d\xab\xeb6s\xe7\x9d\xf7\xdez7\xefS\xb7\ 663 | {:\xe79\xcf\xf7{\x9e\xe7\x9c\xe7\xff\xf9\ 712 | \x83U\x13\xce4 \xcc\xc6\xca\x10)%\xc9\x00\xa2\xa9\ 713 | \x01N\x7f\xf8\xc8\xb0\xed\x15f\xe5\x86\xd3\x01\x06|\xbc\ 714 | \x0c\xfe\x12\xf0\x1a\x8db7|\xfd\xfb\x97\xa1\xe7\xee\x03\ 715 | \x0csp:\xc0^X\x90\xc1AX\x88b\x8b\x91\x0d\ 716 | h\xbcuw\x88:\xe0\xed\xb7\xef\x0cikv\x92\x1c\ 717 | \x1a\xb0\xb6\x02L#E!P\xb7\xf3\x08q\x0e@\xca\ 718 | %JB\x02\x0c\x09&:p}\x149\x808\xdb\xf1\ 719 | \xab\x1a\xda\x0e\xb8\xfa\x82p\x03\x15\xdd\xff\xa2<\x5c\x0c\ 720 | b<\x5c\x94G\xc1\xe3\x0f\x9f\x19\x0a6\xed%9\x16\ 721 | @\x96O\x0fr\xa3\xdc\x01\xdf~\xffa\xe8\xd8w\x82\ 722 | d\x07\xa8\x88\x082\xc4\x19kS\xee\x00\x92m\xc6\xa1\ 723 | \x81\xa4D8\xe0E\xf1\x80WF\xa0P\xc4Z\x1d\x93\ 724 | \x11\x1fo\x7f\x93Q\x1d\x93a\x0fYZ\x90k\xc3z\ 725 | \x06\x06\x06\x9c\x1dH\xb2L'\xa4\x09\xda7\x00\x97\xde\ 726 | \xa0n93\x03s\xfc\x7f\x86\xff\x09\x84\xf4QC\x9e\ 727 | \x91\x81q\xc1_\x86\xbf\x0bA\xddw\x00\xf2vQ0\ 728 | \xae\xed<\xfc\x00\x00\x00\x00IEND\xaeB`\x82\ 729 | \ 730 | \x00\x00\x01;\ 731 | \x89\ 732 | PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ 733 | \x00\x00\x15\x00\x00\x00\x14\x08\x06\x00\x00\x00bKv3\ 734 | \x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ 735 | \x04gAMA\x00\x00\xb1\x8f\x0b\xfca\x05\x00\x00\x00\ 736 | \x09pHYs\x00\x00\x0e\xc3\x00\x00\x0e\xc3\x01\xc7o\ 737 | \xa8d\x00\x00\x00\xd0IDAT8O\xc5\x94!\x0e\ 738 | \xc2@\x10E\xab\xea\xb0X,\x16A\xc2\x89\x10\x04\x05\ 739 | \x16\x8bE`\x08\x86\x03p\x12\x04A\xe0P@\xab\xe8\ 740 | b\xda\xd0\x92\x864\xc3~7Y\xa6\xe9$\xb4 ^\ 741 | \xd5\xfb/\xbbb\xeb\x05\xf7'\xd5M3\xd1\xab\xc9\xa8\ 742 | n~\x17\x0d\xed\x15L\x92S\x92\xbd*\x81\x07\x9f\xef\ 743 | \xc5\xa8\x89sZ\xee\x0a\x1al\xa8\x12x\xf0\xf9^\x8c\ 744 | \xe2\x04\xfduA\xbdU5\xf0\xe0\xf3}i\xb4\xbbx\ 745 | \xa8QG;s\xa3F\x1dm\xcf\x025\x1f\xd1\x8b\xfd\ 746 | \xb8@jMOj\xe0\xf3}i\xd4\x1f\x1f\xd5\xa8\xa3\ 747 | \xdep\xaf\xe6\x7f\xd1\xd8J\xfe\xe8 \x06\x5c\xe0\xc1\xe7\ 748 | {1\x1a\xd9\x172\xd9\x06b\xc4\x05\x1e|\xbe\x17\xa3\ 749 | \xf8}E\xca\xb7\x0f\x0f>\xdf\x8b\xd1oi&z\xbe\ 750 | \xa5T/)\xbd\x01\x02\x99\x8f] \xfc\xa0U\x00\x00\ 751 | \x00\x00IEND\xaeB`\x82\ 752 | " 753 | 754 | qt_resource_name = b"\ 755 | \x00\x09\ 756 | \x06%\x10\x9e\ 757 | \x00t\ 758 | \x00o\x00o\x00l\x00_\x00i\x00c\x00o\x00n\ 759 | \x00\x08\ 760 | \x0c\xa6\xc7\x95\ 761 | \x00r\ 762 | \x00e\x00s\x00o\x00u\x00r\x00c\x00e\ 763 | \x00\x08\ 764 | \x06\xc1Y\x87\ 765 | \x00o\ 766 | \x00p\x00e\x00n\x00.\x00p\x00n\x00g\ 767 | \x00\x09\ 768 | \x0c\x98\xbaG\ 769 | \x00p\ 770 | \x00a\x00u\x00s\x00e\x00.\x00p\x00n\x00g\ 771 | \x00\x09\ 772 | \x08\xb6\xa2\x07\ 773 | \x00s\ 774 | \x00t\x00a\x00t\x00s\x00.\x00p\x00n\x00g\ 775 | \x00\x0c\ 776 | \x06z\x02G\ 777 | \x00r\ 778 | \x00e\x00s\x00t\x00a\x00r\x00t\x00 \x00.\x00p\x00n\x00g\ 779 | \x00\x0a\ 780 | \x0c\xad\x0f\x07\ 781 | \x00d\ 782 | \x00e\x00l\x00e\x00t\x00e\x00.\x00p\x00n\x00g\ 783 | \x00\x0a\ 784 | \x0c\xf7\x1b\xc7\ 785 | \x00c\ 786 | \x00o\x00n\x00f\x00i\x00g\x00.\x00p\x00n\x00g\ 787 | \x00\x0c\ 788 | \x08\xf0`G\ 789 | \x00s\ 790 | \x00u\x00b\x00t\x00r\x00a\x00c\x00t\x00.\x00p\x00n\x00g\ 791 | \x00\x06\ 792 | \x07\xc3WG\ 793 | \x00u\ 794 | \x00p\x00.\x00p\x00n\x00g\ 795 | \x00\x07\ 796 | \x07\xa7W\x87\ 797 | \x00a\ 798 | \x00d\x00d\x00.\x00p\x00n\x00g\ 799 | \x00\x06\ 800 | \x0e\x8eZG\ 801 | _\xeb\ 802 | \x8f\xdb\x00.\x00p\x00n\x00g\ 803 | \x00\x09\ 804 | \x08\x97\xa2\x07\ 805 | \x00s\ 806 | \x00t\x00a\x00r\x00t\x00.\x00p\x00n\x00g\ 807 | \x00\x06\ 808 | \x0e\xb3ZG\ 809 | _\xeb\ 810 | \x90\x00\x00.\x00p\x00n\x00g\ 811 | \x00\x08\ 812 | \x08\x01Y'\ 813 | \x00m\ 814 | \x00a\x00i\x00n\x00.\x00p\x00n\x00g\ 815 | \x00\x08\ 816 | \x06\xe1Z'\ 817 | \x00d\ 818 | \x00o\x00w\x00n\x00.\x00p\x00n\x00g\ 819 | \x00\x0b\ 820 | \x08T\x9f\x87\ 821 | \x00c\ 822 | \x00o\x00m\x00p\x00a\x00r\x00e\x00.\x00p\x00n\x00g\ 823 | \x00\x09\ 824 | \x0d\xf7\xa6\xa7\ 825 | \x00r\ 826 | \x00i\x00g\x00h\x00t\x00.\x00p\x00n\x00g\ 827 | \x00\x0d\ 828 | \x0dx=G\ 829 | \x00s\ 830 | \x00a\x00v\x00e\x00_\x00i\x00c\x00o\x00n\x00.\x00p\x00n\x00g\ 831 | \x00\x08\ 832 | \x0bcX\x07\ 833 | \x00s\ 834 | \x00t\x00o\x00p\x00.\x00p\x00n\x00g\ 835 | " 836 | 837 | qt_resource_struct = b"\ 838 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ 839 | \x00\x00\x00\x00\x00\x00\x00\x00\ 840 | \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ 841 | \x00\x00\x00\x00\x00\x00\x00\x00\ 842 | \x00\x00\x00\x18\x00\x02\x00\x00\x00\x12\x00\x00\x00\x03\ 843 | \x00\x00\x00\x00\x00\x00\x00\x00\ 844 | \x00\x00\x00t\x00\x00\x00\x00\x00\x01\x00\x00\x07\xed\ 845 | \x00\x00\x01y#Oj\x95\ 846 | \x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ 847 | \x00\x00\x01y#Oj\x94\ 848 | \x00\x00\x01\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x05\ 849 | \x00\x00\x01y\xc7\xe2\xce\x5c\ 850 | \x00\x00\x00\xf6\x00\x00\x00\x00\x00\x01\x00\x00\x12\x05\ 851 | \x00\x00\x01y#Oj\x93\ 852 | \x00\x00\x00\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x10}\ 853 | \x00\x00\x01y\xc7\xe2\x9b\xda\ 854 | \x00\x00\x01F\x00\x00\x00\x00\x00\x01\x00\x00\x1c\x91\ 855 | \x00\x00\x01y#Oj\x94\ 856 | \x00\x00\x01r\x00\x00\x00\x00\x00\x01\x00\x00 \xa2\ 857 | \x00\x00\x01y#Oj\x93\ 858 | \x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x17\x8a\ 859 | \x00\x00\x01y#Oj\x96\ 860 | \x00\x00\x00\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x05'\ 861 | \x00\x00\x01y#Oj\x97\ 862 | \x00\x00\x00\xc6\x00\x00\x00\x00\x00\x01\x00\x00\x0e\x15\ 863 | \x00\x00\x01y#Oj\x97\ 864 | \x00\x00\x01\xc6\x00\x00\x00\x00\x00\x01\x00\x00*\xbc\ 865 | \x00\x00\x01y#Oj\x97\ 866 | \x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x02\xaf\ 867 | \x00\x00\x01y#Oj\x95\ 868 | \x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\x0ao\ 869 | \x00\x00\x01z\x14\xbe\xaa\xda\ 870 | \x00\x00\x00\xac\x00\x00\x00\x00\x00\x01\x00\x00\x0b\xf3\ 871 | \x00\x00\x01\x80\xae\x82}D\ 872 | \x00\x00\x01\xa6\x00\x00\x00\x00\x00\x01\x00\x00(W\ 873 | \x00\x00\x01y#Oj\x96\ 874 | \x00\x00\x01\x8e\x00\x00\x00\x00\x00\x01\x00\x00&7\ 875 | \x00\x00\x01\x80\x94\xcbl\xdf\ 876 | \x00\x00\x01\x0a\x00\x00\x00\x00\x00\x01\x00\x00\x14\xb8\ 877 | \x00\x00\x01y#Oj\x98\ 878 | \x00\x00\x014\x00\x00\x00\x00\x00\x01\x00\x00\x19\xc2\ 879 | \x00\x00\x01y#Oj\x98\ 880 | " 881 | 882 | def qInitResources(): 883 | QtCore.qRegisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) 884 | 885 | def qCleanupResources(): 886 | QtCore.qUnregisterResourceData(0x03, qt_resource_struct, qt_resource_name, qt_resource_data) 887 | 888 | qInitResources() 889 | --------------------------------------------------------------------------------