一、PySimpleGUI

PySimpleGUI,是一种利用python语言的GUI界面库,能够创建图形化用户界面,相比于pyqt和wxPython,其学习的难度更低,而且实现同样功能的代码量更少,很适于新手入门。

使用前需要安装PySimpleGUI库。

pip inatall PySimpleGUI

GUI窗口可以分成两类设计模式:

  1. One-shot window
  2. Persistent window

第一种窗口是一个弹出窗口,它会收集一些数据,然后消失。 它类似是一种“表格”,旨在快速获取一些信息然后将其关闭;

而第二种窗口是一种逗留的窗口,可以进行循环,读取和处理一些问题,例如opencv的图像处理。因此也更像一个典型的程序。

下面分析一个简单的GUI实现程序(one-shot window):

import PySimpleGUI as sg      

layout = [[sg.Text('My one-shot window.')],      
                 [sg.InputText(key='-IN-')],      
                 [sg.Submit(), sg.Cancel()]]      

window = sg.Window('Window Title', layout)    

event, values = window.read()    
window.close()

text_input = values['-IN-']    
sg.popup('You entered', text_input)
  • 设置窗口内容

layout是GUI窗口的内容,以列表形式给出,列表内部的每一个列表元素代表一行,其中:

sg.Text是文本框,该例程为My one-shot window。

sg.InputText是文本输入框,其中的key是标识输入框,若定位或更新输入框中的内容时用到,可以理解为字典的键。

sg.Submit和sg.Cancel是按钮。

  • 窗口实例化、显示、关闭

window = sg.Window('Window Title', layout)是窗口的实例化,第一个元素是设置的窗口名,第二个是窗口的内容。

event, values = window.read()是窗口显示,其中event获取的是按键值,values获得各个插件的值,该例中为文本输入框的输入内容。

window.close()为关闭窗口。

  • 弹窗

text_input = values['-IN-'] 是输入在文本框中的值。

sg.popup('You entered', text_input)为弹窗,包括文本'You entered'和的值。

演示效果如下,输入HITMAN:

e6fba1994dd8ffa0261dde1b4832f098.png
输入界面

d61f421d250f3bddeafc5f9213839dd2.png
按下submit

按下submit和cancel的弹窗效果是一样的,因为这两个不同点仅为按钮对应的值不同。

打印下event, values的值:

print(event, values)

当输入HITMAN后分别按submit和cancel按钮得到的结果分别为:

Submit {'-IN-': 'HITMAN'}
Cancel {'-IN-': 'HITMAN'}

二、PySimpleGUI+Opencv

接下来分析一个演示程序,该程序来自于GitHub上的PySimpleGUI中DemoPrograms的程序Demo_OpenCV_Simple_GUI.py,其属于第二种设计类型:Persistent window,其能实现通过摄像头获得数据,并使用一些opencv中的基本操作对图像进行处理,并且利用滑块改变参数,包括:

二值化,滑块可以改变两个边缘阈值
高斯模糊,滑块可以改变高斯核的σ
色调,滑块可以改变HSV中H的大小
图像增强,滑块可以改变局部对比度参数

代码如下:

import PySimpleGUI as sg
import cv2
import numpy as np

