批量识别身份证并导出excel工具分享,身份证识别工具离线识别 + 字段精准优化,Win10/11 直接用

还在手动录入身份证信息?一行行输姓名、身份证号、地址,不仅费眼还容易错,每天录上百条能累到手腕疼!在网上找到了这款吾爱大神写的工具,从 V1.0.3 开源到现在更新到 V1.0.5,核心解决 "识别慢、字段错、依赖显卡 / 网络" 的问题,纯 CPU 运行、离线可用,Win10/11 直接跑,现在分享给有同样需求的同行!(文末附下载地址)

版本迭代:每一次更新都直击使用痛点

从最初版本到 V1.0.5,工具一直在优化核心体验,尤其解决了大家反馈的关键问题:

V1.0.3(开源版):基础功能拉满,效率先提档

  • 核心升级:优化启动速度(打开软件从 10 秒缩到 3 秒),新增识别字段(补全民族、出生日期、有效期等易漏字段);
  • 实用功能:图片重命名(可选配置,识别后自动按 "姓名 - 身份证号" 命名图片)、Excel 导出可选(仅填图片路径 / 直接嵌入图片);
  • 代码开源:核心逻辑已放出,有开发能力的伙伴可下载源码自定义修改(附件自取),适配自家业务场景。

V1.0.4:解决使用体验 "小麻烦"

  • 模型本地化:模型随程序分发,初次启动不用再下载几百 M 的模型包,开箱即用;
  • 终端弹窗修复:彻底解决启动后黑框终端关不掉的问题,界面更清爽,不用手动杀进程。

V1.0.5:精准度再升级

  • 字段匹配优化:重构识别字段的匹配算法,姓名、身份证号、地址等核心字段识别准确率提升 15%,尤其解决了 "地址含生僻字识别错""身份证号末尾 X 识别成 x" 的问题;
  • 无额外依赖变更:依旧纯 CPU 运行,不用折腾显卡配置,老电脑也能扛。

工具已经打包好:

链接:https://pan.quark.cn/s/423f3761c712

源码分享

