はじめに
OpenCVを使ったパターンマッチングで画像中の物体抽出 with Python
上記の記事を作成するにあたりOpenCVについて調べてみると、本当にいろいろなことができるみたいなので、とりあえず思いついたことを試してみることにしました。
...ということで、名刺をカメラで撮影した画像を正面から撮影したかのように補正する「射影変換」の手順を以下にまとめます。
動作環境
項目 | 内容 |
---|---|
マシン | MacBook Air (13-inch, Early 2015) |
プロセッサ | 2.2 GHz Intel Core i7 |
メモリ | 8 GB 1600 MHz DDR3 |
Python | 3.6.0 :: Anaconda 4.3.1 (x86_64) |
Jupyter Notebook | 4.2.1 |
OpenCV | 3.3.0-rc |
環境構築手順
いつもの手前味噌ですが、以下のURLをご参照下さい。
使用した写真
自分の名刺の裏側をiPhoneのカメラで撮影したものを使用します。(IMG_4778.JPG)
ライブラリ読込
import cv2
import numpy as np
from IPython.display import display, Image
def display_cv_image(image, format='.png'):
decoded_bytes = cv2.imencode(format, image)[1].tobytes()
display(Image(data=decoded_bytes))
画像読込
img = cv2.imread("IMG_4778.JPG")
display_cv_image(img)
色の二値化と輪郭抽出
# グレイスケール化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二値化
ret,th1 = cv2.threshold(gray,200,255,cv2.THRESH_BINARY)
display_cv_image(th1)
二値化した結果は以下のとおりです。
# 輪郭抽出
image, contours, hierarchy = cv2.findContours(th1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 面積の大きいもののみ選別
areas = []
for cnt in contours:
area = cv2.contourArea(cnt)
if area > 10000:
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
areas.append(approx)
cv2.drawContours(img,areas,-1,(0,255,0),3)
display_cv_image(img)
正しく輪郭が抽出され、赤い枠で囲むことができました。
射影変換
枠の各点を対応する座標にあわせて射影変換します。
img = cv2.imread("IMG_4778.JPG")
dst = []
pts1 = np.float32(areas[0])
pts2 = np.float32([[600,300],[600,0],[0,0],[0,300]])
M = cv2.getPerspectiveTransform(pts1,pts2)
dst = cv2.warpPerspective(img,M,(600,300))
display_cv_image(dst)
変換した結果は以下のとおり。
できた!
おまけ
tesseract-ocrというライブラリを使用して、認識した名刺の文字をORCしてみました。
上述のソースコードに続けて以下のコードを追記します。
import pyocr
from PIL import Image
tools = pyocr.get_available_tools()
tool = tools[0]
print(tool.image_to_string(Image.fromarray(dst), lang="jpn"))
結果は...
〔保有賓格】
ヽ/寸 トゥェア開莞技術肴
惰報せ‡ュ‥ティ7ド
第三種電氣主任枝術者
乙穫鷺4顆危礦鞠取扱着
空手初段
二ス 卜 レ一タ
...改善の余地ありですね(汗)