2013年12月10日火曜日

Javaによる画像入出力プログラム

ちょっとWindowsの画面をキャプチャする機能が欲しくなったんで、調べてみたんですが、、、、いろんな関数があって大変(;゜ロ゜)
手動でやれば簡単なんですが、枚数があるもんですからプログラムと思ったんですけどね。しばし考えて、「Javaにも同じような機能あるんじゃない?」調べたらありました。しかも非常に簡単です。

キャプチャ自体は以下の関数になります。

// 指定領域をキャプチャしてスクリーンショットのBufferedImageを返す createScreenCapture(Rectangle screenRect);

それで簡単に画面の一部(左上の512x512)をファイルに保存するものを作ってみました。

import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class test {

 /**
  * @param args
  */
 public static void main(String[] args) {

  // スクリーンキャプチャのテスト
  Robot r =null;
  try {
   r = new Robot();
  } catch (Exception e){
   System.out.println("can't get Robot");
  }

  BufferedImage dd = r.createScreenCapture(new Rectangle(0, 0, 512, 512));

  // jpgで保存
  try {
   File savedImage = new File("sss.jpg");
   ImageIO.write(dd, "jpg", savedImage);
  } catch (Exception e) {
   System.out.println("can't write file");
  }

 }

}

このプログラムはファイルを作成するだけですが、読み込むときは以下の通りになります。

BufferedImage img = ImageIO.read(File);

後は、BufferedImageで適当に調べればpixel単位の操作も簡単にできます。


PS:
あ、念のためいっときますが、これはローカルでjavaを動かして自分のPCの画面をキャプチャしたい目的で調べました。(ですからローカルに画像ファイルを保存しちゃってますし)リモートでこれ実行したらどうなるんでしょうねえ?セキュリティにひっかかるかな。(それにBufferedImageデータをどうやって返信するんだという問題がありますが。取得したイメージデータを返信する方法がなければゲームなんかで使えるテクニックなんですが。)

Nexus7 KitKat更新

少し前にNexus7のOSが4.4(KitKat)に更新されました。最初は、動きがいい、電池の持ちがよくなったと喜んでいたんですが、どうも動作におかしなところが目立つようになってきました。


  1. 画面の回転が遅い。センサへの問い合わせをアプリごとにするんじゃなくOS側でまとめてやるようにして、電力消費を減らしたとはききましたが、アプリによっては中々回転したのを反応してくれないものがでてきました。
  2. WiFiがなかなかつながらない。これは家が1階、2階と別々の親機を設置しているせいもあるかもしれませんが、電源On直後などなかなかWiFiを認識してくれないことがあります。
  3. WiFiの接続キーを忘れる。これが一番困ります。WPSで簡単に接続設定はできますが、何らかの関係でWiFiのAPリストから消えると、接続キーも忘れてしまうようです。数回設定しなおしました。

昨夜、VerUpの連絡が来ていました。(4.4.2へ更新です)セキュリティ強化が主眼のようですが、使いがってはどうでしょう。

2013年12月2日月曜日

3Dモデルの表示がしたい:WebGL編

少し前までAndroidでのOpenGLプログラムやら、Blenderからのモデル出力を調べていました。目的は3Dモデルを表示するのに楽な方法は現状だとなんだろうと試行錯誤していたわけです。
昔はc++なんかでガリガリViewerプログラムをInventorなんかつかったりして作っていたんです。Inventor自体は好きなんですが、肝心のSGIがどうもダメダメ(今ではGraphicsは完全に撤退して、スーパーコンピューティングの会社になってしまってます。唯一Graphicsの部門をNECに売却して日本SGIとして細々とやっているくらいですか。。。)で、Inventorを使い続けるのに不安をずっと感じていたんです。仕事でやるならもう自分でViewerは作りません、できあいの製品かってきます。その方が安心です。

ただそれでもどうしても特注のカスタマイズしたViewerが欲しい場合どうしたらいいか?と考えて、様子を見てたんですが、どうも結局OpenGLでガリガリ書くのが時流のような気がします。それでまあ、特注で必要になるとすると今時のタブレット用アプリくらいかとAndroidを見てたんですが、やはりOpenGLをガリガリするのは疲れます。何より、モデルデータの読み込みを自分で用意しないといけないのがしんどいです。そこでモデルデータ作成にBlenderを調べて、今度はモデルデータのエクスポートから表示方法を考えていました。
実は前から気になっていた技術に「WebGL」があります。JavaにもOpenGLの実装がありますが、それをブラウザのJavaScriptでやってしまおうというものです。可能性を非常に感じていたんですがいかんせん「重い!」に当時はつきました。ブラウザを使うPC性能(正確にはGraphicsボードの性能になります)に依存しますし、それでも素でアプリから動かすより数倍重く感じました。(昔々、SGIが同じような考えでVRMLというのを考えてましたが、結局今じゃ聞かなくなってしまいましたね)その後、セキュリティ上の問題がJavaScriptおよびWebGLの両方に見つかり、一時停滞したようですが、また最近記事がでるようになり、JavaScript用のライブラリもScene.jsとかThree.jsとかさかんにでてくるようになりました。ところで現状WebGLが使えるのは、以下のブラウザだけとのことです。

  • Chrome
  • FireFox
  • Safari
  • Opera(機能限定らしい)
  • IE11(やっとMSも実装したらしいけど、どの程度の実力かは不明)