python 复制代码
# 在gui.py文件中添加以下代码
import re<p></p>
<p>from PySide6.QtCore import QThread, Signal
import traceback
from openpyxl.workbook import Workbook
from openpyxl.drawing.image import Image as XLImage
from openpyxl.styles import Alignment</p>
<p>import cv2
import numpy as np
from PIL import Image</p>
<p>'''
ocr实际开始工作的线程
需要将前边加载好的模型传递过来
'''
class OCRWorker(QThread):</p>
<h2 id="53093959_定义信号,用于通知主线程处理进度和结果">定义信号,用于通知主线程处理进度和结果</h2>
<pre><code data-highlighted="yes" class="hljs language-python">progress_updated = Signal(<span class="hljs-built_in">int</span>, <span class="hljs-built_in">int</span>)  <span class="hljs-comment"># 当前进度,总数量</span>
finished_signal = Signal()  <span class="hljs-comment"># 处理完成信号</span>
error_occurred = Signal(<span class="hljs-built_in">str</span>)  <span class="hljs-comment"># 错误信息信号</span>
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, file_paths, export_options, ocr</span>):
    <span class="hljs-built_in">super</span>().__init__()
    <span class="hljs-variable language_">self</span>.file_paths = file_paths
    <span class="hljs-variable language_">self</span>.export_options = export_options
    <span class="hljs-variable language_">self</span>.ocr = ocr
    <span class="hljs-variable language_">self</span>._should_terminate = <span class="hljs-literal">False</span>  <span class="hljs-comment"># 添加终止标志</span>
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">run</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># 处理所有文件</span>
        <span class="hljs-variable language_">self</span>.process_files(<span class="hljs-variable language_">self</span>.file_paths)
 
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        error_msg = <span class="hljs-string">f"处理过程中发生错误: <span class="hljs-subst">{<span class="hljs-built_in">str</span>(e)}</span>\n<span class="hljs-subst">{traceback.format_exc()}</span>"</span>
        <span class="hljs-variable language_">self</span>.error_occurred.emit(error_msg)
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">process_files</span>(<span class="hljs-params">self, file_paths</span>):
    wb = Workbook()
    ws = wb.active
    ws.append([<span class="hljs-string">"图片"</span>, <span class="hljs-string">"姓名"</span>, <span class="hljs-string">"性别"</span>, <span class="hljs-string">"民族"</span>, <span class="hljs-string">"出生日期"</span>, <span class="hljs-string">"住址"</span>, <span class="hljs-string">"身份证号"</span>, <span class="hljs-string">"有效期限"</span>])
    row_idx = <span class="hljs-number">2</span>
 
    total_files = <span class="hljs-built_in">len</span>(<span class="hljs-variable language_">self</span>.file_paths)
    processed_count = <span class="hljs-number">0</span>
    <span class="hljs-keyword">for</span> i, path <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(file_paths):
 
        <span class="hljs-comment"># 检查是否收到终止请求</span>
        <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>._should_terminate:
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"收到终止请求,正在保存已处理的数据..."</span>)
            <span class="hljs-keyword">break</span>
        <span class="hljs-comment"># 发送进度更新信号</span>
        <span class="hljs-variable language_">self</span>.progress_updated.emit(i + <span class="hljs-number">1</span>, total_files)
        info = <span class="hljs-variable language_">self</span>.extract_info_from_image(path)
        <span class="hljs-comment"># 检查线程是否被中断</span>
        <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>.isInterruptionRequested():
            <span class="hljs-keyword">break</span>
        <span class="hljs-keyword">if</span> info:
            ws.cell(row=row_idx, column=<span class="hljs-number">2</span>, value=info[<span class="hljs-string">"姓名"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">3</span>, value=info[<span class="hljs-string">"性别"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">4</span>, value=info[<span class="hljs-string">"民族"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">5</span>, value=info[<span class="hljs-string">"出生日期"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">6</span>, value=info[<span class="hljs-string">"住址"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">7</span>, value=info[<span class="hljs-string">"身份证号"</span>])
            ws.cell(row=row_idx, column=<span class="hljs-number">8</span>, value=info[<span class="hljs-string">"有效期限"</span>])
 
            <span class="hljs-comment"># 根据导出选项决定如何处理图片</span>
            export_option = <span class="hljs-variable language_">self</span>.export_options.get(<span class="hljs-string">"export_option"</span>, <span class="hljs-string">"image_path"</span>)
 
            <span class="hljs-comment"># 处理重命名(如果配置了重命名选项)</span>
            <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>.should_rename_file(info):
                new_path = <span class="hljs-variable language_">self</span>.rename_file(path, info)
                <span class="hljs-comment"># 更新图片路径为重命名后的路径</span>
                <span class="hljs-keyword">if</span> export_option == <span class="hljs-string">"image_path"</span>:
                    ws.cell(row=row_idx, column=<span class="hljs-number">1</span>, value=new_path)
                <span class="hljs-comment"># 更新返回数据中的图片路径</span>
                info[<span class="hljs-string">"图片路径"</span>] = new_path
            <span class="hljs-keyword">if</span> export_option == <span class="hljs-string">"image_file"</span>:
                <span class="hljs-comment"># 直接嵌入图片文件</span>
                <span class="hljs-keyword">try</span>:
                    img = XLImage(info[<span class="hljs-string">"图片路径"</span>])
                    img.width = <span class="hljs-number">500</span>
                    img.height = <span class="hljs-number">300</span>
                    ws.row_dimensions[zxsq-anti-bbcode-row_idx].height = img.height
                    ws.add_image(img, <span class="hljs-string">f"A<span class="hljs-subst">{row_idx}</span>"</span>)
                    ws.column_dimensions[<span class="hljs-string">'A'</span>].width = img.width * <span class="hljs-number">0.14</span>
                <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
                    <span class="hljs-built_in">print</span>(<span class="hljs-string">f"无法插入图片 <span class="hljs-subst">{path}</span>: <span class="hljs-subst">{e}</span>"</span>)
            <span class="hljs-keyword">else</span> :
                <span class="hljs-comment"># 仅保存图片路径</span>
                ws.cell(row=row_idx, column=<span class="hljs-number">1</span>, value=info[<span class="hljs-string">"图片路径"</span>])
 
            <span class="hljs-keyword">for</span> col <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, <span class="hljs-number">9</span>):
                cell = ws.cell(row=row_idx, column=col)
                cell.alignment = Alignment(horizontal=<span class="hljs-string">'center'</span>, vertical=<span class="hljs-string">'center'</span>)
 
            row_idx += <span class="hljs-number">1</span>
            processed_count += <span class="hljs-number">1</span>
 
    <span class="hljs-keyword">for</span> col <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, <span class="hljs-number">9</span>):
        header_cell = ws.cell(row=<span class="hljs-number">1</span>, column=col)
        header_cell.alignment = Alignment(horizontal=<span class="hljs-string">'center'</span>, vertical=<span class="hljs-string">'center'</span>)
 
    output_path = <span class="hljs-string">"身份证识别结果.xlsx"</span>
    wb.save(output_path)
 
    <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>._should_terminate:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"处理已终止,已完成 <span class="hljs-subst">{processed_count}</span>/<span class="hljs-subst">{total_files}</span> 个文件,结果已保存到 <span class="hljs-subst">{output_path}</span>"</span>)
    <span class="hljs-keyword">else</span>:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"处理完成,共处理 <span class="hljs-subst">{processed_count}</span> 个文件,结果已保存到 <span class="hljs-subst">{output_path}</span>"</span>)
    <span class="hljs-comment"># 发送完成信号</span>
    <span class="hljs-variable language_">self</span>.finished_signal.emit()
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">extract_info_from_image</span>(<span class="hljs-params">self, image_path</span>):
    <span class="hljs-string">"""从图片中提取信息(优化版文本处理)"""</span>
    <span class="hljs-keyword">try</span>:
        <span class="hljs-comment"># 检查文件是否存在和可读</span>
        <span class="hljs-comment"># import os</span>
        <span class="hljs-comment"># if not os.path.exists(image_path):</span>
        <span class="hljs-comment">#     raise FileNotFoundError(f"图片文件不存在: {image_path}")</span>
        <span class="hljs-comment">#</span>
        <span class="hljs-comment"># if not os.access(image_path, os.R_OK):</span>
        <span class="hljs-comment">#     raise PermissionError(f"没有权限读取图片文件: {image_path}")</span>
        <span class="hljs-comment"># # 检查是否需要预处理身份证图片</span>
        <span class="hljs-comment"># if self.export_options.get("preprocess_id_card", True):</span>
        <span class="hljs-comment">#     processed_image_path = self.preprocess_id_card_image(image_path)</span>
        <span class="hljs-comment"># else:</span>
        <span class="hljs-comment">#     processed_image_path = image_path</span>
        <span class="hljs-comment">#</span>
        <span class="hljs-comment"># result = self.ocr.ocr(processed_image_path, cls=True)</span>
 
        result = <span class="hljs-variable language_">self</span>.ocr.ocr(image_path, cls=<span class="hljs-literal">True</span>)
 
        <span class="hljs-comment"># 1. 先整体拼接所有文本</span>
        all_text = <span class="hljs-string">""</span>
        <span class="hljs-keyword">for</span> res <span class="hljs-keyword">in</span> result:
            <span class="hljs-keyword">for</span> line <span class="hljs-keyword">in</span> res:
                text = line[zxsq-anti-bbcode-<span class="hljs-number">1</span>][zxsq-anti-bbcode-<span class="hljs-number">0</span>]
                <span class="hljs-keyword">if</span> text:
                    all_text += text
 
        <span class="hljs-comment"># 2. 去除"中华人民共和国居民身份证"标题</span>
        all_text = re.sub(<span class="hljs-string">r'中华人民共和国居民身份证'</span>, <span class="hljs-string">''</span>, all_text)
 
        <span class="hljs-comment"># 3. 去除所有空格和特殊空白字符</span>
        all_text = re.sub(<span class="hljs-string">r'\s+'</span>, <span class="hljs-string">''</span>, all_text)
 
        <span class="hljs-comment"># 4. 在关键字段前添加换行符</span>
        keywords = [<span class="hljs-string">'姓名'</span>, <span class="hljs-string">'性别'</span>, <span class="hljs-string">'民族'</span>, <span class="hljs-string">'出生'</span>, <span class="hljs-string">'住址'</span>, <span class="hljs-string">'公民身份号码'</span>, <span class="hljs-string">'签发机关'</span>, <span class="hljs-string">'有效期限'</span>]
        <span class="hljs-keyword">for</span> keyword <span class="hljs-keyword">in</span> keywords:
            all_text = re.sub(<span class="hljs-string">f'(<span class="hljs-subst">{keyword}</span>)'</span>, <span class="hljs-string">r'\n\1'</span>, all_text)
 
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"处理后的文本: <span class="hljs-subst">{all_text}</span>"</span>)
 
        <span class="hljs-comment"># 初始化提取结果</span>
        name = gender = nation = birth = address = id_number = expire = <span class="hljs-string">""</span>
 
        <span class="hljs-comment"># 提取各字段信息</span>
 
        <span class="hljs-comment"># 提取身份证号</span>
        <span class="hljs-comment"># 直接匹配17位数字+1位校验码(数字或X)</span>
        id_match = re.search(<span class="hljs-string">r'[\d]{17}[\dXx]'</span>, all_text)
        <span class="hljs-keyword">if</span> id_match:
            id_number = id_match.group().strip()
 
            <span class="hljs-comment"># 移除身份证号码干扰</span>
            all_text = all_text.replace(id_match.group(), <span class="hljs-string">''</span>)
 
        <span class="hljs-comment"># 提取姓名</span>
        name_match = re.search(<span class="hljs-string">r'姓名(.+?)(?=\n|$)'</span>, all_text)
        <span class="hljs-keyword">if</span> name_match:
            name = name_match.group(<span class="hljs-number">1</span>).strip()
 
        <span class="hljs-comment"># 提取性别</span>
        gender_match = re.search(<span class="hljs-string">r'性别(男|女)'</span>, all_text)
        <span class="hljs-keyword">if</span> gender_match:
            gender = gender_match.group(<span class="hljs-number">1</span>).strip()
 
        <span class="hljs-comment"># 提取民族</span>
        nation_match = re.search(<span class="hljs-string">r'民族(.+?)(?=\n|$)'</span>, all_text)
        <span class="hljs-keyword">if</span> nation_match:
            nation = nation_match.group(<span class="hljs-number">1</span>).strip()
 
        <span class="hljs-comment"># 提取出生日期</span>
        birth_match = re.search(<span class="hljs-string">r'出生(.+?)(?=\n|$)'</span>, all_text)
        <span class="hljs-keyword">if</span> birth_match:
            birth = birth_match.group(<span class="hljs-number">1</span>).strip()
 
        <span class="hljs-comment"># 提取住址</span>
        address_match = re.search(<span class="hljs-string">r'住址(.+?)(?=\n|$)'</span>, all_text)
        <span class="hljs-keyword">if</span> address_match:
            address = address_match.group(<span class="hljs-number">1</span>).strip()
 
        <span class="hljs-comment"># 提取有效期限</span>
        expire_match = re.search(<span class="hljs-string">r'有效期限(.+?)(?=\n|$)'</span>, all_text)
        <span class="hljs-keyword">if</span> expire_match:
            expire = expire_match.group(<span class="hljs-number">1</span>).strip()
 
        data = {
            <span class="hljs-string">"姓名"</span>: name,
            <span class="hljs-string">"性别"</span>: gender,
            <span class="hljs-string">"民族"</span>: nation,
            <span class="hljs-string">"出生日期"</span>: birth,
            <span class="hljs-string">"住址"</span>: address,
            <span class="hljs-string">"身份证号"</span>: id_number,
            <span class="hljs-string">"有效期限"</span>: expire,
            <span class="hljs-string">"图片路径"</span>: image_path
        }
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"data == <span class="hljs-subst">{data}</span>"</span>)
 
        <span class="hljs-keyword">return</span> data
 
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"处理 <span class="hljs-subst">{image_path}</span> 失败: <span class="hljs-subst">{e}</span>"</span>)
        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">should_rename_file</span>(<span class="hljs-params">self, info</span>):
    <span class="hljs-string">"""检查是否需要重命名文件"""</span>
    rename_options = <span class="hljs-variable language_">self</span>.export_options.get(<span class="hljs-string">"rename_options"</span>, [])
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">len</span>(rename_options) > <span class="hljs-number">0</span>
 
