ShuuLog

ShuuLog

2022年07月18日
XML
カテゴリ: AIの勉強
写真から画像の一部を認識し切り抜くという処理を作りたくて、とりあえず、その一部を認識させる方法を考えてみたいと思います。

今回プログラムの作成及び実行に利用した環境はWindows標準環境(Microsoft StoreよりダウンロードインストールされるPython)を利用しています。(執筆時のバージョンは3.10.5)
OpenCVは上記バージョンのpipにてインストールされるバージョンを利用しています。

今回、挑戦するのは名刺。

スマホのカメラで撮影された名刺画像から背景などの余分な箇所を除き、名刺だけにしたい。
とまぁ、言葉でするのも、人の判断でするのも特に難しくない作業です。

最近の名刺管理アプリケーション(Eightなど)はAIを利用して、名刺を認識しているようですが、いかんせん、まだまだ勉強不足。

とりあえず、画像をごにょごにょすることでどうにか精度を上げていきたい。

名刺の写真ってことで大きな問題になってくるのが、背景と名刺の境界線のところです。


あと、背景なのか名刺のデザインなのか?っていう判断も難しそうです。

ただ、全部を最初からできるわけでもないので、最も簡単な画像を試してみたいと思います。
背景が濃い色で名刺が白のパターンですね。


緑の背景に白色の名刺を置いています。
この画像をもとに以下のプログラムで加工してみます。
import cv2

# イメージファイル読込
img = cv2 . imread ( 'meishi.jpeg' ,)
#グレースケール
wkimg = cv2 . cvtColor ( img , cv2 . COLOR_BGR2GRAY )
# エッジの抽出
wkimg = cv2 . Canny ( image =wk img , threshold1 = 100 , threshold2 = 130 )
# 結果書き込み
wkimg = cv2 . imwrite ( 'meishi_Result.jpeg' , img )



このように、名刺の縁のみを抽出してくれます。

次に、この画像から四角形の箇所を認識させる処理を追加してみます。
まず、結果の画像をよく見ると、二重線になっている箇所がありますので、それらを結合します。
その後、輪郭線の抽出のために「findContours」を利用するのですが、そのためには二値画像が必要となります。
二値画像とは単純にいうと白黒の画像です。その画像を得るために、「threshold」を利用します。
thresholdは閾値を設定して、二値画像を得るわけですが、実際本当にシステムとして認識させるためには、その閾値の設定が難しくなります。写真の明るさや名刺の色、背景の色によって最適な閾値が変わるため、非常に厄介です。この二値画像の作成に関しては再度検証して別途記事にしたいと思います。


import numpy as np

# エッジの結合
wkimg = cv2 . morphologyEx ( wkimg , cv2 . MORPH_CLOSE , np.ones(( 5 , 5 ), dtype = wkimg .dtype))

# 二値画像の生成
ret , thresh1 = cv2 . threshold ( wkimg , 127 , 255 , cv2 . THRESH_BINARY )

# 結果書き込み
cv2 . imwrite ( 'meishi_Result2.jpeg' , thresh1 )




それでは、いよいよ輪郭線の抽出と輪郭線に基づいた描画を行っていきます。
輪郭線の抽出は「findContours」を使ってやっていきます。
この関数で、輪郭線の位置情報が配列として取得できます。取得した位置情報をもとに線を描画するわけですが、描画する際にあまりにも小さなオブジェクトはノイズである可能性が高いため、そちらを除いていたりします。この辺の閾値も実際のプログラムになると値の設定が悩ましいものになります。

この辺の詳しい内容については私もまだ理解できていないので、参考にしたサイト様をいかに貼り付けております。

参考にしたサイト


# 輪郭線の抽出
contours , hierarchy = cv2 . findContours ( thresh1 , cv2 . RETR_LIST , cv2 . CHAIN_APPROX_NONE )

for i in range ( 0 , len ( contours )):
if len ( contours [ i ]) > 0 :

# remove small objects
if cv2 . contourArea ( contours [ i ]) < 500 :
continue

rect = contours [ i ]
x , y , w , h = cv2 . boundingRect ( rect )
cv2 . rectangle ( img , ( x , y ), ( x + w , y + h ), ( 0 , 0 , 255 ), 10 )

# 結果書き込み
cv2 . imwrite ( 'meishi_Result3.jpeg' , img )

結果、このように検出した画像の周りに赤線で枠を描画することができました。


ただ、このやりかただと、名刺の配置が若干斜めになったりすると以下のようになってしまいます。


なので、描画する箇所のプログラムをちょっといじってみます。
この辺の情報もネットを調べれば何個か出てきますので、そちらを参考にします。

参考サイト

# 輪郭線の抽出
contours , hierarchy = cv2 . findContours ( thresh1 , cv2 . RETR_LIST , cv2 . CHAIN_APPROX_NONE )

for i in range ( 0 , len ( contours )):
if len ( contours [ i ]) > 0 :

# remove small objects
if cv2 . contourArea ( contours [ i ]) < 500 :
continue

cv2 . polylines ( img , contours [ i ], True , ( 0 , 0 , 255 ), 10 )

# 結果書き込み
cv2 . imwrite ( 'meishi_Result3.jpeg' , img )


rectangleからpolylinesに変更しています。
rectangleは長方形を描画する関数ですので、前述のとおり、検知された画像が丸々入る長方形を描画しています。
しかし、polylinesは頂点をつなぐ線を描画するため、各頂点から頂点への描画となり、以下のような画像になります。


一旦は、必要な情報(名刺の枠を認識し座標情報を取得する)はできました。

しかし、記事の中にあるように、各種閾値については現状固定で指定しており、今回のサンプル写真であればうまくいきますが、背景が緑ではなく黄色だったら?とか、模様がついていたら?とかなっていくと、閾値の最適化を動的に行う必要が出てくると思います。

また、白の背景に白の名刺の場合などは特に閾値が難しくなるかと思います。

次回以降、その辺の各種閾値なや光、影の影響なども併せて検討して改良していきたいと思います。

※当プログラムは各種サイト様の情報を参考にしております。勝手ながらリンクを張らさせて頂いておりますので、問題があるようでしたらコメントに記載いただければリンクを削除いたします。





お気に入りの記事を「いいね!」で応援しよう

最終更新日  2022年07月18日 11時35分29秒
コメント(0) | コメントを書く
[AIの勉強] カテゴリの最新記事


【毎日開催】
15記事にいいね!で1ポイント
10秒滞在
いいね! -- / --
おめでとうございます!
ミッションを達成しました。
※「ポイントを獲得する」ボタンを押すと広告が表示されます。
x
X

PR

プロフィール

ShuuLog

ShuuLog

カレンダー


© Rakuten Group, Inc.
X
Design a Mobile Website
スマートフォン版を閲覧 | PC版を閲覧
Share by: