スランプグラフ画像の歪を補正する方法
お世話になっております、スログラミングです。
今回はひさしぶりにpythonでプログラミングしようと思ってます。
遊技機の大型化。個人的にはエヴァとか牙狼みたいに動作するなら許せる派ですが、私の好みの話はどうでも良いので一旦おいておくとして、そういう機種でスランプグラフを撮ろうとすると、
こうなりません?
この状態だと、スランプグラフから千円Sを計算したりするときにちょっとめんどくさかったりします。
(そもそも目視でも見辛いですし。)
そこで今回は、斜めから撮影したスランプグラフを真っすぐに戻す方法について説明したいと思います。
本日のアジェンダはこちら。
1. 透視変換とは?
目次で答えが先バレしちゃってますが、斜めから撮影したスランプグラフを真っすぐに戻すには、透視変換を使います。
射影変換というのもあるらしいですが、違いはよくわかってません。
そこら辺の説明は頭の良い方にお任せするとして、斜めに撮った状態のまま千円Sを算出するとどうなってしまうかを考えてみましょう。
他にも方法はあるかもしれませんが、基本的には1pixあたりの出玉数を計算することで、千円Sを算出すると思います。
例えば、冒頭で貼り付けた画像の場合、グラフの左端は0~10000玉までのサイズが522pixなのに対して、右端は384pixとなっています。
この場合、1pixあたりの出玉数は、
・左端:10000[玉] / 522[pix] = 19.16[玉/pix]
・右端:10000[玉] / 384[pix] = 26.04[玉/pix]
となるので、左端で求めた1pixあたりの出玉数を使って、右端の出玉数を算出したりするとおかしな値となってしまいます。
(1pixあたり5玉ずつずれていく。)
左端の出玉数は左端で求めた1pixあたりの出玉数を使って、右端の出玉数は右端で求めた1pixあたりの出玉数を使う、とかすれば問題はありませんが、それだと面倒ですよね。
そこで、透視変換を使ってスランプグラフを真っすぐに戻すことで、左端の出玉数も右端の出玉数も左端で求めた1pixあたりの出玉数を使う、といったことができるようになります。
2. 透視変換のプログラミング
プログラミングは画像処理ライブラリのOpenCVを使えば簡単です。
getPerspectiveTransformと、warpPerspectiveという2つの関数を使います。
関数としては、
①変換前の画像のグラフの四隅の座標
②変換後の画像のグラフの四隅の座標
③変換後の画像サイズ
の3項目の値が必要ですが、今回の目標的には①さえわかればOKです。
早速順番にやっていきましょう。
2.1. ライブラリのインポート
まずは、ライブラリのインポートから。
# 使うライブラリをインポート import cv2 import numpy as np
2.2. 変換したい画像を読み込む
次に変換したい画像を読み込みます。
(画像の場所は適当に変更してください。)
# 変換したい画像を読み込む image = cv2.imread(r"D:\Test\fig1.jpeg", cv2.IMREAD_COLOR)
2.3. 変換前の画像のグラフの四隅の座標を設定
次に、先程記載した①変換前の画像のグラフの四隅の座標を設定します。
座標はペイント等で確認して、皆様のお持ちの画像の値を入れてください。
※関数には、左上→左下→右下→右上の順に座標を渡す必要があるので、順番に注意です。
(list形式のままだとうまくいかないので、numpy形式に変換することも忘れずに。)
# 変換前のグラフの四隅の座標を入力 lt = [993, 1593] # 左上の座標 lb = [981, 3573] # 左下の座標 rb = [2585, 3181] # 右下の座標 rt = [2593, 1701] # 右上の座標 before_points = np.float32([lt, lb, rb, rt])
2.3. 変換後の画像のグラフの四隅の座標&画像サイズを設定
次に②変換後の画像のグラフの四隅の座標を設定するわけですが、①の座標から適当に計算で設定していきます。
今回はスランプグラフを正面から見た画像、すなわち長方形にしたいので、変換後の画像の横幅と縦幅、すなわち③の変換後の画像サイズがわかれば長方形の座標が設定できます。
横幅と縦幅も適当で良いですが、あまりに元の画像から変わってしまうと見辛くなるので、元の画像の横幅と縦幅を求めて使用しておきます。
# 変換後のグラフの四隅の座標を設定 w = abs(rt[0] - lt[0]) # 変換後のグラフの横幅 h = abs(lb[1] - lt[1]) # 変換後のグラフの縦幅 after_points = np.float32([[0, 0], [0, h], [w, h], [w, 0]])
2.4. 透視変換の実行
これで①~③がわかったので、後は透視変換の関数を使った後で画像を保存すれば終わりです。
# 透視変換を実行 pt_matrix = cv2.getPerspectiveTransform(before_points, after_points) after_image = cv2.warpPerspective(image, pt_matrix, (w, h)) # 画像を保存 cv2.imwrite(r"D:\Test\fig1_aft.jpeg", after_image)
3. 今回作成したコード
今回作成したコードを貼り付けておきます。
# coding: UTF-8 # 使うライブラリをインポート import cv2 import numpy as np # 変換したい画像を読み込む image = cv2.imread(r"D:\Test\fig1.jpeg", cv2.IMREAD_COLOR) # 変換前のグラフの四隅の座標を設定 lt = [993, 1593] # 左上の座標 lb = [981, 3573] # 左下の座標 rb = [2585, 3181] # 右下の座標 rt = [2593, 1701] # 右上の座標 before_points = np.float32([lt, lb, rb, rt]) # 変換後のグラフの四隅の座標を設定 w = abs(rt[0] - lt[0]) # 変換後のグラフの横幅 h = abs(lb[1] - lt[1]) # 変換後のグラフの縦幅 after_points = np.float32([[0, 0], [0, h], [w, h], [w, 0]]) # 透視変換を実行 pt_matrix = cv2.getPerspectiveTransform(before_points, after_points) after_image = cv2.warpPerspective(image, pt_matrix, (w, h)) # 画像を保存 cv2.imwrite(r"D:\Test\fig1_aft.jpeg", after_image)
4. まとめ
今回作成したコードを使用するとこんな感じになると思います。
無事に斜めから撮影したスランプグラフが真っすぐになっていますね。
ちなみに言うまでもないかもしれませんが、変換後のグラフのサイズを固定にしたいなら、wとhを元のグラフサイズからの計算で出すのではなく、適当な値を指定してあげればOKです。
(正方形ならwが100pixで、hも100pixとか。)
コメント
コメントを投稿