<span class="hljs-keyword">def</span> <span class="hljs-title function_">rename_file</span>(<span class="hljs-params">self, original_path, info</span>):
    <span class="hljs-string">"""根据配置重命名文件"""</span>
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-variable language_">self</span>.should_rename_file(info):
        <span class="hljs-keyword">return</span> original_path
 
    rename_options = <span class="hljs-variable language_">self</span>.export_options.get(<span class="hljs-string">"rename_options"</span>, [])
    separator = <span class="hljs-variable language_">self</span>.export_options.get(<span class="hljs-string">"separator"</span>, <span class="hljs-string">"_"</span>)
 
    <span class="hljs-comment"># 构建新的文件名部分</span>
    name_parts = []
 
    <span class="hljs-keyword">for</span> option <span class="hljs-keyword">in</span> rename_options:
        <span class="hljs-keyword">if</span> option == <span class="hljs-string">"name"</span> <span class="hljs-keyword">and</span> info.get(<span class="hljs-string">"姓名"</span>):
            name_parts.append(info[<span class="hljs-string">"姓名"</span>])
        <span class="hljs-keyword">elif</span> option == <span class="hljs-string">"id"</span> <span class="hljs-keyword">and</span> info.get(<span class="hljs-string">"身份证号"</span>):
            name_parts.append(info[<span class="hljs-string">"身份证号"</span>])
        <span class="hljs-keyword">elif</span> option == <span class="hljs-string">"nation"</span> <span class="hljs-keyword">and</span> info.get(<span class="hljs-string">"民族"</span>):
            name_parts.append(info[<span class="hljs-string">"民族"</span>])
        <span class="hljs-keyword">elif</span> option == <span class="hljs-string">"sex"</span> <span class="hljs-keyword">and</span> info.get(<span class="hljs-string">"性别"</span>):
            name_parts.append(info[<span class="hljs-string">"性别"</span>])
        <span class="hljs-keyword">elif</span> option == <span class="hljs-string">"address"</span> <span class="hljs-keyword">and</span> info.get(<span class="hljs-string">"住址"</span>):
            name_parts.append(info[<span class="hljs-string">"住址"</span>])
 
    <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> name_parts:
        <span class="hljs-keyword">return</span> original_path
 
    <span class="hljs-comment"># 构造新文件名</span>
    new_name = separator.join(name_parts)
 
    <span class="hljs-comment"># 保持原始文件扩展名</span>
    <span class="hljs-keyword">import</span> os
    dir_name = os.path.dirname(original_path)
    file_ext = os.path.splitext(original_path)[zxsq-anti-bbcode-<span class="hljs-number">1</span>]
    new_path = os.path.join(dir_name, new_name + file_ext)
 
    <span class="hljs-comment"># 重命名文件</span>
    <span class="hljs-keyword">try</span>:
        os.rename(original_path, new_path)
        <span class="hljs-keyword">return</span> new_path
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">f"重命名文件失败 <span class="hljs-subst">{original_path}</span> -> <span class="hljs-subst">{new_path}</span>: <span class="hljs-subst">{e}</span>"</span>)
        <span class="hljs-keyword">return</span> original_path
 
