まいにち右往左往

日記です。興味の範囲がバラバラで統一性がない日記です。だんだん備忘録っぽくなってきました。

Pythonで雪が降ってたらLINEに通知を出してみる その2 特徴点による比較

 

 

halwind.hatenablog.com

 

年が明け、だいぶ時間がたってしまいましたが、年明け早々に雪が降りましたので、前回の続きで特徴点マッチングを試していきます。当初の方針は、雪のない夜の写真と一時間ごとに更新される写真とで特徴点による比較をし、雪が積もれば差異が大きくなるので、それを検知してラインに通知を送るというものです。

 

 

基本的にはOpenCVを利用しました。
参考にさせていただいたサイトはこのあたりです。 

qiita.com

 

www.cellstat.net

 

labs.eecs.tottori-u.ac.jp

 

qiita.com

 

ここで当初から方向転換がありまして、一度雪が降ると通知が止まらなくなってしまい、うるさいことになってしまいました。

ですので、一時間前に取得した写真との比較をメインにしていきたいと思います。一時時間前と差が大きい写真が取れた場合に、ラインに通知を送ります。

 

ここで、事前に画像処理をかけたほうが検出の頻度が上がるのではないかと考え、いくつかの処理を試し、それぞれの結果をまとめてみました。

 

値が小さいほど画像の類似度が高く、値が高いほど画像がの類似度はひくくなります。マッチングのアルゴリズムはAKAZEを使用しています。
一時間前との比較なので、17時は16時との差異を表しています。

 

時間 無変換 グレースケール コントラスト調整 エッジ抽出
17:00 88 89 105 108
18:00 130 130 127 110
19:00 26 27 28 112
20:00 26 27 34 113
21:00 29 30 37 115
22:00 39 39 45 114
23:00 44 44 53 114
0:00 48 48 59 115
1:00 28 28 31 114
2:00 46 45 46 114
3:00 99 99 97 112
4:00 80 80 82 112
5:00 94 94 95 112
6:00 71 71 78 113
7:00 121 121 127 127
8:00 49 49 66 108

 

この日は、2時から朝6時まで雪が降り続きました。表の赤字の部分です。その前提で考えると、画像処理をしない「無変換」でのマッチングがけっこういけてる気がします。まあ夜間はほぼ色がない写真となっているわけで、実質グレースケールとほぼ同じですが。

18時と朝7時で値が高くなっているのは、日が沈んで暗くなった時間と、日が昇って明るくなった時間です。こう考えると、やはり通知は夜だけに絞ったほうが精度が上がりそうです。

それから、上記のサイトを参考に明るさを正規化した画像を使って特徴点を計算した時に、検出できずにdivision zeroのエラーが良く出ました。この辺りはもとの画像に由来するのかもしれませんが(夜の写真なので正規化するとコントラストも弱くのっぺりした画像になってしまう)、他で使う時のためにちょっと覚えておこう。

  

無変換での写真の移り変わりと、特徴点の差を示すとこんな感じです。あ、今回の写真はあくまで例です。

 

時間 17:00
1時間前との差異 88 

明るいせいで、細かいところまで見れるので、雪が降っていなくても一時間前と違いを検出しやすくなっているんじゃないでしょうか。

f:id:halnwind:20190220124013j:plain

 

時間 18:00
1時間前との差異 130

まあ目で見ても、暗くなったため細部が見えなくなってますし、差が大きいのがわかります。

f:id:halnwind:20190220124931j:plain

 

以降3時まであまり変化がありません。

 

時間 3:00
1時間前との差異 99

雪がうっすらつもり出しました。雪のせいで全体的に白っぽくなり、違いを検出できているようです。

f:id:halnwind:20190220125044j:plain

 

こんな感じで、大体70くらいを閾値にすればいいんじゃなかろうか、ってことで実際に運用しているコードが次のものになります。画像の前処理をいろいろ試したときのコードはまた別の記事にしよう。ともかく、これで二つの画像の特徴点間の距離=差異の度合い、が出力される訳です。この理解であっているか、自信はないけど。

あとはもう少し雪が降れば、試行錯誤して精度を上げられそうなんですが、今年は雪が少ないですねー。

  

import cv2

#Twitterからダウンロードした写真を指定 imgFile = 'picnow.jpg'
#1時間前にダウンロードしたpicnow.jpgを比較用にbasepic.jpgとしてコピー shutil.copy('picnow.jpg','basepic.jpg') shutil.copy(imgFile,'basepic.jpg')
#1回目のブログで書いた写真ダウンロードを実行
downloadPic(getMediaURL())

def judge(): baseFile = basepic.jpg' #Twitterからダウンロードしたファイルの変換後ファイル comparingFile = imgFile bf = cv2.BFMatcher(cv2.NORM_HAMMING) #コメントアウトによって比較に使用するライブラリ切り替え detector = cv2.AKAZE_create() #detector = cv2.ORB_create() #detector = cv2.BRISK_create() baseFile = cv2.imread(baseFile,0) (target_kp, target_des) = detector.detectAndCompute(baseFile, None) compFile = cv2.imread(comparingFile,0) (comparing_kp, comparing_des) = detector.detectAndCompute(compFile, None) matches = bf.match(target_des, comparing_des) dist = [m.distance for m in matches] ret = sum(dist) / len(dist) return(ret)
print(judge())