当前位置: 首页 > article >正文

使用PyQt5和百度AI实现图片清晰度增强的GUI应用

在本教程中,我们将详细解析一个使用PyQt5和百度AI接口实现的图片清晰度增强的GUI应用程序。该应用程序允许用户选择图片文件,设置输出目录和图片质量,并通过百度AI的图片清晰度增强接口处理图片。我们将逐步解析代码的各个部分,帮助你理解如何构建一个类似的应用程序。

1. 环境准备

在开始之前,确保你已经安装了以下Python库:

  • PyQt5:用于构建GUI界面。
  • requests:用于发送HTTP请求。
  • Pillow:用于处理图片。

你可以通过以下命令安装这些库:

pip install PyQt5 requests pillow

2. 代码结构

代码主要分为两个部分:

  1. EnhanceImageThread:继承自QThread,用于在后台线程中处理图片增强任务,避免阻塞主线程。
  2. ImageEnhanceApp:继承自QWidget,用于构建GUI界面并处理用户交互。

完整代码:

import sys
from pathlib import Path
import requests
from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
    QLabel, QLineEdit, QComboBox, QSpinBox, QFileDialog, QTextEdit
)
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QDragEnterEvent, QDropEvent
from PIL import Image
from io import BytesIO
from base64 import b64encode, b64decode


class EnhanceImageThread(QThread):
    finished = pyqtSignal(bool)  # 信号,用于通知主线程任务完成
    log_signal = pyqtSignal(str)  # 信号,用于发送日志信息

    def __init__(self, img_file, output_file, quality):
        super().__init__()
        self.img_file = img_file
        self.output_file = output_file
        self.quality = quality

    def run(self):
        try:
            # 对图片数据进行base64编码
            with open(self.img_file, 'rb') as fr:
                b64_image = b'data:image/jpeg;base64,' + b64encode(fr.read())
                self.log_signal.emit(f'待上传图片:{self.img_file}')
        except Exception as e:
            self.log_signal.emit(f'打开图片发生错误:{e}')
            self.finished.emit(True)
            return

        form_data = {
            'image': b64_image,
            'image_url': '',
            'type': 'https://aip.baidubce.com/rest/2.0/image-process/v1/image_definition_enhance'
        }

        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1467.0 Safari/537.36',
            'referer': 'https://ai.baidu.com/tech/imageprocess/image_definition_enhance'
        }

        # 发送请求
        URL = 'https://ai.baidu.com/aidemo'
        try:
            self.log_signal.emit('正在发送请求...')
            response = requests.post(URL, headers=headers, data=form_data, timeout=50)
            response.raise_for_status()
            data = response.json()['data']['image'].strip()
            if not data:
                self.log_signal.emit('请求数据失败')
                return
            # 保存图片
            self.log_signal.emit('正在保存图片...')
            img = Image.open(BytesIO(b64decode(data)))
            img.save(self.output_file, quality=self.quality)
            self.log_signal.emit(f'图片已保存:{self.output_file}')
        except requests.RequestException:
            self.log_signal.emit('请求失败')
        except Exception as e:
            self.log_signal.emit(f'保存图片发生错误:{e}')
        finally:
            self.finished.emit(True)


