基于PySimpleGUI的Opencv基本操作(Python实现)

基于PySimpleGUI的OpenCV基本操作

欢迎交流学习

功能描述

使用PySimpleGUI模块,对OpenCV基本功能进行可视化展示,主要包括

  1. 图像通道转换(HSV,彩色通道,灰度通道)
  2. 图像大小,对比度,亮度的调整
  3. HSV模式下的色彩追踪(色相,饱和度,明度)
  4. 图像直方图(均值化,CLAHE)
  5. 图像的模糊处理(中值模糊,高斯模糊,双边模糊)
  6. 图像的二值化操作(均值法,高斯法,OTSU法等)
  7. 图像的形态学操作(腐蚀,膨胀,开运算,闭运算)
  8. 图像轮廓的查找功能
  9. 图像拖拽功能

模块功能

import random
import PySimpleGUI as psg 
import numpy as np
import cv2

设计思路

GUI
类初始化__init__
图像读取read_img
图像处理img_handler
图像转码show_img
控件布局layout
图像显示show

代码结构

"""
@author:bjxyc@qq.com
@file:chapter_13_cv2gui.py
@time:2023/12/04
Python Version:
pip国内源:
清华大学:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:https://mirrors.aliyun.com/pypi/simple/
"""
import random
import PySimpleGUI as psg
import numpy as np
import cv2


