2018年4月6日金曜日

OpenCV で星座検出(5) - 探索の効率化

2カ月ぶりの更新になりますが、ここ最近は星座検出部の改良をばりばり進めておりました。
GitHub 上でコードを見られます: https://github.com/takasa5/stardust
進行度についてメモを残しておきます。


1. クラス化

最初からやっておけよという話ではありますが、しっかりクラスとして書き直してだいぶコードも見やすくできました。
GitHub からインストールすればだれでも以下のようにして試すことができます。

from stardust import Stardust
import Constellation

# 入力画像のパス(or ndarray化した画像)で初期化
sd = Stardust("./input.jpg")
# 検出したい星座を指定
cs = Constellation.Sagittarius() # いて座
# 星座線を引く(あれば)
sd.draw_line(cs.get())
# 画像を返す
ret = sd.get_image()
# cv2.imshow()なり cv2.imwrite()なりする

クラスの構造については経験の量が響くところだと思うので、改善点は多々あると思います。気づき次第よくしていきたいところです。

2. 検出の効率化

OpenCV で星座検出(1)の4で、距離(前の星と基準の星との2つ)と角度を用いて近くの星について計算していく手法をとっていました。この明らかにダメそうな手法は3-1.未検出部の描画において足を引っ張るので、かねてから改善を画策していました。
ダメな理由を挙げると
  1. 周囲の星から近いものを探すので、時間がかかる
  2. 次の星が"周囲"になかった場合検出に失敗してしまう
  3. 検出した星ありきなので検出失敗時に予想することができない
 という点です。これはよくないですね~!!!!!
データが存在するのに照合しかできず予想ができない」と要約できるでしょうか。

というわけで、ベクトルを装って平面幾何に終始していた前手法から、ベクトルの世界へと旅立っていきましょう。
手順としては次の通りです:

 ① 角度データをもとに、2×2回転行列を生成
 ② 前のベクトルを入力として①で回転し、長さデータをもとに拡大
 ③ 前のベクトルと②で生成したベクトルの和が予想される次の星になる
 ④ ③に一番近い星を探す(OpenCV で星座検出(1)の3を参照)
 ⑤ 予測との誤差を計算し、採用/非採用を決める

問題点2、3は解決です(わかるでしょうか)。また、実行時間も大幅に短縮することができました。どの画像に対しても3秒程度で探索が終了します

3. 描画機能の強化

3-1. 未検出部の描画

ベクトルによる探索に切り替えたことにより、未検出部を予測して線を描くことができるようになりました。
星座左上、右下部
星座下部
 見つけられない場合は円を描かずに線のみ描くようにしました。

3-2. はみだし部の補完

星座がはみだしていても、おそらくこの方向に線が引けるだろうというのは予想できるはずです。
ベクトルによる次点予測を利用し、画像の4辺のどこからはみ出ているのかを判断し、そこまで適切な角度で線を引く関数を実装しました。
また、その後も探索を続行できるので、途中だけはみ出たりしていても描画することができます。
いいはみだし例の画像が検索から拾ってきたものしかなく版権的に怪しいので省略します。

4. 今後

星座データにさそり座を追加し、現状いて座とさそり座の二つになりました(ペルセウス座は星座データ強化用の追加画像データを探し中…)。

これに関して、いて座とさそり座は隣り合っているのでその位置関係が検出に貢献してくれるはずです(人間はそういうふうに探したりするはず)。ただ現状はひとつずつ一から探しているだけなので、そこを改善したいです。
高速化も進んだので、webサービスとしての公開も近い…かもしれません。

0 件のコメント:

コメントを投稿