Pythony应用(02)-截屏并进行文字识别

安装文字识别软件

参考 python-文字识别-tesseract

安装python需要的库

pip install pillow==9.0.1
pip install pytesseract==0.3.8

使用涉及到的技术

  1. tkinter编程
  2. Python+tkinter+pillow实现屏幕任意区域截图
  3. 图片显示
  4. 图片保存
  5. 图片文字识别
  6. 剪贴板复制

具体代码如下

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
文件名: main.py
功 能:XXX类,该类主要涉及XXX功能
版权信息:版本所有(C) 2019-2022
修改记录:
    2022-05-16 19:11:57 创建
    2022-05-16 19:11:57 修改
安装库:
    python -m pip install --upgrade pip
    pip install pillow==9.0.1
    pip install pytesseract==0.3.8
参考资料:
    https://cloud.tencent.com/developer/article/1097904
    https://digi.bib.uni-mannheim.de/tesseract/
    https://gitcode.net/mirrors/tesseract-ocr/tessdata?utm_source=csdn_github_accelerator
    https://zhuanlan.zhihu.com/p/452913602

"""
import tkinter as tk
import tkinter.filedialog
from PIL import ImageGrab, ImageTk, Image
import pytesseract
import time
import os


class MouseCapture:
    """用来显示全屏幕截图并响应二次截图的窗口类"""

    @staticmethod
    def __get_desktop():
        # 创建顶级组件容器
        desktop = tk.Toplevel()
        # 不显示最大化、最小化按钮
        desktop.overrideredirect(True)
        return desktop

    def __canvas_on_mouse_left_button_down(self, event: tk.Event):
        """鼠标左键按下的位置"""
        self.__x_pos.set(getattr(event, "x"))
        self.__y_pos.set(getattr(event, "y"))
        # 开始截图
        self.__select = True

    def __canvas_on_mouse_left_button_move(self, event: tk.Event):
        """鼠标左键移动,显示选取的区域"""
        if not self.__select:
            return

        canvas = getattr(event, "widget")

        # 删除刚画完的图形,要不然鼠标移动的时候是黑乎乎的一片矩形
        canvas.delete(self.__last_draw_rectangle)

        self.__last_draw_rectangle = canvas.create_rectangle(
            self.__x_pos.get(), self.__y_pos.get(),
            getattr(event, "x"), getattr(event, "y"),
            outline='black')

    def __canvas_on_mouse_left_button_up(self, event: tk.Event):
        """获取鼠标左键抬起的位置,保存区域截图"""
        self.__select = False

        canvas = getattr(event, "widget")
        canvas.delete(self.__last_draw_rectangle)

        time.sleep(0.1)

        # 考虑鼠标左键从右下方按下而从左上方抬起的截图
        left, right = sorted([self.__x_pos.get(), getattr(event, "x")])
        top, bottom = sorted([self.__y_pos.get(), getattr(event, "y")])

        self.__capture_bbox = (left + 1, top + 1, right, bottom)
        self.__capture_image = ImageGrab.grab(self.__capture_bbox)
        canvas.master.destroy()

    def __get_canvas(self, master):
        # 屏幕尺寸
        screen_width = master.winfo_screenwidth()
        screen_height = master.winfo_screenheight()
        canvas = tk.Canvas(master, bg='white', width=screen_width,
                           height=screen_height)

        # 显示全屏截图,在全屏截图上进行区域截图
        self.__screen_image = ImageTk.PhotoImage(image=ImageGrab.grab())
        canvas.create_image(screen_width//2, screen_height//2,
                            image=self.__screen_image)

        canvas.bind('<Button-1>', self.__canvas_on_mouse_left_button_down)
        canvas.bind('<B1-Motion>', self.__canvas_on_mouse_left_button_move)
        canvas.bind('<ButtonRelease-1>', self.__canvas_on_mouse_left_button_up)
        # 让canvas充满窗口,并随窗口自动适应大小
        canvas.pack(fill=tk.BOTH, expand=tk.YES)
        return canvas

    def __init__(self):
        # 变量X和Y用来记录鼠标左键按下的位置
        self.__x_pos = tk.IntVar(value=0)
        self.__y_pos = tk.IntVar(value=0)
        self.__screen_image = None
        self.__select = False
        self.__last_draw_rectangle = None
        self.__capture_bbox = None
        self.__capture_image = None

        self.__desktop = self.__get_desktop()
        self.__get_canvas(self.__desktop)

    def __del__(self):
        # 关闭当前窗口
        self.__desktop.destroy()

    @property
    def desktop(self):
        return self.__desktop

    @property
    def capture_bbox(self):
        return self.__capture_bbox

    @property
    def capture_image(self):
        return self.__capture_image


class Application(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)

        # images = ["capture.png", "copy.png", "save.png", "open.png", "exit.png"]
        # self.__images = [self.__get_image(filename) for filename in images]

        toolbar = tk.Frame(self.master, bd=1, relief=tk.RAISED)
        toolbar.pack(side=tk.TOP, fill=tk.X)
        self.__tool_item(toolbar, 1, "截取屏幕", bind=self.btn_capture_on_click)
        self.__tool_item(toolbar, 2, "复制文本", command=self.btn_copy_on_click)
        self.__tool_item(toolbar, 3, "保存截图", command=self.btn_save_on_click)
        self.__tool_item(toolbar, 4, "识别图片", command=self.btn_open_on_click)
        self.__tool_item(toolbar, 5, "退出程序", command=self.master.destroy)

        self.pack()

        self.__txt_ocr_text = tk.Text(self, height=10, relief=tk.RAISED)
        self.__txt_ocr_text.pack(fill=tk.X)

        self.__lbl_capture_img = tk.Label(self, relief=tk.RAISED)
        self.__lbl_capture_img.pack(fill=tk.X)

        self.__screen_image = None

    @staticmethod
    def __get_image(filename):
        return ImageTk.PhotoImage(Image.open(os.path.join("images", filename)))

    def __tool_item(self, master, serial_num, text, bind=None, command=None):
        btn_kw = { ## "image": self.__images[serial_num - 1],
                  "compound": tk.LEFT,
                  "relief": tk.FLAT, "text": text, "font": ('', '16')}
        if command:
            btn_kw["command"] = command
        btn = tk.Button(master, **btn_kw)
        if bind:
            btn.bind("<ButtonRelease-1>", bind)
        btn.grid(row=1, column=serial_num, padx=10)

    def btn_open_on_click(self):
        """保存截图"""
        filename = tkinter.filedialog.askopenfilename(
            title='打开图片', filetypes=[('image', '*.jpg *.png')])

        if filename and self.__screen_image:
            self.__screen_image = Image.open(filename)
            self.__ocr_image(self.__screen_image)

    def __ocr_image(self, image: Image):
        tk_image = ImageTk.PhotoImage(image)
        self.__lbl_capture_img.configure(image=tk_image)
        self.__lbl_capture_img.image = tk_image

        # 识别文字,并指定语言
        self.__txt_ocr_text.delete("1.0", "end")
        ocr_text = pytesseract.image_to_string(image, lang='chi_sim')
        self.__txt_ocr_text.insert("end", ocr_text)

    def btn_save_on_click(self):
        """保存截图"""
        filename = tkinter.filedialog.asksaveasfilename(
            title='保存截图', filetypes=[('image', '*.jpg *.png')])

        if filename and self.__screen_image:
            self.__screen_image.save(filename)

    def btn_copy_on_click(self):
        """复制文本到剪贴板"""
        self.master.clipboard_clear()
        ocr_txt = self.__txt_ocr_text.get("1.0", "end").strip()
        self.master.clipboard_append(ocr_txt)
        self.master.update()

    def btn_capture_on_click(self, event: tk.Event):
        """截取屏幕"""
        # 最小化主窗口
        self.master.state('icon')
        time.sleep(0.2)

        # 显示全屏幕截图
        mc = MouseCapture()
        getattr(event, "widget").wait_window(mc.desktop)
        self.__screen_image = mc.capture_image
        self.__ocr_image(self.__screen_image)

        # 截图结束,恢复主窗口
        self.master.state('normal')

    @staticmethod
    def start_app():
        root = tk.Tk()
        root.geometry('800x600')
        Application(master=root)
        root.mainloop()


if __name__ == '__main__':
    Application.start_app()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mengyoufengyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值