そんなところで、ChromeとFireFoxを使いながらThree.jsで様子を見てみることにしました。(理由は、BlenderからモデルデータをThree.jsが読み込める形式にする方法があるから)ところがこれが非常に難航しました。まずWebの記事のようにThree.jsが動かない。(表示がおかしい)これの原因究明にかなり時間がかかりましたが、大体わかってきたのでメモしておきます。(利用したブラウザはChromeとFireFoxです)

1.簡単なサンプルしか表示されない
簡単な立方体を表示するJavaScriptのプログラムは問題なく動きました。

ところが、これにjpegのテクスチャを張ろうとすると、、、
何コレ?っていう感じですが、本当は以下の様に表示される(予定)ものです。
(これはその後、試行錯誤の結果表示できるようになったものです)
球体に、地球表面のjpegを用意してそれをテクスチャとして貼り付けているはず、なんですがうまくいきません。

2.ChromeとFireFoxで挙動が違う
上記の地球のサンプルですが、実はFireFoxだとうまく表示できるんです。Chromeはだめ。ブラウザの開発コンソールを見ても特にエラーは返してこないし、なんでだ!?と悩みましたが、確かJavaScriptのセキュリティ問題で、ローカルなファイルはJavaScriptでは読めないようにしたのを思い出しました。(IEは、今更そんな制限つけれるかという感じのようですが)FireFoxも緩いようですが、テクスチャとしての読み込みだけは許可してくれたようです。(注:WebGLはさらにメモリリークの問題も発生していたため、Chromeではテクスチャデータだろうがローカルからの読み込みを禁止しているんでしょうね)

Three.jsのサンプルにテクスチャを貼ったものがありますが、Chromeだと全滅ですね。FireFoxじゃないとローカルな環境ではまともに表示してくれません。

3.Blenderのモデルデータを読み込んでくれない
さあここまでくれば問題はあきらかです。肝心のBlenderのモデルデータファイルを読みこもうとするとChromeやらの開発コンソールに明確に、ローカルファイルは読み込めませんといってきます。(正確にはローカルなファイルを指定するfile://というURLでは不正と判断され、http経由じゃなきゃだめ、みたいな感じ)
これにはまいりました。Webで見つかった記事には一言もそんなこと書いていてくれません。あきらめてLinuxマシンにapache2をインストールしましたよ。(設定はデフォルトのまま。特に外部のPCから見たいわけではないんで。URLはhttp:://localhostで参照できれば十分です。)そうしたら無事表示されました。(基本、ローカルでしか使いません。ローカルなファイル見るのにapache経由というのも変な感じがしますが、そうしないとセキュリティをクリアできない!)
何表示してるの?って感じですが、まずBlenderでモデル作成したとき、XYZ軸の+方向がどう表示されるのか確認しないといけなかったので、Blenderで四角すいを3つ、XYZ軸(RGB)方向に作成した(ついでに各四角すいはそれぞれの軸の色にしてあります)モデルデータを表示してみたものです。(下図のモデルを出力したものです)

WebGLには軸表示としてHelperを使っています。なんかX軸(R)で90度回転してますね・・・
ところで、Three.jsのGitHubにあるエクスポートスクリプト(python)はBlender2.66用です。自分は現状最新の2.69を使っており、これが表示されない原因かとも一時思いました。しかし、結果的にはBlender2.66だろうが、2.69だろうがエクスポートされるファイル(JSON形式です)は同じものでした。Blenderを両方インストールして確認してみました。モデルがもっと複雑になると違ってくるかもしれませんが。

3.5 Blenderモデルのエクスポートオプション
上述の結果は、Blenderにてthree.js用にモデルデータをエクスポートするさい、デフォルト設定で行ったものです。改めてオプションを見てみたら、座標軸を変換するオプションがありました。
下部の「Flip YZ」がデフォルトではオンになっていますが、これをオフにして出力してみると、以下のようになりました。
XYZ(RGB)軸がきちんと同じ方向に表示されるようになりました。しかし、なんでこんなオプションがあるんだか…


色々試行錯誤して、「Blnederで作成したモデルデータをWebGLで表示する」という目的は達成できました。ついでにかなりまだクセが強いのも理解できましたが。(最後のモデルが回転してしまう、というのはよくある話なんで、理解できてればそんなに苦にはなりません。)

結局、Three.jsに多数格納されているexampleですが、テクスチャ関係使っているものはFireFoxでないとローカル環境だけでは見れません。apache動かして、http経由で見ればChromeでも見ることができます。(逆にいうと、これ気づかないと大多数の人が「Three.jsってこんな表現しかできないのか」と勘違いしてしまいそうです。