class MyApp:
    def __init__(self):
        self.img_copy_contours = None
        self.gr_img = None
        self.img = None
        self.img_copy = None
        self.img_result = None
        self.img_location_y = 0
        self.img_location_x = 0
        self.value = None
        self.event = None
        self.screen_width = 1920
        self.screen_height = 1080
        # widget list
        self.np_file_path = psg.Input(disabled=True, size=(20, 5))
        self.bt_file_path = psg.FileBrowse(button_text='选择文件', key='file_path')
        self.bt_file_read = psg.Button(button_text='读取文件', key='file_read')

        # 通道
        self.rd_gray = psg.Radio('黑白', 'is_color', key='-gray-', enable_events=True)
        self.rd_hsv = psg.Radio('HSV', 'is_color', key='-hsv-', enable_events=True)
        self.rd_color = psg.Radio('彩色', 'is_color', key='-color-', default=True, enable_events=True)

        # 直方图
        self.ck_equalizeHist = psg.Checkbox('均值化', key='-equalizeHist-', enable_events=True)
        self.ck_CLAHE = psg.Checkbox('CLAHE', key='-CLAHE-', enable_events=True)

        # 阈值类
        self.rd_threshold_NONE = psg.Radio('无', 'is_threshold', key='-threshold_NONE-', default=True, enable_events=True)
        self.rd_threshold_BINARY = psg.Radio('二值化', 'is_threshold', key='-BINARY-', enable_events=True)
        self.rd_threshold_BINARY_INV = psg.Radio('反二值化', 'is_threshold', key='-BINARY_INV-', enable_events=True)
        self.rd_threshold_TRUNC = psg.Radio('TRUNC', 'is_threshold', key='-TRUNC-', enable_events=True)
        self.rd_threshold_TOZERO = psg.Radio('TOZERO', 'is_threshold', key='-TOZERO-', enable_events=True)
        self.rd_threshold_TOZERO_INV = psg.Radio('TOZERO_INV', 'is_threshold', key='-TOZERO_INV-', enable_events=True)
        self.rd_threshold_MEAN = psg.Radio('均值', 'is_threshold', key='-MEAN-', enable_events=True)
        self.rd_threshold_GAUSSIAN = psg.Radio('高斯', 'is_threshold', key='-GAUSSIANV-', enable_events=True)
        self.rd_threshold_OTSU = psg.Radio('OTSU', 'is_threshold', key='-OTSU-', enable_events=True)
        # 图像平滑
        self.rd_blur_none = psg.Radio('NONE', 'is_blur', default=True, key='-blur_NONE-', enable_events=True)
        self.rd_blur_Gaussian = psg.Radio('高斯', 'is_blur', key='-GaussianBlur-', enable_events=True)
        self.rd_blur_median = psg.Radio('中值', 'is_blur', key='-medianBlur-', enable_events=True)
        self.rd_blur_bilateral = psg.Radio('双边', 'is_blur', key='-bilateral-', enable_events=True)

        # 形态学
        self.rd_morphology_none = psg.Radio('NONE', 'is_morphology', key='-morphology_NONE-', default=True, enable_events=True)
        self.rd_morphology_erode = psg.Radio('腐蚀', 'is_morphology', key='-erode-', enable_events=True)
        self.rd_morphology_dilate = psg.Radio('膨胀', 'is_morphology', key='-dilate-', enable_events=True)
        # self.rd_morphology_open = psg.Radio('开运算', 'is_morphology', key='-open-', enable_events=True)
        # self.rd_morphology_close = psg.Radio('闭运算', 'is_morphology', key='-close-', enable_events=True)
        self.rd_morphology_open = psg.Checkbox('开运算', key='-open-', enable_events=True)
        self.rd_morphology_close = psg.Checkbox('闭运算', key='-close-', enable_events=True)

        # 轮廓
        self.rd_find_contour_none = psg.Radio('NONE', 'is_find_contour', key='-find_contour_none-', default=True, enable_events=True)
        self.rd_find_contour = psg.Radio('找轮廓', 'is_find_contour', key='-find_contour-', enable_events=True)
        self.rd_find_contour_boundingRect = psg.Checkbox('外接矩', key='-boundingRect-', enable_events=True)
        self.rd_find_contour_minEnclosingCircle = psg.Checkbox('外接圆', key='-minEnclosingCircle-', enable_events=True)
        self.rd_find_contour_ellipse = psg.Checkbox('外接椭', key='-ellipse-', enable_events=True)
        self.tt_contour_area = psg.Text()
        self.tt_contour_length = psg.Text()

        self.sl_img_scale = psg.Slider((0.01, 2), default_value=1, orientation='horizontal', resolution=0.01, key='-scale-', enable_events=True)
        self.sl_img_contrast = psg.Slider((0, 2), default_value=1, orientation='horizontal', resolution=0.01, key='-contrast-', enable_events=True)
        self.sl_img_light = psg.Slider((-255, 255), default_value=0, orientation='horizontal', key='-light-', enable_events=True)
        self.sl_img_hsv_lower_h = psg.Slider((0, 255), default_value=0, orientation='horizontal', key='-hsv_lower_h-', enable_events=True)
        self.sl_img_hsv_lower_s = psg.Slider((0, 255), default_value=0, orientation='horizontal', key='-hsv_lower_s-', enable_events=True)
        self.sl_img_hsv_lower_v = psg.Slider((0, 255), default_value=0, orientation='horizontal', key='-hsv_lower_v-', enable_events=True)
        self.sl_img_hsv_upper_h = psg.Slider((0, 180), default_value=180, orientation='horizontal', key='-hsv_upper_h-', enable_events=True)
        self.sl_img_hsv_upper_s = psg.Slider((0, 255), default_value=255, orientation='horizontal', key='-hsv_upper_s-', enable_events=True)
        self.sl_img_hsv_upper_v = psg.Slider((0, 255), default_value=255, orientation='horizontal', key='-hsv_upper_v-', enable_events=True)
        self.sl_img_threshold = psg.Slider((0, 255), default_value=127, orientation='horizontal', key='-threshold-', enable_events=True)
        self.sl_img_blue = psg.Slider((0, 10), default_value=2, orientation='horizontal', key='-blur-', enable_events=True)
        self.sl_img_morphology = psg.Slider((0, 10), default_value=2, orientation='horizontal', key='-morphology-', enable_events=True)
        self.sl_img_morphology_times = psg.Slider((0, 10), default_value=2, orientation='horizontal', key='-morphology_times-', enable_events=True)
        self.mg_img_show = psg.Image(key='-image-')
        self.gr_img_show = psg.Graph(canvas_size=(1400, 1000), graph_bottom_left=(0, 1000), graph_top_right=(1400, 0), background_color="white",
                                     key="-GRAPH-", drag_submits=True, enable_events=True)
        # function dict
        self.func_dict = {
            'file_read': self.read_img,
            '-scale-': self.img_handler,
            '-contrast-': self.img_handler,
            '-light-': self.img_handler,
            '-gray-': self.img_handler,
            '-color-': self.img_handler,
            '-hsv-': self.img_handler,
            '-hsv_lower_h-': self.img_handler,
            '-hsv_lower_s-': self.img_handler,
            '-hsv_lower_v-': self.img_handler,
            '-hsv_upper_h-': self.img_handler,
            '-hsv_upper_s-': self.img_handler,
            '-hsv_upper_v-': self.img_handler,
            '-threshold_NONE-': self.img_handler,
            '-BINARY-': self.img_handler,
            '-BINARY_INV-': self.img_handler,
            '-TRUNC-': self.img_handler,
            '-TOZERO-': self.img_handler,
            '-TOZERO_INV-': self.img_handler,
            '-threshold-': self.img_handler,
            '-MEAN-': self.img_handler,
            '-GAUSSIANV-': self.img_handler,
            '-OTSU-': self.img_handler,
            '-blur_NONE-': self.img_handler,
            '-GaussianBlur-': self.img_handler,
            '-medianBlur-': self.img_handler,
            '-bilateral-': self.img_handler,
            '-blur-': self.img_handler,
            '-morphology_NONE-': self.img_handler,
            '-erode-': self.img_handler,
            '-dilate-': self.img_handler,
            '-morphology-': self.img_handler,
            '-morphology_times-': self.img_handler,
            '-open-': self.img_handler,
            '-close-': self.img_handler,
            '-find_contour_none-': self.img_handler,
            '-find_contour-': self.img_handler,
            '-boundingRect-': self.img_handler,
            '-minEnclosingCircle-': self.img_handler,
            '-ellipse-': self.img_handler,
            '-equalizeHist-': self.img_handler,
            '-CLAHE-': self.img_handler,

        }
        # Create windows
        # self.win = psg.Window('CV2GUI', layout=self.layout(), size=(self.screen_width, self.screen_height), no_titlebar=True)
        self.win = psg.Window('CV2GUI', layout=self.layout(), size=(self.screen_width, self.screen_height))

    def img_handler(self):
        # 参数获取
        f = self.value['-scale-']
        alpha = self.value['-contrast-']
        beta = self.value['-light-']
        hsv_lower_h = self.value['-hsv_lower_h-']
        hsv_lower_s = self.value['-hsv_lower_s-']
        hsv_lower_v = self.value['-hsv_lower_v-']
        hsv_upper_h = self.value['-hsv_upper_h-']
        hsv_upper_s = self.value['-hsv_upper_s-']
        hsv_upper_v = self.value['-hsv_upper_v-']
        threshold = self.value['-threshold-']
        blur = int(self.value['-blur-'] * 2 + 1)
        morphology = int(self.value['-morphology-'] * 2 + 1)
        morphology_times = int(self.value['-morphology_times-'] * 2 + 1)

        # 图像通道
        if self.value['-gray-']:
            self.img_result = cv2.cvtColor(self.img_copy, cv2.COLOR_BGR2GRAY)
        if self.value['-color-']:
            self.img_result = self.img_copy
        if self.value['-hsv-']:
            self.img_result = cv2.cvtColor(self.img_copy, cv2.COLOR_BGR2HSV)
            lower_blue = np.array([hsv_lower_h, hsv_lower_s, hsv_lower_v])
            upper_blue = np.array([hsv_upper_h, hsv_upper_s, hsv_upper_v])
            mask = cv2.inRange(self.img_result, lower_blue, upper_blue)
            self.img_result = cv2.bitwise_and(self.img_copy, self.img_copy, mask=mask)

        # 图像缩放
        # self.img_result = cv2.resize(self.img_result, (0, 0), fx=f, fy=f)

        # 对比度,亮度
        self.img_result = cv2.convertScaleAbs(self.img_result, alpha=alpha, beta=beta)

        if self.value['-equalizeHist-']:
            try:
                self.img_result = cv2.equalizeHist(self.img_result)
            except cv2.error as e:
                psg.popup_error('黑白通道有效')

        if self.value['-CLAHE-']:
            try:
                clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
                self.img_result = clahe.apply(self.img_result)
            except cv2.error as e:
                psg.popup_error('黑白通道有效')

        # 图像平滑
        if self.value['-blur_NONE-']:
            pass
        if self.value['-GaussianBlur-']:
            self.img_result = cv2.GaussianBlur(self.img_result, (blur, blur), 0)
        if self.value['-medianBlur-']:
            self.img_result = cv2.medianBlur(self.img_result, blur)
        if self.value['-bilateral-']:
            self.img_result = cv2.bilateralFilter(self.img_result, blur, 75, 75)

        # 阈值类
        if self.value['-threshold_NONE-']:
            pass
        if self.value['-BINARY-']:
            _, self.img_result = cv2.threshold(self.img_result, threshold, 255, cv2.THRESH_BINARY)
        if self.value['-BINARY_INV-']:
            _, self.img_result = cv2.threshold(self.img_result, threshold, 255, cv2.THRESH_BINARY_INV)
        if self.value['-TRUNC-']:
            _, self.img_result = cv2.threshold(self.img_result, threshold, 255, cv2.THRESH_TRUNC)
        if self.value['-TOZERO-']:
            _, self.img_result = cv2.threshold(self.img_result, threshold, 255, cv2.THRESH_TOZERO)
        if self.value['-TOZERO_INV-']:
            _, self.img_result = cv2.threshold(self.img_result, threshold, 255, cv2.THRESH_TOZERO_INV)
        if self.value['-MEAN-']:
            try:
                self.img_result = cv2.adaptiveThreshold(self.img_result, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 2)
            except cv2.error as e:
                psg.popup_error('黑白通道有效')
        if self.value['-GAUSSIANV-']:
            try:
                self.img_result = cv2.adaptiveThreshold(self.img_result, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
            except cv2.error as e:
                psg.popup_error('黑白通道有效')
        if self.value['-OTSU-']:
            try:
                _, self.img_result = cv2.threshold(self.img_result, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
            except cv2.error as e:
                psg.popup_error('黑白通道有效')

        # 形态学

        if self.value['-morphology_NONE-']:
            pass
        if self.value['-erode-']:
            kernel = np.ones((morphology, morphology), np.uint8)
            self.img_result = cv2.erode(self.img_result, kernel, iterations=morphology_times)
        if self.value['-dilate-']:
            kernel = np.ones((morphology, morphology), np.uint8)
            self.img_result = cv2.dilate(self.img_result, kernel, iterations=morphology_times)
        if self.value['-open-']:
            kernel = np.ones((morphology, morphology), np.uint8)
            self.img_result = cv2.morphologyEx(self.img_result, cv2.MORPH_OPEN, kernel)
        if self.value['-close-']:
            kernel = np.ones((morphology, morphology), np.uint8)
            self.img_result = cv2.morphologyEx(self.img_result, cv2.MORPH_CLOSE, kernel)

        # 轮廓
        if self.value['-find_contour_none-']:
            pass
        if self.value['-find_contour-']:
            contours, hierarchy = cv2.findContours(self.img_result, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
            print(len(contours))
            self.img_copy_contours = self.img_copy.copy()

            for i in range(len(contours)):
                b = random.randint(0, 255)
                g = random.randint(0, 255)
                r = random.randint(0, 255)
                cv2.drawContours(self.img_copy_contours, contours, i, (b, g, r), 2)
                if self.value['-minEnclosingCircle-']:
                    (x, y), radius = cv2.minEnclosingCircle(contours[i])
                    center = (int(x), int(y))
                    radius = int(radius)
                    cv2.circle(self.img_copy_contours, center, radius, (b, g, r), 2)
                if self.value['-ellipse-']:
                    ellipse = cv2.fitEllipse(contours[i])
                    cv2.ellipse(self.img_copy_contours, ellipse, (b, g, r), 2)
                if self.value['-boundingRect-']:
                    x, y, w, h = cv2.boundingRect(contours[i])
                    cv2.rectangle(self.img_copy_contours, (x, y), (x + w, y + h), (b, g, r), 2)
            self.img_result = self.img_copy_contours

        # 图像缩放
        self.img_result = cv2.resize(self.img_result, (0, 0), fx=f, fy=f)

        self.show_img(self.img_result)
        pass

    def show_img(self, img):
        img_bytes = cv2.imencode('.png', img)[1].tobytes()
        self.gr_img_show.delete_figure(self.gr_img)
        self.gr_img = self.gr_img_show.draw_image(data=img_bytes, location=(self.img_location_x, self.img_location_y))
        self.gr_img_show.update(background_color="white")

    def read_img(self):
        path = self.value['file_path']
        self.img = cv2.imread(path)
        self.img_copy = self.img.copy()
        self.show_img(self.img_copy)

    def layout(self):
        layout_col_1 = [
            [psg.Exit()],
            [self.np_file_path, self.bt_file_path, self.bt_file_read],
            [psg.Text('通  道:', size=(9, 1), font=('黑体', 12)), self.rd_gray, self.rd_color, self.rd_hsv],
            [psg.Text('缩  放:', size=(9, 1), font=('黑体', 12)), self.sl_img_scale],
            [psg.Text('对比度:', size=(9, 1), font=('黑体', 12)), self.sl_img_contrast],
            [psg.Text('亮  度:', size=(9, 1), font=('黑体', 12)), self.sl_img_light],
            [psg.Text('色  相:', size=(9, 1), font=('黑体', 12)), self.sl_img_hsv_lower_h, self.sl_img_hsv_upper_h],
            [psg.Text('饱和度:', size=(9, 1), font=('黑体', 12)), self.sl_img_hsv_lower_s, self.sl_img_hsv_upper_s],
            [psg.Text('明  度:', size=(9, 1), font=('黑体', 12)), self.sl_img_hsv_lower_v, self.sl_img_hsv_upper_v],
            [psg.Text('直方图:', size=(9, 1), font=('黑体', 12)), self.ck_equalizeHist, self.ck_CLAHE],
            [psg.Text('平滑类:', size=(9, 1), font=('黑体', 12)), self.rd_blur_none, self.rd_blur_median, self.rd_blur_Gaussian,
             self.rd_blur_bilateral],
            [psg.Text('卷积核:', size=(9, 1), font=('黑体', 12)), self.sl_img_blue],
            [psg.Text('阈值类:', size=(9, 1), font=('黑体', 12)), self.rd_threshold_NONE, self.rd_threshold_MEAN, self.rd_threshold_GAUSSIAN,
             self.rd_threshold_OTSU],
            [self.rd_threshold_BINARY, self.rd_threshold_BINARY_INV, self.rd_threshold_TRUNC, self.rd_threshold_TOZERO, self.rd_threshold_TOZERO_INV],
            [psg.Text('阈  值:', size=(9, 1), font=('黑体', 12)), self.sl_img_threshold],
            [psg.Text('形态学:', size=(9, 1), font=('黑体', 12)), self.rd_morphology_none, self.rd_morphology_erode, self.rd_morphology_dilate,
             self.rd_morphology_open, self.rd_morphology_close],
            [psg.Text('卷积核:', size=(9, 1), font=('黑体', 12)), self.sl_img_morphology],
            [psg.Text('迭代数:', size=(9, 1), font=('黑体', 12)), self.sl_img_morphology_times],
            [psg.Text('找轮廓:', size=(9, 1), font=('黑体', 12)), self.rd_find_contour_none, self.rd_find_contour,
             self.rd_find_contour_boundingRect, self.rd_find_contour_minEnclosingCircle, self.rd_find_contour_ellipse],

        ]
        layout_col_2 = [
            [self.gr_img_show]
        ]
        layout = [
            [psg.Column(layout_col_1, size=(500, 900)), psg.Column(layout_col_2)]
        ]
        return layout

    def show(self):
        x1, gx, y1, gy = None, None, None, None
        while True:
            self.event, self.value = self.win.read()
            print(self.event, self.value)
            if self.event in [None, 'Exit']:
                self.win.close()
                break
            if self.event in self.func_dict:
                self.func_dict[self.event]()
            # 鼠标跟随事件
            if self.event in ['-GRAPH-']:
                x, y = self.value['-GRAPH-']
                if not x1 or not y1:
                    x1, y1 = x, y
                    gx, gy = self.gr_img_show.get_bounding_box(self.gr_img)[0]
                dx, dy = x - x1, y - y1
                self.img_location_x = gx + dx
                self.img_location_y = gy + dy
                self.gr_img_show.relocate_figure(self.gr_img, gx + dx, gy + dy)
            if self.event in ['-GRAPH-+UP']:
                x1, gx, y1, gy = None, None, None, None


if __name__ == '__main__':
    app = MyApp()
    app.show()

GUI示例

GUI

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
opencv——基于python语言实现》pdf 是一本介绍了使用Python语言实现OpenCV库的编程技术的电子书。 OpenCV 是一个广泛应用于计算机视觉领域的开源库,它提供了许多用于图像处理和计算机视觉的函数和算法。 该电子书首先介绍了OpenCVPython的基本概念和背景知识,如图像处理的基本操作和图像编程的基本原理。它还详细介绍了OpenCV库中的各种图像处理算法和函数,并提供了许多示例代码和案例研究,以帮助读者理解和应用这些算法和函数。 该电子书还涵盖了如何使用PythonOpenCV进行人脸检测、目标跟踪、图像识别和图像分割等常见任务。它还介绍了如何利用OpenCVPython进行视频处理和实时图像处理,并展示了如何与摄像头和外部设备进行交互。 这本书对于希望学习和应用OpenCVPython进行图像处理和计算机视觉的人来说是非常有价值的。它详细讲解了OpenCV库中的各种函数和算法的使用方法,并提供了丰富的示例和案例研究。读者可以通过学习该书,深入了解OpenCVPython的使用,并掌握图像处理和计算机视觉的基本原理和技术,从而能够应用于实际项目和应用中。 总之,《opencv——基于python语言实现》pdf 是一本适合初学者和有一定基础的人学习和应用OpenCVPython进行图像处理和计算机视觉的电子书。通过阅读该书,读者可以全面了解OpenCV库的使用方法和基本原理,并掌握使用Python语言进行图像处理和计算机视觉任务的技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值