def main():
    sg.theme('LightGreen')

    # define the window layout
    layout = [
      [sg.Text('OpenCV Demo', size=(60, 1), justification='center')],
      [sg.Image(filename='', key='-IMAGE-')],
      [sg.Radio('None', 'Radio', True, size=(10, 1))],
      [sg.Radio('threshold', 'Radio', size=(10, 1), key='-THRESH-'),
       sg.Slider((0, 255), 128, 1, orientation='h', size=(40, 15), key='-THRESH SLIDER-')],
      [sg.Radio('canny', 'Radio', size=(10, 1), key='-CANNY-'),
       sg.Slider((0, 255), 128, 1, orientation='h', size=(20, 15), key='-CANNY SLIDER A-'),
       sg.Slider((0, 255), 128, 1, orientation='h', size=(20, 15), key='-CANNY SLIDER B-')],
      [sg.Radio('blur', 'Radio', size=(10, 1), key='-BLUR-'),
       sg.Slider((1, 11), 1, 1, orientation='h', size=(40, 15), key='-BLUR SLIDER-')],
      [sg.Radio('hue', 'Radio', size=(10, 1), key='-HUE-'),
       sg.Slider((0, 225), 0, 1, orientation='h', size=(40, 15), key='-HUE SLIDER-')],
      [sg.Radio('enhance', 'Radio', size=(10, 1), key='-ENHANCE-'),
       sg.Slider((1, 255), 128, 1, orientation='h', size=(40, 15), key='-ENHANCE SLIDER-')],
      [sg.Button('Exit', size=(10, 1))]
    ]
    # create the window and show it without the plot
    window = sg.Window('OpenCV Integration', layout, location=(800, 400))
    cap = cv2.VideoCapture(0)
    while True:
        event, values = window.read(timeout=20)
        if event == 'Exit' or event == sg.WIN_CLOSED:
            break

        ret, frame = cap.read()

        if values['-THRESH-']:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)[:, :, 0]
            frame = cv2.threshold(frame, values['-THRESH SLIDER-'], 255, cv2.THRESH_BINARY)[1]
        elif values['-CANNY-']:
            frame = cv2.Canny(frame, values['-CANNY SLIDER A-'], values['-CANNY SLIDER B-'])
        elif values['-BLUR-']:
            frame = cv2.GaussianBlur(frame, (21, 21), values['-BLUR SLIDER-'])
        elif values['-HUE-']:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
            frame[:, :, 0] += int(values['-HUE SLIDER-'])
            frame = cv2.cvtColor(frame, cv2.COLOR_HSV2BGR)
        elif values['-ENHANCE-']:
            enh_val = values['-ENHANCE SLIDER-'] / 40
            clahe = cv2.createCLAHE(clipLimit=enh_val, tileGridSize=(8, 8))
            lab = cv2.cvtColor(frame, cv2.COLOR_BGR2LAB)
            lab[:, :, 0] = clahe.apply(lab[:, :, 0])
            frame = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)

        imgbytes = cv2.imencode('.png', frame)[1].tobytes()
        window['-IMAGE-'].update(data=imgbytes)

    window.close()


main()
  • 窗口内容

sg.theme是窗口的主题,可以改变背景颜色等等。

sg.Image为显示的图片,这个将在后面进一步叙述。

sg.Radio是单选按钮,用于选择图像处理的方式。

sg.Slider为滚动条,orientation='h'设置成水平方向,可以设置参数的范围等。

  • 图像处理

该程序利用while循环,先判断是否按下了EXIT或者右上角的×,如果是的,就退出循环,关闭窗口。

然后如果未关闭窗口,判断values——单选按钮的选择,根据选择,将图像进行对应的处理。

  • 获得摄像头的图像

其全过程包括:

1.sg.Image(filename='', key='-IMAGE-'),设置图像,取键为'-IMAGE-'。

2.cap = cv2.VideoCapture(0),设置摄像头,ret, frame = cap.read(),获得当时的摄像头的图像数据。

3.进行图像处理之后,imgbytes = cv2.imencode('.png', frame)[1].tobytes()

cv2.imencode为将图片格式转换(编码)成流数据,赋值到内存缓存中;主要用于图像数据格式的压缩,方便网络传输。'.png'为png格式编码,按照不同格式编码的结果不一样.tobytes()将流数据转化为bytes形式。

4.window['-IMAGE-'].update(data=imgbytes),将数据更新至键'-IMAGE-'对应的图片中,实现显示。

效果如下:

9d8f729a95f38e0af5d551d2e5bbb61f.png
不进行图像处理

696646ab1a14be6648b83464a46282f9.png
二值化

667fe1b605427f879d1176befe107f21.png
边缘检测

c1c09de8d5897d10e2870dc33c0aae57.png
高斯模糊

6c07101459666ed63fb347e739653dc0.png
色调

e48d16c593c822aedf729768d35c1cfd.png
图像增强
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