##シェルスクリプトで画像の昼夜の判断ができないか? →ImageMagick使ってできた!!
###目次
- はじめに
- まずは ImageMagick をインストール
- ImageMagick のコマンドとオプション
- identify のリターン値で画像の暗さを判断する
- おわりに
##はじめに
前に記事にした
ラズパイで画像をGoogleDriveにアップロードするならrclone一択じゃね?という話
https://qiita.com/ElecCPinAAII/items/19f1757e89bc06535d98
で書いたように、タイムラプス作成用の画像をラズパイで撮影しているのですが、
画像撮影をcronで朝の5時から夜の8時まで15分置きに走らせる設定にしているので、
タイムラプスにした時に真っ黒けな夜の動画部分ができちゃってました。
日の長さによって定期的にcronを走らせる時間をずらしていけばいいんですが、ダルいですしね。
タイムラプス作成時に黒い画像だけ手で消していくのもダルいし。
####なんとか楽したい。
最初に考えたのは、今はタイムラプスの作成をシェルコマンドで動かしているけど、
Pythonで組み直して、そこに画像認識処理をかませるってことですが、
なんせシェルコマンドだって全然わからないのに、
Pythonをイチから学ぶのはてーへんだ。
それにシェルの方が圧倒的に短くコンパクトにいくのは前回で調査済み。
そこでいろいろ探していたら ImageMagick っていうソフト?があるらしーじゃないですか。
なんでもコマンドラインから画像をあーだのこーだのできるらしい。
くんくん、これはなんだか使えそうな気配がしますよ!!!
でもどんな感じで使えるのかわからん。
とりま入れてみるべ!!!
##まずはImageMagickをインストール
brew いれてたんで、早かったっす(いや時間は不安になるくらいかかったけど)
$brew install imagemagick
もう永遠とも思えるほど時間がかかりましたけど、
なんだかインストールできたっぽい。
なんのエラーも出なくてらっき。
書くことがない。
##ImageMagickのコマンドとオプション
さてこの ImageMagick ってすごーくいろんなことが画像に対してできるみたいだけど、
今回やりたいのは
####画像が暗いか明るいかを判断したいだけ。
つまり画像の情報が欲しいだけなので、
ImageMagick のコマンドである identify これがお目当のお仕事をしてくれそうです。
↓こちらのサイト↓を参考にさせていただきました。
ImageMagick コマンドリファレンス
http://image-magick.com/2014/09/27/identify/
さらに -verbose というオプションが画像のありとあらゆる情報を引っ張り出すらしい。
さーて動くかな。
とりあえずコマンドラインで試してみます。
$identify -verbose test.jpg
すると、ずらずらずら〜〜〜〜って情報が出るんですが、何がなんだか。
そこで、昼間の画像と真っ暗な夜の画像の両方の情報を出してみて、
比べてみました。
ほぼほぼおんなじなんですが、mean っていう情報があってですね、
その値が暗い画像と明るい画像では違うっぽい。
#夜の画像の情報の一部
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 4.40014 (0.0172554)
standard deviation: 15.6713 (0.0614561)
kurtosis: 139.093
skewness: 10.6346
entropy: 0.367111
#昼の画像の情報の一部
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 139.746 (0.548022)
standard deviation: 74.29 (0.291333)
kurtosis: -1.25547
skewness: 0.424975
entropy: 0.736811
でもこの情報のリターン値をどうやってひろうのよ、、、とほほ、
と思って、さらに調べていくと
↓こんなサイトをみっけ。
ImageMagick - 2枚の画像を比較!
https://www.mk-mode.com/blog/2013/09/04/imagemagick-compare-two-images/#
これによると
$ identify -format "%[mean]" target.jpg
↑これでAverage value statistic of image(画像の平均値)が 0(黒)〜65535(白) という値で返って来るそうだ!!
やった!
出口が見えたぞ!!
##identifyのリターン値で画像の暗さを判断する
いくつぐらいの値が帰って来るか全然想像つかないので、
とりあえず手持ちの昼の画像と夜の画像でテスト。
↑夜の画像は 1130.84
↑昼の画像は 35914.6
ほかにもいくつかの暗い画像で試した結果、
値が 15000 以下の画像は暗すぎると判断した。
あーとは、if文で判断すれば簡単じゃん!?
しかしシェルコマンドを知っている人にとっては当たり前かもしれないけど、
ifの条件に「>」とか「<」使えないってどゆこと!?
さらにリターン値が小数点以下桁数不定の小数点だったのも落とし穴でした。
シェル、小数点使えないって、なんなん。
ぜーんぜん上手くいかなくて、
あちこちのサイトを漁ってひねりだしたのが↓
# $fはファイル名
flag=`identify -format "%[mean]" "$f"`
if [ ${flag%.*} -gt 15000 ] ; then
....
あんまりあちこち参照しすぎて、利用させてもらったサイトの参照元がわからなくなってしまいました。
(お世話になったサイト様たち、ありがとうございました)
そして今となっては自分でも、この「 flag%.* 」ってなんだろうな。。。ってなってます。
もしこれを見て、この意味がわかる人がいたらコメントで教えてください(真剣)
(2020/6/24 追記)
職場の神様の1人から上記「%」の件につき解説いただきました。
% っていうのは文字列を後ろから指定した条件のところまで削除するっていう呪文らしいですね。
ここでは小数点の . を指定しているので、小数点以下の文字列を消すという役割をしています。
(そーいや、参考にしたサイトにも小数点以下を取り去る的な解説があったのを思い出した)
ということで、この「 flag%.* 」という呪文を日本語に訳すと
< flag にはいっている文字列のおしりから、指定した「 . 」までの文字列をなんであろうと(*)削除したまえ>
って意味だったんですね。
ただこの「 * 」で表現する「なんであろうと」の部分、じゃあ他には何が指定できるの?ってところまではまだわかりません。
アルファベットだけ消すとか数字だけ消すとか、そんな使い方ができるのかな?
情弱あるあるで、私が検索してもちっともこの辺の情報が出てこないんですけど!!
##おわりに
ま、他にもトラブルはあったけど、今回の画像判断には関係がないから書きません。
とにもかくにも、こうしてめでたく暗い画像なしのずーっと昼間のタイムラプス画像の出来上がり。
Pythonとか使わなくても画像が取り扱えるのはちょー便利と思ったので、
Qiitaにシェアさせてもらいます。
わずかにでも誰かのお役に立つことを願って。
それにしてもシェルの変数の参照方法もろくに知らない私がぼちぼちできるんだから、
####ネットの知識共有って素晴らしい。
今回リモートワークで職場にいる神々に全然会えなかったので、
ネット上のオリンポス山におわしまする様々な神々に本当に助けられました。
ここに感謝申し上げまする〜〜