自己写个OCR工具,某捷休想再从我这里收费

在人工智能日益发达,python大行其道的今天,一些OCR(光学字符识别,其实就是识别图片中的文字)工具居然还要收费,叔可忍,婶不可忍,于是做了一个个人OCR工具。使用这个工具,在利用snipaste或类似软件进行屏幕截图后,将截图保存到系统剪贴板,再按下工具提示的热键,可以将剪贴板中的图形数据识别为文本后复制到剪贴板,之后在需要识别出的文字的地方就能直接ctrl+v完成粘贴;也可以识别成excel文件保存,并将保存的excel文件单元格的宽度、高度和对齐方式调整为比较合适的状态。如果图片已经保存在电脑上,则可以利用工具的另一个功能,将文件夹下所有的图片全部识别为文本文件保存。

工具用到了百度人工智能接口,操作excel文件使用的xlwings,因此,使用此工具要求电脑已联网,并且安装了excel软件。这个工具一方面有一定的实用性,另一方面也演示了tinker、xlwings、keyboard等程序包的部分用途,逻辑上并不复杂,代码有详尽注释,可供参考。

from aip import AipOcr  # 导入AipOcr模块,用于做文字识别,pip install baidu-aip, pip install chardet
import time  # 时间模块
import requests  # 用于下载,pip install requests
import io  # 用于创建写入剪贴板中的图像数据的字节数组
from PIL import ImageGrab  # 用于获取剪贴板上的图像数据,pip install pillow
import keyboard  # 用于注册热键,pip install keyboard
import pyperclip  # 用于将识别的文本内容复制到剪贴板,pip install pyperclip
import xlwings as excel  # 用于操作excel文件,pip install xlwingsfrom aip import AipOcr  # 导入AipOcr模块,用于做文字识别,pip install baidu_aip, pip install chardet
import time  # 时间模块
import requests  # 用于下载,pip install requests
import io  # 用于创建写入剪贴板中的图像数据的字节数组
from PIL import ImageGrab  # 用于获取剪贴板上的图像数据,pip install pillow
import keyboard  # 用于注册热键,pip install keyboard
import pyperclip  # 用于将识别的文本内容复制到剪贴板,pip install pyperclip
import xlwings as excel  # 用于操作excel文件,pip install xlwings

APP_ID = baidu_keys.APP_ID
API_KEY = baidu_keys.API_KEY
SECRET_KEY = baidu_keys.SECRET_KEY
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# 工具用法
usage = '\n用法:\n  截图复制到剪贴板后按“shift+esc”识别表格,按“alt+esc”识别文本。\n  ' + \
    '按“alt+shift+f”识别指定文件夹中的图片。\n  按“cmd+esc”退出程序。\n'

"""识别表格"""
def table_ocr():
    try:
        print('开始识别...')
        file = None
        image = ImageGrab.grabclipboard()
        if image != None:
            img_bytes = io.BytesIO()
            image.save(img_bytes, format='png')
            table = client.tableRecognitionAsync(img_bytes.getvalue())
            request_id = table['result'][0]['request_id']
            # 判断识别是否完成,直到完成才根据请求ID获取Excel下载路径
            result = client.getTableRecognitionResult(request_id)  # 通过ID获取识别结果
            while result['result']['ret_msg'] != '已完成':  # 如果状态是“已完成”,才能获取下载地址
                time.sleep(2)  # 暂停2秒再刷新
                result = client.getTableRecognitionResult(
                    request_id)  # 持续刷新,直到满足条件
            download_path = result['result']['result_data']

            # 下载Excel文件
            excel = requests.get(download_path)  # 抓取下载链接
            # win32ui.MessageBox('请指定识别文件保存位置及文件名...')
            print('请指定识别文件保存位置及文件名...')
            """win32ui打开保存文件对话框,但win32ui目前尚没有打开文件夹对话框,故改用tinker
            flags = win32con.OFN_OVERWRITEPROMPT
            dlg = win32ui.CreateFileDialog(0, 'xls', '识别结果', flags, 'Excel Files (*.xlsx)|*.xls;*.xlsx||', None) #0表示保存文件对话框;1表示打开文件对话框
            dlg.DoModal()
            file = dlg.GetPathName()"""
            # tinker打开保存文件对话框
            root = tk.Tk()
            # root.withdraw()  # 隐藏tk主窗口。因为随即销毁tk,所以并无必要
            file = filedialog.asksaveasfilename(title='保存文件', filetypes=(("excel files", "*.xls"),),
                                                defaultextension='xls', initialfile='识别结果', initialdir='/')
            root.destroy()

            with open(file, 'wb') as f:  # 新建excel文件
                f.write(excel.content)  # 写入excel文件并保存
            # 调整保存的excel文件格式
            adjust_table(file, 'body')

        else:
            print('系统剪贴板中没有读取到图形数据。')
        print(
            f'{["识别已完成,结果保存为文件:" + file if file != None else "剪贴板中没有图形数据,无识别结果。"][0]}')
        print(usage)
    except:
        print('识别出错,请重新启动程序识别!')
        sys.exit()