class ImageEnhanceApp(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setStyleSheet(self.get_harmony_style())  # 设置鸿蒙系统样式
        self.setAcceptDrops(True)  # 启用拖放功能

    def initUI(self):
        self.setWindowTitle('图片清晰度增强V1')
        self.resize(600, 600)  # 调整窗口大小以适应日志区域

        layout = QVBoxLayout()

        # 输入图片文件
        input_layout = QHBoxLayout()
        self.input_label = QLabel('输入文件:')
        self.input_text = QLineEdit()
        self.input_text.setPlaceholderText('选择或拖动图片文件到此处')
        self.input_button = QPushButton('选择')
        self.input_button.clicked.connect(self.select_input_file)
        input_layout.addWidget(self.input_label)
        input_layout.addWidget(self.input_text)
        input_layout.addWidget(self.input_button)
        layout.addLayout(input_layout)

        # 输出目录
        output_layout = QHBoxLayout()
        self.output_label = QLabel('输出目录:')
        self.output_text = QLineEdit()
        self.output_text.setPlaceholderText('选择或输入输出目录')
        self.output_button = QPushButton('选择')
        self.output_button.clicked.connect(self.select_output_directory)
        output_layout.addWidget(self.output_label)
        output_layout.addWidget(self.output_text)
        output_layout.addWidget(self.output_button)
        layout.addLayout(output_layout)

        # 图片格式
        format_layout = QHBoxLayout()
        self.format_label = QLabel('图片格式:')
        self.format_combo = QComboBox()
        self.format_combo.addItems(['JPEG', 'PNG'])
        format_layout.addWidget(self.format_label)
        format_layout.addWidget(self.format_combo)
        layout.addLayout(format_layout)

        # 图片质量
        quality_layout = QHBoxLayout()
        self.quality_label = QLabel('JPEG 图片质量:')
        self.quality_spin = QSpinBox()
        self.quality_spin.setRange(1, 100)
        self.quality_spin.setValue(90)
        self.quality_spin.setSingleStep(5)
        quality_layout.addWidget(self.quality_label)
        quality_layout.addWidget(self.quality_spin)
        layout.addLayout(quality_layout)

        # 增强按钮
        self.enhance_button = QPushButton('开始')
        self.enhance_button.clicked.connect(self.enhance_image)
        layout.addWidget(self.enhance_button)

        # 日志输出区域
        self.log_label = QLabel('日志输出:')
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)  # 设置为只读
        layout.addWidget(self.log_label)
        layout.addWidget(self.log_text)

        self.setLayout(layout)

    def select_input_file(self):
        file, _ = QFileDialog.getOpenFileName(self, '选择图片文件', '', 'Images (*.png *.jpg *.jpeg)')
        if file:
            self.input_text.setText(file)
            self.log_text.append(f'已选择输入图片:{file}')

    def select_output_directory(self):
        directory = QFileDialog.getExistingDirectory(self, '选择输出目录')
        if directory:
            self.output_text.setText(directory)
            self.log_text.append(f'已选择输出目录:{directory}')

    def enhance_image(self):
        input_file = self.input_text.text()
        output_directory = self.output_text.text()
        if not input_file or not output_directory:
            self.log_text.append('警告:请先选择输入图片文件和输出目录')
            return

        image_format = self.format_combo.currentText()
        quality = self.quality_spin.value()
        output_file = f'{output_directory}/{Path(input_file).stem}.{image_format.lower()}'
        # 判断output_file是否存在
        if Path(output_file).exists():
            self.log_text.append(f'目标图片已经存在:{output_file}')
            return

        self.enhance_button.setEnabled(False)
        self.log_text.append('开始处理图片...')
        self.thread = EnhanceImageThread(input_file, output_file, quality)
        self.thread.finished.connect(self.enhance_button.setEnabled)
        self.thread.log_signal.connect(self.log_text.append)  # 连接日志信号
        self.thread.start()

    def dragEnterEvent(self, event: QDragEnterEvent):
        """拖入文件时触发"""
        if event.mimeData().hasUrls():  # 检查是否有文件拖入
            event.acceptProposedAction()  # 接受拖入操作

    def dropEvent(self, event: QDropEvent):
        """拖放文件时触发"""
        for url in event.mimeData().urls():  # 获取拖入的文件路径
            file_path = url.toLocalFile()
            if file_path.lower().endswith(('.png', '.jpg', '.jpeg')):  # 检查文件是否为图片
                self.input_text.setText(file_path)
                self.log_text.append(f'已拖入输入图片:{file_path}')
                break

    def get_harmony_style(self):
        """返回鸿蒙系统风格的QSS样式"""
        return """
        QWidget {
            font-family: "HarmonyOS Sans SC";
            font-size: 16px;
            background-color: #F5F5F5;
        }
        QLabel {
            color: #333333;
        }
        QLineEdit {
            border: 1px solid #CCCCCC;
            border-radius: 4px;
            padding: 5px;
            background-color: #FFFFFF;
        }
        QPushButton {
            background-color: #007AFF;
            color: #FFFFFF;
            border: none;
            border-radius: 4px;
            padding: 8px 16px;
        }
        QPushButton:hover {
            background-color: #0066CC;
        }
        QPushButton:disabled {
            background-color: #CCCCCC;  /* 设置背景为灰色 */
            color: #666666;            /* 设置文字为灰色 */
            filter: grayscale(100%);   /* 将按钮内容(图标和文本)设置为灰度 */
        }
        QComboBox {
            border: 1px solid #CCCCCC;
            border-radius: 4px;
            padding: 5px;
            background-color: #FFFFFF;
        }
        QSpinBox {
            border: 1px solid #CCCCCC;
            border-radius: 4px;
            padding: 5px;
            background-color: #FFFFFF;
        }
        QTextEdit {
            font-size: 14px;
            border: 1px solid #CCCCCC;
            border-radius: 4px;
            padding: 5px;
            background-color: #FFFFFF;
        }
        """


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ImageEnhanceApp()
    ex.show()
    sys.exit(app.exec_())

