• 使用Python进行名片OCR(识别姓名,职务,电话,Email邮箱)


    上一篇博客介绍了如何通过以下方式自动OCR和扫描收据:

    1. 检测输入图像中的接收
    2. 应用透视变换以获得收据的自顶向下视图
    3. 利用Tesseract对收据上的文本进行OCR
    4. 使用正则表达式提取价格数据

    这篇博客将介绍如何使用Python对名片进行OCR,从名片中提取姓名、职务、电话号码和电子邮件地址。是收据扫描仪OCR的扩展,但具有不同的正则表达式和文本定位策略。
    优化:可以利用更先进的文本后处理技术,例如真正的自然语言处理(NLP natural language processing)算法,而不是正则表达式。 正则表达式可以很好地用于电子邮件地址和电话号码,但可能无法获得高精度的姓名和职务。

    1. 效果图

    原始图 VS 名片轮廓绘制绿色 效果图如下:

    在这里插入图片描述
    名片四点透视变换鸟瞰图及识别效果图如下:
    可以看到电话、姓名、邮箱、职务均被正确的识别到。
    在这里插入图片描述

    2. 原理

    pip install opencv-contrib-python

    • 了解如何检测图像中的名片
    • 将OCR应用于名片图像
    • 利用正则表达式提取:名称、职位名称、电话号码、电子邮件地址

    3. 源码

    # 加载示例名片图像(即larry_page.png和tony_stark.png),对其进行OCR,然后从名片中输出姓名、职务、电话号码和电子邮件地址。
    # USAGE
    # python ocr_business_card.py --image images/mht.jpg --debug 1
    
    
    import argparse
    import re  # Python的正则表达式库re,它将允许解析名片上的姓名、职务、电子邮件地址和电话号码
    
    import cv2
    import imutils
    import numpy as np
    import pytesseract  # pytesseract包用于与Tesseract OCR引擎接口
    # 导入必要的包
    from imutils.perspective import four_point_transform  # 四点变换函数来获得名片的自顶向下的鸟瞰图。获得该视图通常会产生更高的OCR精度。
    
    # 构建命令行参数及解析
    # --image 要ocr的名片图片,假设该图像包含一张前景和背景之间具有足够对比度的名片,确保可以成功地应用边缘检测和轮廓处理来提取名片。
    # --debug 可选,是否查看处理的每一步可视化
    # --min--conf 可选 过滤文本弱检测的置信度阈值
    ap = argparse.ArgumentParser()
    ap.add_argument("-i", "--image", required=True,
                    help="path to input image")
    ap.add_argument("-d", "--debug", type=int, default=-1,
                    help="whether or not we are visualizing each step of the pipeline")
    ap.add_argument("-c", "--min-conf", type=int, default=0,
                    help="minimum confidence value to filter weak text detection")
    args = vars(ap.parse_args())
    
    # 从磁盘加载图像,保持宽高比的缩放
    # 克隆图像,在轮廓处理后提取名片的原始高分辨率版本
    # 然后计算新宽度与旧宽度的比率(这是想要获得原始高分辨率名片的自顶向下视图时的要求)
    orig = cv2.imread(args["image"])
    image = orig.copy()
    image = imutils.resize(image, width=500)
    cv2.imshow("origin", image)
    cv2.waitKey(0)
    ratio = orig.shape[1] / float(image.shape[1])
    
    # 转换图像为灰度图,高斯平滑,应用边缘检测以使名片的外轮廓线显现出来
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blurred = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(blurred, 30, 150)
    
    # 在边缘图上进行轮廓检测,按面积进行倒序排列,获取最大的轮廓即名片
    cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]
    
    # 初始化轮廓与名片外轮廓线对应
    cardCnt = None
    
    # 遍历轮廓
    for c in cnts:
        # 轮廓近似
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
    
        # 如果轮廓有4个顶点,则近似认为它是名片轮廓
        if len(approx) == 4:
            cardCnt = approx
            break
    
    # 如果未找到名片轮廓,则抛出异常
    if cardCnt is None:
        raise Exception(("Could not find receipt outline. "
                         "Try debugging your edge detection and contour steps."))
    
    # 检查是否显示名片轮廓检测过程图
    # 检查是否处于调试模式,如果是在输出图像上绘制名片的轮廓
    if args["debug"] > 0:
        output = image.copy()
        cv2.drawContours(output, [cardCnt], -1, (0, 255, 0), 2)
        cv2.imshow("origin VS Business Card Outline", np.hstack([image, output]))
        cv2.waitKey(0)
    
    # 应用4点透视变换获取原始名片自顶向下的鸟瞰图
    # 将cardCnt乘以计算出的比率,因为cardCnt是为减少的图像维数计算的。乘以比率将cardCnt缩放回原始图像的尺寸。
    card = four_point_transform(orig, cardCnt.reshape(4, 2) * ratio)
    
    # 展示转换后的图像
    cv2.imshow("Business Card Transform", card)
    
    # 转换名片从BGR到RGB通道,并ocr
    rgb = cv2.cvtColor(card, cv2.COLOR_BGR2RGB)
    text = pytesseract.image_to_string(rgb)
    # print('ocr: ', text)
    
    # 使用正则表达式(regular expressions)解析电话号码和邮箱
    # 正则表达式可以用于匹配文本中的特定模式
    phoneNums = re.findall(r'[\+\(]?[1-9][0-9 .\-\(\)]{8,}[0-9]', text)
    emails = re.findall(r"[a-z0-9\.\-+_]+@[a-z0-9\.\-+_]+\.[a-z]+", text)
    
    # 尝试使用正则表达式(regular expressions)获取名称/标题,不一定可靠
    nameExp = r"^[\w'\-,.][^0-9_!¡?÷?¿/\\+=@#$%ˆ&*(){}|~<>;:[\]]{2,}"
    names = re.findall(nameExp, text)
    
    # 显示电话号码
    print("PHONE NUMBERS")
    print("=============")
    
    # 遍历检测到的号码并输出
    for num in phoneNums:
        print(num.strip())
    
    # 显示邮箱地址头
    print("\n")
    print("EMAILS")
    print("======")
    
    # 遍历检测到的email地址
    for email in emails:
        print(email.strip())
    
    # 展示姓名/职务
    print("\n")
    print("NAME/JOB TITLE")
    print("==============")
    
    # 遍历姓名/职务并显示在屏幕上
    for name in names:
        print(name.strip())
    
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    参考

  • 相关阅读:
    FT2004(D2000)开发实战之PBF配置
    【云原生】阿里云容器镜像服务产品
    循环问答机,存储txt
    Spring Boot 检索&定时任务
    Linux系统下安装RabbitMQ超简单教程(非详细)(Centos8)
    c++ 二分查找
    Docker数据卷&&自定义Docker镜像
    通过百度翻译API完成Java中的中英文翻译
    Open CASCADE学习|为什么由Edge生成Wire不成功?
    Etcd 常用命令与备份恢复
  • 原文地址:https://blog.csdn.net/qq_40985985/article/details/125681523