Cloud Vision APIを利用してOCRを使ってみました。日本語でもかなりの精度に驚いています。
ただし文章とみなされる部分に関しては文字列として判断されますが、空白が空いていたりすると文章として取得できないケースもあります。
そんな時には位置情報から取得する内容を作ることで、ブロックごとのデータ取得ができます。
コード
import io from google.cloud import vision import xml.etree.ElementTree as ET def read_ocr(input_file): client = vision.ImageAnnotatorClient() with io.open(input_file, 'rb') as image_file: content = image_file.read() image = vision.Image(content=content) response = client.document_text_detection(image=image) return response def card_template(input_xml): tree = ET.parse(input_xml) # input_xmlはxmlのパス root = tree.getroot() return root def card_analytics(response, card_template, height): size = card_template.find("./size") ratio = 1.0 org_heigit = int(size.find('height').text) if org_heigit > 0 and height > 0: ratio = height / org_heigit # テンプレートマッチング text_infos = [] document = response.full_text_annotation for page in document.pages: for block in page.blocks: for paragraph in block.paragraphs: for word in paragraph.words: for symbol in word.symbols: bounding_box = symbol.bounding_box xmin = bounding_box.vertices[0].x ymin = bounding_box.vertices[0].y xmax = bounding_box.vertices[2].x ymax = bounding_box.vertices[2].y xcenter = (xmin + xmax) / 2 ycenter = (ymin + ymax) / 2 text = symbol.text text_block += symbol.text text_infos.append([text, xcenter, ycenter]) result_dict = {} for obj in card_template.findall("./object"): name = obj.find('name').text xmin = obj.find('bndbox').find('xmin').text ymin = obj.find('bndbox').find('ymin').text xmax = obj.find('bndbox').find('xmax').text ymax = obj.find('bndbox').find('ymax').text xmin, ymin, xmax, ymax = int(xmin), int(ymin), int(xmax), int(ymax) ymin = int(ymin * ratio) ymax = int(ymax * ratio) texts = '' for text_info in text_infos: text = text_info[0] xcenter = text_info[1] ycenter = text_info[2] if xmin <= xcenter <= xmax and ymin <= ycenter <= ymax: texts += text result_dict[name] = texts return result_dict response = gcp_read.read_ocr("sample.jpg") # テンプレートを取得 card_template = gcp_read.card_template("card.xml") result = gcp_read.card_analytics(response, card_template, 640)
<annotation> <folder>Downloads</folder> <filename>card.jpg</filename> <path>/</path> <source> <database>Unknown</database> </source> <size> <width>1000</width> <height>640</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <name>name</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>110</xmin> <ymin>35</ymin> <xmax>610</xmax> <ymax>95</ymax> </bndbox> </object> <object> <name>birthday</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>610</xmin> <ymin>35</ymin> <xmax>950</xmax> <ymax>95</ymax> </bndbox> </object> </annotation>
xmlでテンプレートを作成し、テンプレートデータに合わせた内容を取得することができます。
テンプレート通りのサイズがとれるかわからないため画像をリサイズしたい工夫が必要ですが、決まっているレイアウトの場合にユースケースとして考えることができます。
まとめ
参考にしたサイトを忘れてしまったので、掲載できていませんが、参考にしたサイトはあります。
いろんなパターンをやると戦略の幅が広がるので、思いついた時に試すのはいいですね。