今回は、画像の射影変換をやってみたいと思います。
射影変換
春のパン祭り得点集計では、射影変換が活用できそうなのでやってみます。
射影変換が何をやっているかは前に勉強していたのですが、完全に忘れた…
また復習して記事にします。
ひとまず、ある視点から見た画像を、別の視点から見た画像に変換する、というものです。
シール台紙を撮影するとき、多少斜めからの撮影になるので、これを正面からの画像に変換します。
画像の幾何変換 — OpenCV-Python Tutorials 1 documentation
以下の画像を使いました。
>>> img1 = cv2.imread('harupan_210402_1.jpg') >>> img2 = cv2.imread('harupan_210402_2.jpg') >>> h,w = img1.shape[:2] >>> img1 = cv2.resize(img1, (int(w/10), int(h/10)), interpolation=cv2.INTER_AREA) >>> img2 = cv2.resize(img2, (int(w/10), int(h/10)), interpolation=cv2.INTER_AREA) >>> cv2.imshow('image1', img1) >>> cv2.waitKey(0) 13 >>> cv2.destroyAllWindows() >>> cv2.imshow('image2', img2) >>> cv2.waitKey(0) 13
射影変換で正面から見た画像に変換したいと思いますが、それには
- 元画像での4点の座標
- この4つの点の変換先座標
を指定する必要があります。
元画像の点としてシール台紙の4つの角を指定、変換先の座標としては長方形の4点を指定します。
元画像でのシール台紙の角は、手動で探します。ImageJを使いました。カーソルを当てた位置の座標を表示してくれます。
最終的には自動検出するようにしたい。
1枚目 : (774,702), (444,3222), (2664,3282), (2394,762)
2枚目 : (978,978), (570,2934), (2190,3138), (2304,918)
※元画像はいずれも横3024pixel、縦4032pixelです。
縦横1/10にした画像で変換を行います。
長方形の4点を指定するためには縦横比が必要なので、実際に測ります。
16.0cm x 11.0cmでした。
正しく射影変換するためには、画像に既知の形状の物体が映っていないとだめということですね。
変換実施
射影変換やってみました。
変換先画像は、320×220の解像度にしました。
>>> import numpy as np >>> >>> pts1_org = np.float32([[77,70],[44,322],[266,328],[239,76]]) >>> pts1_dst = np.float32(([[0,0],[0,160],[110,160],[110,0]])) >>> M = cv2.getPerspectiveTransform(pts1_org, pts1_dst*2) >>> img1_dst = cv2.warpPerspective(img1,M,(110*2,160*2)) >>> cv2.imshow('image1_dst', img1_dst) >>> cv2.waitKey(0) 13 >>> cv2.destroyAllWindows() >>> pts2_org = np.float32([[98,98],[57,293],[219,314],[230,92]]) >>> pts2_dst = np.float32(([[0,0],[0,160],[110,160],[110,0]])) >>> M = cv2.getPerspectiveTransform(pts2_org, pts2_dst*2) >>> img2_dst = cv2.warpPerspective(img2,M,(110*2,160*2)) >>> cv2.imshow('image2_dst', img2_dst) >>> cv2.waitKey(0)
- およそそれらしく変換できたかと。お手軽ですね。
- シール台紙の角が少しめくれあがっていて、変換結果が引き伸ばされたようなちょっと微妙な感じに。
- とは言えシール点数計算には十分な結果では?
ここまで
フィルタ処理をやろうと考えていましたが、OpenCVチュートリアルを見ると先に「幾何変換」の内容が来ていて、今回射影変換をやりました。