2013年5月30日木曜日

Tomcat Servletを簡単に使う

windowsでやったけど、Linuxでも同じだと思う。

■tomcatのcore版

http://tomcat.apache.org/download-70.cgi


適当なディレクトリに変更した後、

単体で動作するためには、
インストールディレクトリを環境変数CATALINA_HOMEとして登録。
binをPATHに追加。
JAVA_HOMEに使用するJDKを指定する。

その後、コマンドラインからstartup.batをたたくと、起動する。

以下のような標準出力があり、tomcat用のウィンドウが起動します。
ウィンドウにServer startup in ~msと出たらOKです。

Using CATALINA_BASE:   "C:\apache-tomcat\apache-tomcat-7.0.40"
Using CATALINA_HOME:   "C:\apache-tomcat\apache-tomcat-7.0.40"
Using CATALINA_TMPDIR: "C:\apache-tomcat\apache-tomcat-7.0.40\temp"
Using JRE_HOME:        "C:\Java\jdk1.7.0_07"
Using CLASSPATH:       "C:\apache-tomcat\apache-tomcat-7.0.40\bin\bootstrap.jar;
C:\apache-tomcat\apache-tomcat-7.0.40\bin\tomcat-juli.jar"

起動の確認は、localhost:8080にhttpアクセスします。


■Eclipseに統合
tomcat plugin
http://www.eclipsetotale.com/tomcatPlugin/tomcatPluginV33.zip

展開して、ディレクトリごとeclipseのpluginディレクトリ直下にコピー。

eclipseを起動(再起動)するとtomcatアイコンが追加されているはず。

起動したら設定のtomcatからパスを設定。

また、conf/tomcat-users.xmlに以下を追加して、guiでtomcatマネージャを
使用できる用に設定。

  <role rolename="manager-gui"/>
  <user username="admin" password="admin" roles="manager-gui"/>


■tomcatプロジェクト
tomcatプロジェクトを作成する。
tomcat用のディレクトリ構成は以下。

・WEB-INF/src・・ソースコードはここに置く。

・WEB-INF・・・・jar(ライブラリ)など外部からアクセスしないものを置く。

・work, bin, src・・とりあえずまだ使わない。

web.xmlはServletAPI3.0から必須では無いのでとりあえずは作らない。


WEB-INF/srcにパッケージを作成、Javaクラスも作成したら、まずはテスト。

ほとんどアノテーションで記述出来る。

@WebServlet(urlPatterns={"/AAA"})

これでwarパッケージ配下のurlを決定出来る。getもpostも簡単にサーバ側
APIの処理が実装出来る。楽しい。
目的はREST APIを簡単に実装することなので、次回はRESTを。


import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = { "/TomcatTest" })
public class TomcatTest extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
try {
response.getWriter().println(request.getParameter("tomcat"));
} catch (IOException e) {
// Error
}
}
}
view raw TomcatTest.java hosted with ❤ by GitHub

2013年5月26日日曜日

OpenCV2.4.5を使ったAndroidプロジェクトでClass not found

OpenCV2.4.5を使ったAndroidプロジェクトでClass not foundが出て悩まされた。

通常のJava Build Pathで無く、AndroidのLibraryにOpenCV Libraryを追加したところ実行出来た。

ただしIs Libraryをチェックしてはダメ。

http://stackoverflow.com/questions/6325826/unable-to-instantiate-activity-caused-by-classnotfoundexception

OpenCV2.4.5 for Android fpsと画角のデバッグ表示

xmlレイアウトファイルのカメラビューの要素に以下を指定する。

opencv:show_fps="true"

親レイアウトに以下を指定する必要がある。

xmlns:opencv="http://schemas.android.com/apk/res-auto"

Android LinearLayout RelativeLayout

LinearLayoutとRelativeLayoutをまとめた記事。
レイアウトはパフォーマンスにも影響するので、シンプルに構成する工夫をしたほうが良いです。


http://d.hatena.ne.jp/Korsakov/20110131/1296504108


・RelativeLayout 相対レイアウト

http://androidguide.nomaki.jp/html/layout/relative/relativeMain.html


・リニアレイアウト
View(ボタンやテキスト)を縦または横一列に並べて配置するために使用します。

