「Python」PySide2入门| 简单拼图小工具(PySide2安装,多文件选择,layout宽高设置,显示Opencv图像等)

虽然工作上并不用经常写界面做前端,但有时候在做一些测试或写一些demo的时候需要用到简单的界面去操作和展示一些东西。所以还是需要掌握一定的界面开发工具的。C#上用Winform很方便,python上还一直不会搞。

看很多人推荐Qt,所以决定稍微学一下Qt。

python上有PyQt5和PySide2,很相似,很多函数可以互相用,只不过PySide2是Qt的亲儿子嘛,还是直接学PySide吧。

1、安装PySide2的坑

单独记这个还是有必要的,目前版本安装有个坑

pip install pyside2

安装后,按照官方例子运行的时候会报错

qt.qpa.plugin: Could not load the Qt platform plugin "windows" in "" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Available platform plugins are: direct2d, minimal, offscreen, windows.

完全卸载python后第一个就安装pyside,也会报错。

解决方式(参考):

将 ...\Anaconda3\Lib\site-packages\PySide2\plugins\platforms\  目录下的所有文件

复制到  ...\Anaconda3\Library\plugins\platforms\   目录下,替换之前的文件即可。

目前未见其他错误

还有一点,就是设计器,pyside2安装也会带有设计器,在  ...\Anaconda3\Lib\site-packages\PySide2\  目录下

可以将该目录添加到环境变量,这样就可以直接在命令行中直接启动了。


详细代码见 https://github.com/RainkLH/ImageStitching-pyside2

2、界面编程

最终效果如下

「Python」PySide2入门| 简单拼图小工具(PySide2安装,多文件选择,layout宽高设置,显示Opencv图像等)_第1张图片

2.1、 主界面程序框架

这是一个很简单的界面程序,可以作为通用的框架使用。其效果就是一个带有一个标签的窗口。

import sys
from PySide2.QtWidgets import *


class MainWindow(QWidget):
    # 界面窗口标题
    MainWindowTitle = "RkWindow"

    def __init__(self):
        super().__init__()
        self.setWindowTitle(self.MainWindowTitle)
        # 设置尺寸
        self.resize(100, 100)
        self.setup_ui()

    def setup_ui(self):
        # 一个标签
        self.hello_label = QLabel("Hello world!")
        # 主布局,竖向布局
        self.main_layout = QVBoxLayout()
        # 在布局中添加wiget,标签、文字框、滚动条等都是wiget
        self.main_layout.addWidget(self.hello_label)
        # 设置布局!
        self.setLayout(self.main_layout)


if __name__ == '__main__':
    # 运行界面
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

效果如图:

「Python」PySide2入门| 简单拼图小工具(PySide2安装,多文件选择,layout宽高设置,显示Opencv图像等)_第2张图片

2.2、按钮与多文件选择

创建一个选择图片文件按钮:

self.btn_imgs = QPushButton("chose file")

按钮点击事件连接到相应的方法:

self.btn_imgs.clicked.connect(self._open_file_dialog)

多文件选择对话框:

def _open_file_dialog(self):
        dlg_file = QFileDialog()
        # 对话框标题
        dlg_file.setWindowTitle("选择图片")
        # 筛选文件类型
        dlg_file.setNameFilter("image files (*.jpg *.png *.bmp)")
        # 多文件模式
        dlg_file.setFileMode(QFileDialog.ExistingFiles)
        dlg_file.setViewMode(QFileDialog.Detail)
        if dlg_file.exec_():
            # 所选图片文件列表
            self.file_names = dlg_file.selectedFiles()
            # 拼图算法类,实例,载入图片
            self.image_stitching.set_images(self.file_names)
            # 在界面上列出所有已选中图片
            for file_name in self.file_names:
                self.tedit_selected_imgs.append(file_name)

2.3、Layout的比例和高宽

2.3.1、 比例

一个layout里面可以塞多个wiget和layout,可以通过比例来调整内部各部件的大小。

例如:

# 横向布局
layout_res_btns = QHBoxLayout()
# 各组件
self.lb_info_name_for_save = QLabel("存储名称")
self.lb_info_dir_for_save = QLabel("存储目录")
self.tedit_save_name = QLineEdit()
self.tedit_save_dir = QLineEdit()
self.btn_result_save = QPushButton("保存")
# 添加这些组件
layout_res_btns.addWidget(self.lb_info_name_for_save)
layout_res_btns.addWidget(self.tedit_save_name)
layout_res_btns.addWidget(self.lb_info_dir_for_save)
layout_res_btns.addWidget(self.tedit_save_dir)
layout_res_btns.addWidget(self.btn_result_save)
# 设置比例
layout_res_btns.setStretch(0,1)
layout_res_btns.setStretch(1,2)
layout_res_btns.setStretch(2,1)
layout_res_btns.setStretch(3,6)
layout_res_btns.setStretch(4,1)

效果如下中间区域那一部分:

「Python」PySide2入门| 简单拼图小工具(PySide2安装,多文件选择,layout宽高设置,显示Opencv图像等)_第3张图片

2.3.2、 宽高

上图可以看出,上下的空白很多,是因为这整个layout的整体高度是自动分配的,而其里面的按钮和文本框,是默认剧中显示的,所有会有很多空白,如何让他具有固定高度呢。

修改方式是将其转换成wiget,来修改:

widget_res_btns = QWidget()
layout_res_btns = QHBoxLayout(widget_res_btns)
layout_res_btns.addWidget(...)
...
...
widget_res_btns.setFixedHeight(40)

2.4、显示Opencv(numpy)图像

python中opencv的图像实际上可以是numpy数组。

需要转换为QImage再添加到QLabel中

self.lb_img_preview = QLabel("结果预览")
img = ....# image from opencv
# 转换为QImage,注意格式,必要时使用cv2.cvtcolor()
image = QImage(img, img.shape[1], img.shape[0], img.strides[0], QImage.Format_BGR888)        
pmap = QPixmap.fromImage(image)#.scaled(lb_size,aspectMode=PySide2.QtCore.Qt.AspectRatioMode.KeepAspectRatio)
# 可以使用scaled设置缩放模式,例如KeepAspectRatio为保证长宽比的情况下自动缩放
self.lb_img_preview.setPixmap(pmap)

3、拼图算法

这里说的拼图就是最简单的拼图概念,把几张图拼成一张

原理就是先遍历所有图片文件,按照最大宽或最大高,创建一张稿纸,再依次把所有图粘贴进去。

使用opencv实现:

def stitching(self, layout):
    # 计算所需稿纸大小
    if layout == "v":
        self.h=sum([i.shape[0] for i in self.imgs])
    if layout == "h":
        self.w=sum([i.shape[1] for i in self.imgs])
    # 初始化稿纸
    color = (255, 255, 255)
    self.dst = np.array([[color for i in range(self.w)]for j in range(self.h)], dtype=np.uint8)
    # 在稿纸上粘贴每一张图片的起始位置
    index = 0
    for img in self.imgs:
        if layout == "v":
            self.dst[index:index + img.shape[0], 0:img.shape[1]] = img
            index = index + img.shape[0]
        if layout == "h":
            self.dst[0:img.shape[0], index:index + img.shape[1]] = img
            index = index + img.shape[1]
    return self.dst

4、所有源码

详细代码见 https://github.com/RainkLH/ImageStitching-pyside2

你可能感兴趣的:(Python,pyqt5,qt5,python,gui)