<span class="hljs-comment"># 图片灰度处理, 处理成扫描件, 下面还没写好 不要用</span>
<span class="hljs-comment"># def preprocess_id_card_image(self, image_path):</span>
<span class="hljs-comment">#     """对身份证图片进行校正、裁剪并转换为黑白扫描件"""</span>
<span class="hljs-comment">#     try:</span>
<span class="hljs-comment">#         # 读取图片</span>
<span class="hljs-comment">#         img = cv2.imread(image_path)</span>
<span class="hljs-comment">#         if img is None:</span>
<span class="hljs-comment">#             return image_path</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         # 1. 转换为灰度图</span>
<span class="hljs-comment">#         gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         # 2. 使用中值滤波代替高斯模糊</span>
<span class="hljs-comment">#         denoised = cv2.medianBlur(gray, 3)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         # 3. 使用自适应阈值</span>
<span class="hljs-comment">#         binary = cv2.adaptiveThreshold(</span>
<span class="hljs-comment">#             denoised, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,</span>
<span class="hljs-comment">#             cv2.THRESH_BINARY, 15, 3</span>
<span class="hljs-comment">#         )</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         # 4. 可选:轻微平滑处理</span>
<span class="hljs-comment">#         smoothed = cv2.medianBlur(binary, 1)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         # 5. 保存处理后的图片</span>
<span class="hljs-comment">#         import os</span>
<span class="hljs-comment">#         dir_name = os.path.dirname(image_path)</span>
<span class="hljs-comment">#         file_name = os.path.splitext(os.path.basename(image_path))[zxsq-anti-bbcode-0]</span>
<span class="hljs-comment">#         file_ext = os.path.splitext(image_path)[zxsq-anti-bbcode-1]</span>
<span class="hljs-comment">#         processed_path = os.path.join(dir_name, f"{file_name}_processed{file_ext}")</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         cv2.imwrite(processed_path, smoothed)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#         return processed_path</span>
<span class="hljs-comment">#     except Exception as e:</span>
<span class="hljs-comment">#         print(f"身份证图片预处理失败 {image_path}: {e}")</span>
<span class="hljs-comment">#         return image_path</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># def order_points(self, pts):</span>
<span class="hljs-comment">#     """对四个点进行排序:左上、右上、右下、左下"""</span>
<span class="hljs-comment">#     rect = np.zeros((4, 2), dtype="float32")</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     # 计算坐标和</span>
<span class="hljs-comment">#     s = pts.sum(axis=1)</span>
<span class="hljs-comment">#     rect[zxsq-anti-bbcode-0] = pts[np.argmin(s)]  # 左上角点(坐标和最小)</span>
<span class="hljs-comment">#     rect[zxsq-anti-bbcode-2] = pts[np.argmax(s)]  # 右下角点(坐标和最大)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     # 计算坐标差</span>
<span class="hljs-comment">#     diff = np.diff(pts, axis=1)</span>
<span class="hljs-comment">#     rect[zxsq-anti-bbcode-1] = pts[np.argmin(diff)]  # 右上角点(坐标差最小)</span>
<span class="hljs-comment">#     rect[zxsq-anti-bbcode-3] = pts[np.argmax(diff)]  # 左下角点(坐标差最大)</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     return rect</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># def four_point_transform(self, image, pts):</span>
<span class="hljs-comment">#     """四点透视变换"""</span>
<span class="hljs-comment">#     # 获取排序后的坐标</span>
<span class="hljs-comment">#     rect = self.order_points(pts)</span>
<span class="hljs-comment">#     (tl, tr, br, bl) = rect</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     # 计算新图像的宽度和高度</span>
<span class="hljs-comment">#     width_a = np.sqrt(((br[zxsq-anti-bbcode-0] - bl[zxsq-anti-bbcode-0]) ** 2) + ((br[zxsq-anti-bbcode-1] - bl[zxsq-anti-bbcode-1]) ** 2))</span>
<span class="hljs-comment">#     width_b = np.sqrt(((tr[zxsq-anti-bbcode-0] - tl[zxsq-anti-bbcode-0]) ** 2) + ((tr[zxsq-anti-bbcode-1] - tl[zxsq-anti-bbcode-1]) ** 2))</span>
<span class="hljs-comment">#     max_width = max(int(width_a), int(width_b))</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     height_a = np.sqrt(((tr[zxsq-anti-bbcode-0] - br[zxsq-anti-bbcode-0]) ** 2) + ((tr[zxsq-anti-bbcode-1] - br[zxsq-anti-bbcode-1]) ** 2))</span>
<span class="hljs-comment">#     height_b = np.sqrt(((tl[zxsq-anti-bbcode-0] - bl[zxsq-anti-bbcode-0]) ** 2) + ((tl[zxsq-anti-bbcode-1] - bl[zxsq-anti-bbcode-1]) ** 2))</span>
<span class="hljs-comment">#     max_height = max(int(height_a), int(height_b))</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     # 目标点</span>
<span class="hljs-comment">#     dst = np.array([</span>
<span class="hljs-comment">#         [0, 0],</span>
<span class="hljs-comment">#         [max_width - 1, 0],</span>
<span class="hljs-comment">#         [max_width - 1, max_height - 1],</span>
<span class="hljs-comment">#         [0, max_height - 1]], dtype="float32")</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     # 计算透视变换矩阵并应用</span>
<span class="hljs-comment">#     M = cv2.getPerspectiveTransform(rect, dst)</span>
<span class="hljs-comment">#     warped = cv2.warpPerspective(image, M, (max_width, max_height))</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment">#     return warped</span>
 