3. EnhanceImageThread类解析

EnhanceImageThread类负责在后台线程中处理图片增强任务。它通过百度AI的图片清晰度增强接口发送请求,并将处理后的图片保存到指定目录。

3.1 初始化方法

def __init__(self, img_file, output_file, quality):
    super().__init__()
    self.img_file = img_file
    self.output_file = output_file
    self.quality = quality
  • img_file:输入的图片文件路径。
  • output_file:输出的图片文件路径。
  • quality:图片的质量(仅适用于JPEG格式)。

3.2 run方法

run方法是线程执行的核心逻辑。它首先将图片文件进行base64编码,然后通过百度AI的接口发送请求,最后将处理后的图片保存到指定目录。

def run(self):
    try:
        # 对图片数据进行base64编码
        with open(self.img_file, 'rb') as fr:
            b64_image = b'data:image/jpeg;base64,' + b64encode(fr.read())
            self.log_signal.emit(f'待上传图片:{self.img_file}')
    except Exception as e:
        self.log_signal.emit(f'打开图片发生错误:{e}')
        self.finished.emit(True)
        return
  • b64encode:将图片文件转换为base64编码。
  • log_signal:用于发送日志信息到主线程。

接下来,构造请求的表单数据和请求头,并发送POST请求:

form_data = {
    'image': b64_image,
    'image_url': '',
    'type': 'https://aip.baidubce.com/rest/2.0/image-process/v1/image_definition_enhance'
}

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1467.0 Safari/537.36',
    'referer': 'https://ai.baidu.com/tech/imageprocess/image_definition_enhance'
}

URL = 'https://ai.baidu.com/aidemo'
  • form_data:包含图片数据和请求类型的表单数据。
  • headers:请求头,包含用户代理和引用信息。

发送请求并处理响应:

try:
    self.log_signal.emit('正在发送请求...')
    response = requests.post(URL, headers=headers, data=form_data, timeout=50)
    response.raise_for_status()
    data = response.json()['data']['image'].strip()
    if not data:
        self.log_signal.emit('请求数据失败')
        return
    # 保存图片
    self.log_signal.emit('正在保存图片...')
    img = Image.open(BytesIO(b64decode(data)))
    img.save(self.output_file, quality=self.quality)
    self.log_signal.emit(f'图片已保存:{self.output_file}')
except requests.RequestException:
    self.log_signal.emit('请求失败')
except Exception as e:
    self.log_signal.emit(f'保存图片发生错误:{e}')
finally:
    self.finished.emit(True)
  • response.raise_for_status():检查请求是否成功。
  • Image.open(BytesIO(b64decode(data))):将base64编码的图片数据解码并打开为图片对象。
  • img.save:保存处理后的图片。

4. ImageEnhanceApp类解析

ImageEnhanceApp类负责构建GUI界面并处理用户交互。它使用PyQt5的组件来创建输入框、按钮、下拉菜单等控件。

4.1 初始化方法

def __init__(self):
    super().__init__()
    self.initUI()
    self.setStyleSheet(self.get_harmony_style())  # 设置鸿蒙系统样式
    self.setAcceptDrops(True)  # 启用拖放功能
  • initUI:初始化UI界面。
  • setStyleSheet:设置应用程序的样式。
  • setAcceptDrops(True):启用拖放功能,允许用户通过拖放文件来选择图片。

4.2 initUI方法

initUI方法创建了应用程序的主界面,包括输入文件选择、输出目录选择、图片格式选择、图片质量设置、增强按钮和日志输出区域。