http://androidguide.nomaki.jp/html/layout/linearlayout/linearlayoutMain.html

Androidアプリケーションのライフサイクル

Androidアプリケーションのライフサイクル

復習しておきましょう。

まずはactivityのスタート。

3つのメソッドが順番に呼ばれて起動します。


















































別のアクティビティを呼び出したら、以下のように遷移します。


















































別のアクティビティが表示される前に、元のアクティビティのonPause()が呼ばれます。
ここから元のアクティビティを表示する場合は、元のアクティビティのonResume()に戻り、
別のアクティビティを表示する場合は、onStop()に入ります。


他のアクティビティが表示されている状態から、再び画面に表示される場合には、
onRestart() → onStart() → onResume()で再び実行中になります。





























注意は、onStop()状態のアクティビティの状態保存は保証されず、メモリの状態によっては
強制終了されます。それを示したのが以下の図です。




















明示的にアクティビティを終了した場合の処理は、onDestroy()で終了します。














































状態の遷移によって発生する処理を記述するための各メソッドの総称がコールバックメソッド
です。
処理をしたい場合には、オーバーライドして記述しましょう。


OpenCVのアプリケーションを作る場合は、特有のライブラリの読み込みと初期化があるので、
注意が必要です。

2013年5月25日土曜日

OpenCV2.4.5 for Android サンプル clorbloddetect

clorbloddetectっていうサンプル。おもしろい。

リアルタイムにユーザがタッチした部分の色を取得して、近い色の部分を抽出してる。

このコード使って、リアルタイムに処理出来そうだな。

2013年5月24日金曜日

OpenCV2.4.5 for Android環境を作成する

Android環境の作成もとても簡単になっている。

Eclipseは、もともとAndroid開発環境が入っている「Android SDK付属のEclipse」を使用する。

・Android開発環境
http://developer.android.com/sdk/index.html


次は、OpenCV開発に必要な、OpenCVのモジュールとNDKを取得する。
for AndroidモジュールはJNIを使用してネイティブモジュールを呼び出している。
時間が許せば必要な部分のみJNIヘッダを作成するのが良い。

難しい場合、NDKを準備すれば、AndroidでOpenCVを使用することが出来る。


少し古い資料だが、以下のスライドが参考になる。
http://www.slideshare.net/ToruUenoyama/opencvandroid


さて、必要なモジュールは以下。

・OpenCV 2.4.5
http://docs.opencv.org/doc/tutorials/introduction/android_binary_package/O4A_SDK.html

・Android NDK
http://developer.android.com/tools/sdk/ndk/index.html


取得したら、任意のディレクトリに解凍しておく。
ただしスペースが入らないディレクトリを選択するかつくるのが安心。

解凍は以下に行うという前提で進める。

D:\android\OpenCV-2.4.5-android-sdk
C:\android-ndk-r8e

・OpencCVのインポート
 OpencCV-2.4.5-android-sdkディレクトリを、一般プロジェクトとしてインポートする。

まだビルドはうまくいきません。


・jdkを設定する。

 Window → プロパティ → Java → Installed JREs から、jdkを設定。

・プロジェクトのプロパティ → Android からターゲットを2.2に決定。
 OpenCVはAndroid2.2(target 8)から使える用になっているので、SDKマネージャからインストールしておく。

・Nativeサポートを追加する。
 Window → プロパティ →C/C++ → Build → Environmentに以下を設定。
Variable: NDKROOT
Value: C:\android-ndk-r8e
プロジェクト → Android Tools → Android Native Support
 プロジェクト → プロパティ → C/ C++ build → ビルドコマンドに以下を設定
${NDKROOT}/ndk-build.cmd

プロジェクトをビルドする。

ビルドエラーが消えたら完了です。

サンプルを見て行きましょう。


2013年5月13日月曜日

OpenCVで画像を連結する

画像の連結が必要だったので、OpenCVで実装してみました。
仕組みとしては、連結先画像のMat行列に、連結部品の画像のデータをコピーしていくようなものです。

モザイク画のような綺麗に整列したデータや、
結合する先の座標の指定が可能なのでパラメータをランダムに動かせば、予想外の画をつくることも出来そうです。