<span class="hljs-comment"># 中断处理, 此处不要直接中断线程, 可能导致excel未能处理完毕线程就退出了</span>
<span class="hljs-comment"># 我们应该保证excel</span>
<span class="hljs-keyword">def</span> <span class="hljs-title function_">request_termination</span>(<span class="hljs-params">self</span>):
    <span class="hljs-string">"""请求终止处理过程"""</span>
    <span class="hljs-variable language_">self</span>._should_terminate = <span class="hljs-literal">True</span></code></pre>
相关推荐
runepic8 小时前
Python 批量合并多个 Excel 数据(自动补 0 + 生成明细)
java·python·excel
hellotutu8 小时前
Java 读取 Excel 文件
java·开发语言·excel
yivifu8 小时前
Excel中Lookup函数实现临界点归入下一个等级的方法
java·前端·excel
SunnyDays10118 小时前
使用 Python 冻结、取消冻结和拆分 Excel 窗格
python·excel·冻结窗格·冻结行和列·取消冻结窗格·拆分窗格
TheNextByte18 小时前
如何将Android短信导出到CSV/TEXT/Excel
android·excel
shenweihong8 小时前
鸿蒙6开发保存Excel文件
华为·excel·harmonyos
NocoBase8 小时前
如何快速搭建一个替换 Excel 的系统?(完整指南)
数据库·低代码·开源·excel·个人开发·零代码·无代码
yivifu1 天前
快速解决Excel多行行高过小导致数据无法阅读的问题
excel
shenzhenNBA1 天前
python用openpyxl操作excel-单元格样式操作
python·excel·openpyxl·单元格样式