マエカワの開発日記~2017年 夏~ 後編
注意
この記事は2017年の夏季休業期間でマエカワが実際にしてきた勉強に関して書いていこうといった趣旨のものです。前編を読んでいない方は、ぜひそちらにも足を運んでいただきたい所存でございます。リンクはこちら。
maekawa-yoshimiki-1119.hatenablog.com
それでは、後半の内容、書いていきます。
画像処理技術
OpenCVについて
今回、webカメラから取得した画像を解析、加工して、ユーザに見えるデータとして提供しようといった目的のもと、webアプリケーション開発などを頑張ってきました。画像取得から加工までのプロセスはJAVAを用いたOpenCVで実現しようと考え、公式サイトからダウンロード&インストール。この際、次の書籍を参考書として購入しました。
- 作者: 北山直洋,北山洋幸
- 出版社/メーカー: カットシステム
- 発売日: 2016/10/01
- メディア: 単行本
- この商品を含むブログを見る
まずは、実際にOpenCVで画像処理部分を書いていった感想から。
もともとJAVAベースの画像処理は、「ビジュアル情報処理」っていう講義でprocessingを使っていたので、一応触ったことがあるくらいの認識でいました。しかし、OpenCVのコードを見てみると、やっぱり難しい。前回書いたサーブレット関連よりかはまだ優しいほうなんですが、未知の世界であることには変わりありませんでした。ただ、一回書いてしまえばクラスとして後々使いまわせるもの(例えば、画像をグレースケールに変換してから画素値を比較するとか)が多かったので、進んで行けば行くほど楽にコードを書くことができました。なので、自分の中では「書いてて楽しい」といった感じです。
あと購入した参考書なんですが、やっぱりネット上には載っていない(載っていたとしてもちんぷんかんぷんな)ことがわかりやすく書いてあったので、買ってよかったと思っています。ただ、動体検出の手法まで載っていたにしても本当に基礎の部分だったので、一回理解してしまうと次から参照しなくなり、少しもったいないなぁといった感は否めません。決して安いものではないので…。参考書なんて買いたくないといった人のために、一応OpenCVのJAVAドキュメントのリンクを載せておきます(Generated Documentation (Untitled))。ただ、いきなりこれを見てもどのように活用したらいいかわからないと思います。そういうときはC#なりPythonのコードが書いてあるサイトを見て、「あぁ、Coreはこういうとき使うんだなぁ…Imgprocはここで使うのかぁ」と照らし合わせながらコードを書いていくしかないでしょう。自分はそれが煩わしかったんで、参考書に逃げました。自力でドキュメントを読み解くか、参考書というチートアイテムを使って読み解くかは人によってさまざまでしょうが、参考書に頼りきりで、ドキュメントを読もうとしないと力がつかないのは明白です。そうならないように、参考書で補完できない部分については頑張ってドキュメントと他サイトを駆使してコードを書いたりしてます。
つまづいたところ
さて、今回つまづいたところについて前回同様書いていこうかと思います。全部で3つ。
1つ目はeclipseへの外部API追加。これについては、プロジェクトのプロパティ(プロジェクトを右クリックしたら一番下に出てきます)に"\opencv\build\java"の中にあるopencv-ooo.jarを追加することで解決することができます。
2つ目がNATIVE_LIBRALYの追加。これができていないとOpenCVを使うことができません。おそらく、プロパティのJRE System Librakyといったところに"Native libraly location"というものがあるので、それを編集。自分のPCのシステムに合わせて、"\opencv\build\java"の中にある"x64"か"x86"フォルダへパスを通します。mainメソッドの書き始めを
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
にしたら準備完了。OpenCVを動かすことができます。
3つ目は画素値を取る際の注意点。OpenCVでは、Matのgetメソッドで画素値をdoubleとして配列に格納することができます(グレースケールの場合は一つ、カラーの時はBGRの3値が配列に入ります)。実際に次の「取得画像の色をネガティブにして保存する」コードを組んで動かしてみます。
public static void main(String[] args){ System.LoadLibraly(Core.NATIVE_LIBRALY_NAME); int w; //width int h; //height Mat img=Imgcodecs.imread("画像のパス"); double[] data=new double[3]; //データ格納用 for(int j=0;j<h;j++){ for(int i=0;i<w;i++){ data=img.get(i,j); //ここで取得できるのはBGRの値 data[0]=255-data[0]; //blue data[1]=255-data[1]; //green data[2]=255-data[2]; //red } } Imgcodecs.imwrite("保存先のパス"); }
こんな感じでしょうか?しかし、これでは10行目の
data=img.get(i,j);
でNullPointerExceptionが出てしまいます。
これにはかなり時間を割かれましたが、原因が明らかに。実はgetメソッドの引数の順番を入れ替えれば正常に実行されます。自分はてっきり
Mat.get(width,height);
だと思い込んでいたんですが、実際は
Mat.get(height,width);
だったようです。なんだか気持ち悪い感じ。これに気が付いた時は「こんなの罠だろ…」とつぶやいていました。
ということで、
public static void main(String[] args){ System.LoadLibraly(Core.NATIVE_LIBRALY_NAME); int w; //width int h; //height Mat img=Imgcodecs.imread("画像のパス"); double[] data=new double[3]; //データ格納用 for(int j=0;j<w;j++){ for(int i=0;i<h;i++){ data=img.get(i,j); //ここで取得できるのはBGRの値 data[0]=255-data[0]; //blue data[1]=255-data[1]; //green data[2]=255-data[2]; //red } } Imgcodecs.imwrite("保存先のパス"); }
これで動きます(get(j,i)にするのは気持ち悪かったんで、wとhの位置を変えています)。
とまぁ、こんな感じでざっくりとつまづいたところになります。
最後に
少し長くなってしまった感がありますが、これでマエカワが夏季休業期間に行ったメインの勉強内容になります。大きく分けて2つですが、どちらの内容も中身が濃く、充実した休暇にできたと実感しています。受講した講義がきっかけだったとはいえ、なかなか自分の力になったのではないかと思います。
そして、もう一つ実感したことが、「大学の講義だけじゃ、この先不安じゃない??」といった焦り。これまで、のほほんとC、JAVA、Python、Schemeなどのコードを書いては「難しいなぁ…何の役に立つんだろう…」と思っていただけの自分がいました。今回、サービス提供者側としてwebアプリケーションなり、画像処理などを触ってみて初めて「あぁ、こんな便利なツールがあるんだ…こうやってサーバは構築されてるんだ…Python超楽じゃん…jsp使えないじゃん…」と感じ、考えることができました。これは、講義を受けてるだけでは得ることができなかったものだと思います。
これから先、情報系出身というステータスだけでは社会を生き抜くことは困難になってきます。プログラミングやそのほかの情報分野は年々重要視され、小学生のカリキュラムにもプログラミングを導入することが決定しています。プログラミングスキルがコモディティ化する未来もそう遠くない。そういった意味でも、のほほんと、漠然と講義を受けている状態に焦りを覚えています。
ま、かたい話はこれくらいにしましょう。ダラダラ書いててもしょうがないんで、次勉強する(したい)ことについて書いて締めようと思います。一つ目はPHP。jspで作ったwebアプリケーションの書き換えを第一目標として頑張っていこうと思います。二つ目は人工知能。何やらPythonで書くことができるらしいので、頑張ってみようかと。流行っているからには一回くらい触っとかないと。長いものは巻いときたい。三つ目はandroidアプリケーション。今回勉強したことが役に立ちそうなんで、自分にとってのお役立ちアプリなんかを自分のために作ってみようかなぁと思っております。ゆっくりでもいいから確実に、自分のものにしていきたいですね。
では、長かったですが今回の特集はこれにて終了。ここまで読んでくださった方、ありがとうございました。
マエカワ