//============================================================================
// Name : CombinationImages.cpp
// Author :
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <cv.h>
#include <cvaux.h>
#include <highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
int cv_output_tangenbetu_file(InputArray src, char* fileName);
int main(int argc, char** argv) {
//Mat jpeg1, jpeg2;
int img_num = argc > 1 ? argc - 1 : 2;
vector<Mat> src_img;
int total_height;
int width;
for (int i = 0; i < img_num; i++) {
src_img.push_back(imread(argv[i + 1], 1));
Mat last = src_img.back();
total_height += last.rows; ←縦に連結する場合。横の場合は、widthを足していけばOK。
width = last.cols;
}
Mat combined_img(Size(width, total_height), CV_8UC3);
vector<Mat>::iterator it = src_img.begin(), it_end = src_img.end();
Rect roi_rect;
int cnt = 0;
for (; it != it_end; ++it) {
roi_rect.width = it->cols;
roi_rect.height = it->rows;
Mat roi(combined_img, roi_rect);
it->copyTo(roi);
roi_rect.y += it->rows;  ←縦に連結する場合。横の場合は、x座標を操作すればOK。
cnt++;
}
// 表示したい場合は以下を有効に。
//namedWindow("combined images", CV_WINDOW_NORMAL);
//imshow("Display combined images", combined_img);
cv_output_tangenbetu_file(combined_img, <出力したいファイル名>);
waitKey(0);
return 0;
}
/**
* ファイルに書き出す
*/
int cv_output_tangenbetu_file(InputArray src, char* fileName) {
const string file = fileName;
vector<int> params(2);
// 品質(0-100) defalt:95
params[0] = CV_IMWRITE_JPEG_QUALITY;
params[1] = 100;
imwrite(file, src, params);
return 0;
}

2013年5月11日土曜日

JNI JavaからCppを実行する


JNI Javaからcppを呼び出してみる。

■まずはJavaでコード書きます
https://gist.github.com/masazdream/5560075

package jp.sp.jni;
public class HelloWorldJNI {
static {
System.loadLibrary("HelloWorldJNI");
}
public native String sayHelloWorld();
public static void main(String[] args){
HelloWorldJNI hello = new HelloWorldJNI();
System.out.println(hello.sayHelloWorld());
}
}

■対応するCppファイルを書きます
https://gist.github.com/masazdream/5560082


//============================================================================
// Name : HelloWorldJNI.cpp
// Author :
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include "jp_sp_jni_HelloWorldJNI.h"
JNIEXPORT jstring JNICALL
Java_jp_sp_jni_HelloWorldJNI_sayHelloWorld(JNIEnv *env, jobject obj){
return env->NewStringUTF("Hello World");
}
※Javaのコードとの名称対応は大切です。


■JavaとCppのコードから必要なヘッダファイルとSharedObjectを作成します
そのために今回はantを使用しますので、antからgccコンパイルする環境を作成します。

・ant-contribのバイナリをantのlibに配置
http://sourceforge.net/projects/ant-contrib/files/

・ant-xercesのバイナリを取得して、antoのlibに配置

http://xerces.apache.org/mirrors.cgi

・ant-cpptasksを作成する。
http://sourceforge.net/projects/ant-contrib/files/ant-contrib/cpptasks-1.0-beta5/


デフォルトでついてくるbuild.xmlに以下の対策を施して、実行するとjarが作成出来ます。
■対策
①javacタグにincludeAntRuntime="true"を設定します。
②ソースをコンパイルするJavaのバージョンに注意しないと警告が
うるさいので処理します。
A. java.sourceとjavac.targetには、コンパイルするJavaのバージョンを
設定しましょう。
B. jt.jarのパスを表すpathを作成して、javacのbootclasspathに指定します。
<path id="compile.boot.path">
  <fileset dir="${java.home}/lib">
    <include name="rt.jar" />
  </fileset>
</path>
<javac ・・・
  <bootclasspath refid="compile.boot.path" />
</javac>

■必要なパスを通す
③xercesのライブラリをクラスパスに追加する
<path id="compile.path">
  <fileset dir="[最初のステップでjarを置いたディレクトリ]">
    <include name="*.jar" />
  </fileset>