def initUI(self):
    self.setWindowTitle('图片清晰度增强V1')
    self.resize(600, 600)  # 调整窗口大小以适应日志区域

    layout = QVBoxLayout()

    # 输入图片文件
    input_layout = QHBoxLayout()
    self.input_label = QLabel('输入文件:')
    self.input_text = QLineEdit()
    self.input_text.setPlaceholderText('选择或拖动图片文件到此处')
    self.input_button = QPushButton('选择')
    self.input_button.clicked.connect(self.select_input_file)
    input_layout.addWidget(self.input_label)
    input_layout.addWidget(self.input_text)
    input_layout.addWidget(self.input_button)
    layout.addLayout(input_layout)

    # 输出目录
    output_layout = QHBoxLayout()
    self.output_label = QLabel('输出目录:')
    self.output_text = QLineEdit()
    self.output_text.setPlaceholderText('选择或输入输出目录')
    self.output_button = QPushButton('选择')
    self.output_button.clicked.connect(self.select_output_directory)
    output_layout.addWidget(self.output_label)
    output_layout.addWidget(self.output_text)
    output_layout.addWidget(self.output_button)
    layout.addLayout(output_layout)

    # 图片格式
    format_layout = QHBoxLayout()
    self.format_label = QLabel('图片格式:')
    self.format_combo = QComboBox()
    self.format_combo.addItems(['JPEG', 'PNG'])
    format_layout.addWidget(self.format_label)
    format_layout.addWidget(self.format_combo)
    layout.addLayout(format_layout)

    # 图片质量
    quality_layout = QHBoxLayout()
    self.quality_label = QLabel('JPEG 图片质量:')
    self.quality_spin = QSpinBox()
    self.quality_spin.setRange(1, 100)
    self.quality_spin.setValue(90)
    self.quality_spin.setSingleStep(5)
    quality_layout.addWidget(self.quality_label)
    quality_layout.addWidget(self.quality_spin)
    layout.addLayout(quality_layout)

    # 增强按钮
    self.enhance_button = QPushButton('开始')
    self.enhance_button.clicked.connect(self.enhance_image)
    layout.addWidget(self.enhance_button)

    # 日志输出区域
    self.log_label = QLabel('日志输出:')
    self.log_text = QTextEdit()
    self.log_text.setReadOnly(True)  # 设置为只读
    layout.addWidget(self.log_label)
    layout.addWidget(self.log_text)

    self.setLayout(layout)
  • QVBoxLayoutQHBoxLayout:用于垂直和水平布局控件。
  • QLineEdit:用于输入文件路径和输出目录。
  • QComboBox:用于选择图片格式。
  • QSpinBox:用于设置图片质量。
  • QPushButton:用于触发图片增强操作。
  • QTextEdit:用于显示日志信息。

4.3 其他方法

  • select_input_file:打开文件选择对话框,选择输入图片文件。
  • select_output_directory:打开目录选择对话框,选择输出目录。
  • enhance_image:启动后台线程处理图片增强任务。
  • dragEnterEventdropEvent:处理文件拖放事件。

5. 运行应用程序

在代码的最后部分,我们创建了一个QApplication对象,并实例化ImageEnhanceApp类来运行应用程序。

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = ImageEnhanceApp()
    ex.show()
    sys.exit(app.exec_())
  • QApplication:管理应用程序的控制流和主要设置。
  • app.exec_():进入主事件循环,等待用户交互。

在这里插入图片描述

6. 总结

通过本教程,我们详细解析了一个使用PyQt5和百度AI接口实现的图片清晰度增强的GUI应用程序。我们学习了如何使用QThread在后台处理耗时任务,如何使用PyQt5构建GUI界面,以及如何通过百度AI的接口处理图片。希望本教程能帮助你理解如何构建类似的应用程序,并为你的项目提供灵感。


http://www.kler.cn/a/557479.html

相关文章:

  • Linux下安装中文输入法总结
  • pycharm中配置PyQt6详细教程
  • qt项目配置部署
  • java基于数组实现队列(二)
  • 解决双系统开机显示gnu grub version 2.06 Minimal BASH Like Line Editing is Supported
  • 计算机网络————(一)HTTP讲解
  • Maven 构建中的安全性与合规性检查
  • Android SoundTrigger架构学习
  • 0基础学前端-----CSS DAY13
  • VR疗法的新突破——王博如何用技术帮助心理康复
  • STM32单片机芯片与内部95 STM32F429系列 架构 启动 供电 时钟
  • 14.5 Auto-GPT:基于Agent的AGI实验如何重新定义人工智能未来?
  • 阿里云ECS命名规则解析与规格选型实战指南
  • 番茄工作法html实现
  • 特征提取:如何从不同模态中获取有效信息?
  • Linux第十二节 — 进程概念详解 + 操作系统引入
  • 第二课 — 读取按钮状态用以控制LED闪烁
  • 【JavaScript进阶】构造函数数据常用函数
  • [ Vim ] 常用命令 and 配置
  • 从0开始:OpenCV入门教程【图像处理基础】