お客様との打ち合わせや展示会に参加すると必ず交換される「名刺」ですが、SFAやCRMで管理するために、貰った名刺をデータ化する必要があります。今では、名刺読み取り専用のスキャナーやスマートフォンアプリが販売されており、名刺を簡単にデータ化できますが、そういったツールを持たなければ手入力で名刺の内容を打ち込まなければなりません。
それこそ、数百枚単位で名刺が交換される展示会の後では、名刺のデータ化だけで結構な時間をとられてしまうことも多いのではないでしょうか。
この悩みをCognitive ServicesのOCR機能で解決してみたいと思います。
名刺読み取りのアルゴリズム
名刺は各社でフォーマットが異なり、氏名、会社名等の配置が異なるため、読み取りは難しいようにも見えますが、名刺を見ていると一定の法則性があることがわかります。
・名刺の法則性
| 項目 | ||
| 会社名 | 会社名の行にはほぼ「会社」の単語が入る。(「株式会社」、「有限会社」等) | |
| 氏名 | フォントサイズは「企業ロゴ」、「氏名」、「会社名」の順で大きい傾向にあり、行の高さ上位3位には「氏名」が入る | |
| 電話番号 | 行に「Tel」、「Phone」、「電話」、「直通」のいずれかが入っている | |
| Fax番号 | 行に「Fax」の単語が必ず入る。 電話番号とFax番号は同じ行になることが多いが、Fax番号が電話番号より前に記載されることはない |
|
| 住所 | ほとんどの場合で、都道府県名が入る。 入らない場合も県庁所在地など、一目で都道府県がわかるものが多い。 | |
| 必ず「@」が入る。 | ||
| URL | 「http」、「www」のいずれかは必ず入る |
Computer Vision APIのOCR機能では、行単位とテキストと、テキストエリアの大きさを取得できるため、名刺の各行について法則性に基づいたデータ抽出を行えば、必要な情報を取得できると考えられます。
名刺読み取り機能の作成
上述の法則性を基に名刺読み取りのスクリプトを作成してみました。
基本的に画像から読み取ったテキスト行に特定の単語が含まれるかどうかを判定するだけのため、Computer Vision APIのレスポンス形式がわかっていれば1日もかからず作成できてしまいます。
(Computer Vision APIについては 「Cognitive Services: OCR機能で印刷物の写真からテキストのデータ化をしてみる」もご参考ください )
都道府県、県庁所在地を取得するための「prefecture.json」も単に都道府県名と県庁所在地名をJSON形式の配列で保存しているだけで、簡単に作成できます。
・sample.py
#!/usr/bin/env python
#coding:utf-8
import requests
import json
import re
def ocr(img_url, lang = "unk"):
Computer Vision API 設定
url = "https://southeastasia.api.cognitive.microsoft.com/vision/v1.0/ocr" # エンドポイント
api_key = "********" # APIキー
リクエスト本文
body = {
'url': img_url
}
リクエストヘッダ
headers = {
Request headers
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': api_key
}
リクエストパラメータ
params = {
Request parameters
'language': lang,
'detectOrientation ': 'true'
}
リクエスト
res = requests.request("POST", url, headers=headers, json = body, params= params)
return res.json()
def main():
検索文字列設定 ###
都道府県、県庁所在地取得 (外部jsonファイル)
with open("./prefecture.json", "r") as f:
pref = [p.encode("utf-8") for p in json.load(f)]
対象と検索値の設定
search_words = {
"company": ["会社"],
"mail": ["@", "@"],
"tel": ["tel", "phone", "電話", "直通"],
"fax": ["fax"],
"address": pref,
"url": ["http", "www"]
}
OCRテキスト読み取り ###
名刺画像URL
img_url = "https://*****"
OCR実行
resdata = ocr(imgurl, lang = "ja")
各行のテキスト、高さ抽出
lines = [
{
"height": max([int(word["boundingBox"].split(",")[3]) for word in line['words']]),
"text": "".join([word["text"] for word in line['words']])
}
for regi, region in enumerate(resdata['regions'])
for line_i, line in enumerate(region['lines'])
]
名刺画像内のデータ抽出 ###
data = {}
for i, line in enumerate(lines):
設定検索条件に基づいてデータを検索、抽出
for key, words in search_words.items():
if data.get(key) == None:
data.update({key: ""})
word_match = re.search("|".join(words).decode("utf-8"), line["text"].lower())
if word_match and data[key] == "":
data[key] = line["text"]
data.update({"metadata" + str(i): line["text"]})
TelとFaxが1行になっているものを分割して格納
if data["tel"].lower().find("fax") >= 0:
tel_arr = data["tel"].lower().split("fax")
data["tel"] = tel_arr[0]
data["fax"] = tel_arr[1]
氏名の抽出 ###
行高さの上位数の設定
height_top = 3
行高さの上位
namelist = sorted(lines, key=lambda x: x["height"], reverse=True)[:heighttop]
明確に氏名でない項目の削除
not_name = [val for key, val in data.items() if key.find("metadata")
・prefecture.json
[
"北海道",
"札幌市",
中略 ####
"沖縄県",
"那覇市"
]
上記コードで、以下のサンプルの名刺画像から情報を取得してみました。
"沖縄県",
"那覇市"
]
上記コードで、以下のサンプルの名刺画像から情報を取得してみました。
・入力画像
部分的にハイフンが長音記号になっているところがありますが、簡単な手直しで済み、1枚2秒程度で処理できるため、手入力に比べてはるかに効率的にデータ化ができそうです。
・読み取り結果
| name0 | 田中太郎 |
| name1 | 節owled |
| name2 | ommunrcatton |
| fax | .047-700-5005 |
| tel | tel.047ー397ー8897 |
| url | http//www.knowledgecommunication.jp |
| company | 株式会社ナレッジコミュニケーション |
| address | 〒272ー0143千葉県市川市相之川3ー13ー23丸伝小川ビル3F |
| E-mail:t-tanaka@knowledgecommunication.jp |
今回は、Computer Vision APIのOCR機能を使用して名刺読み取りプログラムを作成してみましたが、簡単なスクリプトでも案外良好に名刺のデータ化をすることができました。
サンプルでは、名刺の画像で試していますが、いくつか実際の名刺の写真で試してみても同様にデータ化ができており、完全ではないにせよデータ入力のサポートになるものには仕上がっているように思いました。
今回は名刺でしたが、フォーマットや規則さえ分かっていれば他の紙ベースの文書にも適応できるので、ぜひ試してみてください。
次回もお楽しみに。