</path>
<javac ・・・
  <classpath refid="compile.path" />
</javac>

これでコンパイル出来ます。
target/lib/cpptasks.jarがあるので、ant本体のlibディレクトリに
コピーします。

> echo $ANT_HOME

でhomeを確認が出来たら、配下のlibにコピーします。

■antの記述を整えます。
javahでヘッダーファイル作成を記述します。
ccタスクでcppファイルをコンパイルします。

<taskdef resource="cpptasks.tasks">でccタスクを使用する準備が出来ますので、
以下のようにccタスクを記述します。

<cc link="shared" outfile="[soを出力するディレクトリ名]/[クラス名]" obj="[ヘッダーファイルを出力したディレクトリ]">
  <includepath location="${env.JAVA_HOME}/include}" />
  <includepath location="${env.JAVA_HOME}/include/linux" />
  <fileset dir="[ヘッダーファイルを出力したディレクトリ]" includes="HelloWorldJNI.cpp" />
  <libset libs="stdc++">  ←cppの場合は指定。CとCPPが混じっている場合には、cppファイルのみにantで実行出来ます。
</cc>

※outfileに指定したパスのファイル名をつかって、libhello.soなどの名前が決定されます。

最終的に以下の様なファイルになる。https://gist.github.com/masazdream/5560085

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- WARNING: Eclipse auto-generated file.
Any modifications will be overwritten.
To include a user specific buildfile here, simply create one in the same
directory with the processing instruction <?eclipse.ant.import?>
as the first entry and export the buildfile again. -->
<project basedir="." default="build" name="jni">
<property environment="env" />
<property name="ECLIPSE_HOME" value="../../eclipse" />
<property name="debuglevel" value="source,lines,vars" />
<property name="target" value="1.7" />
<property name="source" value="1.7" />
<path id="jni.classpath">
<pathelement location="bin" />
</path>
<target name="init">
<mkdir dir="bin" />
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java" />
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="bin" />
</target>
<target depends="clean" name="cleanall" />
<target depends="build-subprojects,build-project,makeh" name="build" />
<target name="build-subprojects" />
<target depends="init" name="build-project">
<echo message="${ant.project.name}: ${ant.file}" />
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
<src path="src" />
<classpath refid="jni.classpath" />
</javac>
</target>
<property name="h_dir" location="/root/workspace/jni/jnih" />
<target name="makeh">
<taskdef resource="cpptasks.tasks" />
<javah classpath="/root/workspace/jni/bin" class="jp.sp.jni.HelloWorldJNI" destdir="${h_dir}" />
<cc link="shared" outfile="/root/workspace/jni/dist/HelloWorldJNI" objdir="${h_dir}">
<includepath location="${env.JAVA_HOME}/include" />
<includepath location="${env.JAVA_HOME}/include/linux" />
<fileset dir="${h_dir}" includes="HelloWorldJNI.cpp" />
<libset libs="stdc++" />
</cc>
</target>
<target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects" />
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
<copy todir="${ant.library.dir}">
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" />
</copy>
<unzip dest="${ant.library.dir}">
<patternset includes="jdtCompilerAdapter.jar" />
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar" />
</unzip>
</target>
<target description="compile project with Eclipse compiler" name="build-eclipse-compiler">
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />
<antcall target="build" />
</target>
</project>
view raw build.xml hosted with ❤ by GitHub

■Javaの実行
soファイルの入ったディレクトリを環境変数「LD_LIBRARY_PATH」に指定してから実行します。

実行結果は、Hello World。
せっかくなのでcやcppで記述したファイルをドンドンJavaで実行していましょう。


2013年5月3日金曜日

Java コマンド実行 execとProcessBuilder

Javaから外部コマンドを実行する際にはexecでは無くProcessBuilderを使いましょう。

Javaの内部実装もProcessBuilderですし、何より標準出力と標準エラー出力のバッファが小さいことによるデッドロックが起こりません。
後、標準出力と標準エラー出力を簡単にマージできちゃいます。


ffmpegを使っているときに、標準出力サイズがとても大きくなることと、標準エラー出力と交互に出るので、execだとデッドロックが発生したり、Threadで対処したりいろいろ面倒くさかったのでメモ。