個人的な趣味で、AKB48の中国上海姉妹グループのSNH48メンバーが、中国ツイッター(新浪微博)にアップしている画像のうち、自撮りと思われる画像だけを選別し、ローカルの特定のフォルダーにいったん集め、特定のサーバにFTPでアップロードするという、世の中の何の役にも立たない実に下らないことを、二週間に一回くらい手作業でやっていた。
中国ツイッター(新浪微博)からメンバーがアップした画像を一括ダウンロードする処理は、中国ツイッター(新浪微博)のOAuth APIがどうやっても上手く行かないので(単に筆者の技術力がないだけ)、Google Chromeの拡張機能として作成した。
そうすると、Google Chromeで新浪微博にログインした状態で実行すれば、本来OAuth APIでやるべきユーザ認証の部分を省略できるからだ。
ただ、拡張機能のJavaScript内部で、新浪微博のサーバ上にある画像ファイルを、ローカルの任意のフォルダに自動で直接ダウンロードすることはできない。そんなことができてしまったら、任意のサーバ上にマルウェアを置いておいて、Google Chromeの拡張機能でこっそりそのマルウェアを世の中のPCにバラまくことができてしまうからだ。
なので、拡張機能からコンソールログに、新浪微博のサーバ上にある画像へのURLを書き出すようにした。
そして、やや回りくどいけれど、そのコンソールログをローカルの任意のフォルダに保存する。
そしてそのコンソールログに含まれる画像ファイルのURLを次々読み込んでは、ローカルの特定のフォルダに、特定の命名規則にしたがったファイル名に変換してダウンロードするという処理を、PHPで書いた。
その結果、今まで1枚、1枚、手作業の左クリックでローカルのフォルダに画像ファイルをダウンロードするという作業が、途中の「コンソールログを左クリックしてローカルの特定のフォルダに保存する」という一か所以外、すべて自動化された。
これで作業時間は、おそらく90%以上削減された。
SNH48メンバーの人数は、最初の頃は20人前後だったので、手作業でもじゅうぶん追いつけたけれど、今や100人を超えている。
しかも全員がほぼ毎日ツイートし、各ツイートには最多で9枚の画像を添付できる。もはや手作業では不可能になっていた。
しかしここまで自動化すると新たな問題が出てくる。
今までは、自撮り画像かどうかを、1枚、1枚、手作業の左クリックで保存するときに、自分の人間の目で判断できた。
ところが、100名以上の2週間分の画像を一括で自動ダウンロードできるようになると、2,000枚を超える画像をまとめて1枚ずつ、自撮りかどうか目視でチェックして選り分ける必要が出てくる。
これを黙々とやっていると、機械的な作業がイヤじゃない筆者でも、さすがに飽きてくる。
なので、人間が自撮りかどうか判別する前に、いったんコンピュータの「顔認識」で、明らかに顔が写っていない画像、たとえば風景を写した画像などを除外することができないか、と考え始めた。
もちろんコンピュータの「顔認識」は、人間がやる顔認識に比べれば精度にそれほど高くない。本来含めるべき画像を捨ててしまったり、含めるべきでない画像を入れてしまったりするかもしれない。
でもそこはあきらめるとして、とにかく少しでも作業を効率化するために「顔認識」で事前の選別をやらせようと思い立った。
そこでインターネットをいろいろ調べると、OpenCVというオープンソースの顔認識APIの存在を見つけた。
ところが運の悪いことに、筆者が自宅のPCのバッチ処理に愛用しているWindows版のPHP用のextensionにそのままつかえるDLLが存在しない。(このあたりはUnix系OSのスキルがない筆者のような技術者の弱点)
かと言って、Web APIとして公開されている顔認識APIを使うと、画像1枚ごとにWeb APIを呼び出して、JSON形式の分析結果を受取ることになるので、処理時間が異常に長くなるのはやる前から分かる。
そこで、やむなくOpenCVを使うためだけに、新たにプログラミング言語のPythonを覚えることにした。幸い入門書はインターネット上で無料で手に入った。
Pythonは、筆者がほぼ習得済みのWindows PowerShellと同じく変数がすべてオブジェクトということなので、理解はしやすかった。(じっさいには逆で、変数がすべてオブジェクトであるPythonを真似して、Windows PowerShellも変数がすべてオブジェクトになったのだろうけれど)
Pythonの「改行に意味がある」という仕様には少し慣れないが、言語として洗練されているので、すぐに大まかな文法は理解できた。
そこで次の問題は、開発環境だ。
PHPなら経験年数が長いので、もうテキストエディタだけでもコーディングはできるけれど、Pythonは独習しはじめたばかりなので、文法チェックくらいはリアルタイムでやってくれる一般的な開発環境が欲しい。
それでなくても頭の中ですでに、Visual Basic、Windows PowerShell、PHP、JavaScript、swift 2.0、そして今回新たに独習しはじめたPythonなど、いろんなプログラミング言語がごっちゃになり始めているので。
そこでWinPythonというとっても便利なWindows用のPythonの統合開発環境を見つけたのだが、「待てよ」と思った。
WinPythonに慣れてしまうと、Python開発しかできなくなってしまう。たしかMicrosoft Visual StudioでもPython開発ができたはずだ。
そう思って調べてみると、思った通りVisual Studio 2015 Community Edition(無償版)でも、ちゃんとPython開発ができるらしいことが分かった。
そこで久しぶりにVisual Studio 2015 Community Editionのインストーラーを実行すると、ちゃんとオプションでPythonが選択できるようになっているではないか。(今までPythonを書く必要性がなかったので気づかなかっただけだけれど)
そしてPython 2.7のWindows 64ビット版をインストールした後、Visual Studio 2015 Community EditionでPython開発のオプションをONにして再設定し、Python用の環境設定(python.exeやpythonw.exeへのパスを通したりすること)をしてやると、ちゃんとPython開発ができるようになった。
ただ、その前にWinPythonをいったんインストールして、アンインストールしたせいか、実行するとnumpyモジュール内部でエラーが発生する。
これについてはインターネットでいろいろ調べた結果、WindowsのMS-DOSプロンプトを立ち上げて、「pip install numpy」を実行してPythonのnumpyモジュールを再インストールすることで解決した。
ただ、Python 2.7用のOpenCVの拡張モジュールのcv2.pydファイルを、Pythonのインストールフォルダ配下のLib配下のsite-packages直下に正しくコピーしても、Visual Studioのコードエディタでcv2モジュールのIntelliSense(各オブジェクトのメンバー名やメソッド名を自動的に入力補完してくれる機能)が有効にならない。
これもネットをいろいろ調べてが、どうやらVisual StudioでPython 2.7用のOpenCVモジュールを使う場合、IntelliSenseが有効にならないのは、Visual Studioの仕様上の制限らしい。
なのでこれは仕方ないと諦めた。Pythonの標準的なモジュールについては、ちゃんとIntelliSenseがメンバー名やメソッド名を選択肢として自動表示してくれるし、自動補完もしてくれ、それだけで十分に助かる。
結果、めでたく数千枚の画像について、一気にOpenCVの顔認識機能で顔が写っていると思われる画像だけを、前もって選り分けて別フォルダにコピーするという自動処理Pythonプログラムの開発に成功した。
といっても、今朝思い立ってから、のべ数時間で実現できたので、そんなに苦労したわけではない。
しかし、どうやらOpenCVの顔認識はかなりチューニングが必要なようだ。
今のところ、インターネットで拾った数値ほぼそのまま流用させて頂いて、以下のように適当にパラメータを設定している。
cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(240,240))
ところがこれでは、人間が見ると明らかに顔でないものが顔だと認識されている。
例えばこんな感じ。
えっ?この白い枠の中がOpenCVの上のパラメータ設定からすると、顔だと認識されてしまうわけですね。
もちろん上手く行っている画像もある。
こんな変顔をしてても、ちゃんと顔だと認識してくれてる。しかし…
このオレンジのどこが顔なんだろうか…とか。
つまり残る課題は、OpenCVのパラメータをどうチューニングすれば、できるだけ人間の顔だけを拾ってくれるようになるかだ。
今のままでは、例えば2,000枚チェックしなきゃいけないのが、せいぜい1,500枚くらいにしか絞り込めない。
どこまで自動化の道を追求できるか…。
じつに下らないことに時間をかけているということは、よく分かっているけれど、おかげでPythonのバッチ処理を普通に書けるようになるので、今後仕事にも使えないことはない。
そうやって、趣味でも何でも利用して、仕事のためになるスキルを増やしていくのであった。