批量识别身份证并导出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>
相关推荐
CircleMouse3 小时前
如何设置wps单元格下拉选项设置
excel·wps
zhangjin12228 小时前
kettle插件-excel插件,kettle读取excel动态表头,kettle根据列名读取excel
excel·kettle·kettle excel插件·kettle 动态excel
远洪1 天前
excel 找出两列不同的数据
excel
pcplayer1 天前
非常好用的 Excel 读写控件
excel·delphi·office
Navicat中国1 天前
使用 Navicat 导入向导导入 Excel 数据时,系统提示导入成功,表中也能看到数据,但行数统计显示为 0,这是什么原因?
数据库·excel·导入
穿着内裤的外星人1 天前
触控精灵远程读写Excel步骤配置
excel
是孑然呀1 天前
【小记】excel vlookup一对多(第二篇)
excel
开开心心就好1 天前
专为视障人士设计的免费辅助工具
windows·计算机视觉·计算机外设·excel·散列表·推荐算法·csdn开发云
transformer_WSZ1 天前
excel两列数据绘制折线图
excel·折线图
蒋胜山2 天前
Excel 练习题(5)
经验分享·excel