"""修改excel文件单元格的边框,宽度,高度,对齐方式"""
def adjust_table(file, sheet_name):
    char_width = 2.13  # 字符宽度,这里用的经验值,12号汉字宽度大约2.13mm,字号变大或缩小可以调整这个值
    excel_app = excel.App(visible=False, add_book=False)  # 打开excel但隐藏软件界面
    try:
        excel_workbook = excel_app.books.open(file)
        excel_sheet = excel_workbook.sheets[sheet_name]
        rows, cols = excel_sheet.used_range.shape  # 表格中被编辑过的单元格最大行号和列号
        u_range = excel_sheet.range(excel_sheet.range('A1'), excel_sheet.range(rows, cols))
        u_range.api.Font.Size = 12          # 设置字体的大小。
        u_range.api.Borders(9).LineStyle = 1  # 底边框
        u_range.api.Borders(9).Weight = 4  # 边框粗细,最大值为4
        u_range.api.Borders(7).LineStyle = 1  # 左边框
        u_range.api.Borders(7).Weight = 4
        u_range.api.Borders(8).LineStyle = 1  # 上边框
        u_range.api.Borders(8).Weight = 4
        u_range.api.Borders(10).LineStyle = 1  # 右边框
        u_range.api.Borders(10).Weight = 4
        u_range.api.Borders(11).LineStyle = 1  # 内部垂直边框
        u_range.api.Borders(11).Weight = 2
        u_range.api.Borders(12).LineStyle = 1  # 内部水平边框
        u_range.api.Borders(12).Weight = 2
        """调整完字体大小和边框后,使单元格自适应宽度和高度,也可以用
        range.columns.autofit()
        range.rows.autofit()
        """
        excel_sheet.autofit()

        for col in range(1, cols + 1):
            for row in range(1, rows + 1):
                # cell_name = chr(64 + col) + str(row) #求出‘A1’形式的单元格名称,由于索引从1开始,转换为字符只加64
                # cell = excel_sheet[cell_name] #当列名字母数量超过1个时,列的数字序号转换为列名比较复杂,因此应该用下面的方法构造cell
                cell = excel_sheet.range(row, col)
                if cell.value != None:  # 被合并的单元格值为None,这种单元格直接跳过
                    value = str(cell.value)  # 取得单元格的内容,用于估算单元格内容的宽度

                    # 对自适应的宽度做一个调整,最大宽度设为50,最小宽度设为10
                    if cell.column_width >= 50:
                        cell.column_width = 50
                    elif cell.column_width <= 10:
                        cell.column_width = 10

                    column_width = cell.column_width
                    # 计算合并单元格的宽度,为合并区域所有列的宽度
                    if cell.merge_cells:  # 当前单元格为合并单元格
                        for i in range(col + 1, cell.merge_area.columns.count + 1):
                            r = excel_sheet.range(row, i)
                            column_width += r.column_width

                    cell.api.VerticalAlignment = -4108  # 单元格纵向居中
                    # 调整单元格水平对齐方式
                    if column_width >= len(value)*char_width:  # 估算文字宽度小于单元格宽度,单元格水平居中
                        cell.api.HorizontalAlignment = -4108
                    else:  # 估算文字宽度大于单元格宽度,单元格自动换行靠左对齐
                        cell.api.HorizontalAlignment = -4130
        # 调整各行高度,单元格纵向留空白
        for row in range(1, rows + 1):
            excel_sheet.range(row, 1).row_height += 8
        # 保存修改,关闭文件,退出excel
        excel_workbook.save()
        excel_workbook.close()
        excel_app.quit()
    except:  # 万一出错关闭文件退出excel
        excel_workbook.close()
        excel_app.quit()

"""识别文本,识别结果在控制台输出,并直接拷贝到剪贴板"""
def text_ocr():
    try:
        image = ImageGrab.grabclipboard()
        if image != None:
            img_bytes = io.BytesIO()
            image.save(img_bytes, format="png")
            text = client.basicAccurate(img_bytes.getvalue())
            result = text['words_result']
            txt = str('')
            for i in result:
                txt = txt + i['words'] + '\n'
            print('\n-----------\n', txt)
            pyperclip.copy(txt)
        else:
            print('系统剪贴板中没有读取到图形数据。')
        print(usage)
    except:
        print('识别出错,请重新启动程序识别!')
        sys.exit()

"""将指定文件夹中的图片识别为文本文件"""
def img_ocr():
    try:
        root = tk.Tk()
        # root.withdraw()  # 隐藏tk主窗口。因为随即销毁tk,所以并无必要
        # 获取图片所在文件夹
        path = filedialog.askdirectory(title='打开文件夹', initialdir='/')
        root.destroy()
        # 识别完成图片数量计数
        pages = 0
        path_name = ''
        # 遍历图片文件夹,将所有png、jpg、jpeg、bmp文件扫描为同名txt文件保存在同一目录下
        for file in os.scandir(path):
            (path_name, ext) = os.path.splitext(file)
            ext = ext.lower()  # 文件扩展名转换为小写字母
            if(ext == '.png' or ext == '.jpg' or ext == '.jpeg' or ext == '.bmp'):
                with open(file, 'rb') as f:
                    # 调用百度人工智能识别
                    text = client.basicAccurate(f.read())
                    result = text["words_result"]
                    # 将识别出的文本逐行写入文本文件
                    with open(path_name + '.txt', 'a', encoding='utf-8') as txt:
                        for i in result:
                            txt.write(i["words"] + '\n')
                    pages += 1
                    print('识别完成了%d页!' % (pages))
        if pages == 0:
            print('文件夹中没有支持的图片。')
        else:
            print(f'文件夹“{os.path.dirname(path_name)}”识别完毕!共识别了{pages}个图片。')
        print(usage)
    except:
        print('识别出错,请重新启动程序识别!')
        sys.exit()


if __name__ == '__main__':
    print(usage)
    keyboard.add_hotkey('alt+esc', text_ocr)
    keyboard.add_hotkey('shift+esc', table_ocr)
    keyboard.add_hotkey('shift+alt+f', img_ocr)
    keyboard.wait('cmd+esc')
    print('Bye.')
    sys.exit()

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yivifu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值