マルチ・トラッキングして地図やWebと連携するAR
絵画を検出したら、情報表示サイトを開いて、その絵を所蔵している美術館をGoogle Mapsで見てみましょう。
こんな感じです
絵画の検出には、SATCHを使ってArt_ProjectでAR(マルチ・トラッキング)で使ったやり方を使用。
絵画は、The Starry Night、Ophelia、The Cathedralの3つを使います。
絵画を検出していない場合
メニュの「Map View」をタップすると、GPSで取得した現在地を表示。
GPSでの位置情報が取得できていない場合、とりあえず「富士山」にロケーションされています。
「Web View」をタップすると、ただのGoogleの検索画面を表示。
絵画を検出した場合
黄色い文字が表示されれば、検出OKです。
黄色い文字が表示された状態のままで、以下を実行。
メニュの「Map View」をタップすると、この絵画を所蔵する美術館の場所を表示。
「Web View」をタップすると、絵画についての情報を表示。
以上
TOP
SATCHのtracking.luaのコード
絵画の検出については、SATCHを使ってArt_ProjectでAR(マルチ・トラッキング)を参照。
【tracking.lua】
local text = Text2D(getCurrentScene():getObjectByName("text")) local componentInterface = getComponentInterface() -- GLOBAL VARIABLES -- tracking statuts: if 1 : tracking, if 0 : no tracking gtrackingStatus = 0 -- get the keyframe index from a tracked object with auto-initialization gtrackingKeyFrameIndex = -1 -- scene local scene = getCurrentScene() -- get the virtual camera, will be used to send to the MLT local camera = Camera(scene:getCurrentCamera()) -- get the videocapture, will be used to send to the MLT local videoCapture_live = VideoCapture(scene:getObjectByName("videocapture_live")) -- Tracking local MLTPlugin = getMLTPluginManager() -- Error status local errorStatus = eOk -- tracking index : the index of the tracker.xml (because we can open more than 1 tracking.xml file). local trackingIndex = -1 -- the fps of the Tracking engine local trackingRate = 0 -- vector to put the tracking position local trackingPosition = Vector3() -- quaternion to put the tracking orientation local trackingOrientation = Quaternion() -- 3D object receiving tracking pose --local trackingObject = Object3D(scene:getObjectByName("Tracking_Object")) -- object index from the tracking scenario (0 : first object, 1 : second object...) (this is the index in the "Objects" panel of the CV GUI) local trackingObjectIndex = 0 --検出時やロスト時にメッセージを1回だけ出すためのフラグ local found_sendflag = false local lost_sendflag = false -- this is how to start a tracking. the function needs the path to the tracker.xml file, the videocapture id and the camera object. errorStatus, trackingIndex = MLTPlugin:startTracking("tracker/tracker.xml", videoCapture_live:getVidCapID(), camera) -- if the tracking has correctly started, we can proceed to an infinite loop if errorStatus == eOk then repeat errorStatus, gtrackingStatus = MLTPlugin:getTargetStatus(trackingIndex, trackingObjectIndex) errorStatus, gtrackingKeyFrameIndex = MLTPlugin:getRecognizedKeyFrameIndex(trackingIndex, trackingObjectIndex) -- if our object is detected... if (gtrackingStatus == 1) then if found_sendflag == false then if gtrackingKeyFrameIndex == 0 then text:setText("The Starry Night(Vincent van Gogh)") componentInterface:executeAppFunc("setTrackingStatus","StarryNight") elseif gtrackingKeyFrameIndex == 1 then text:setText("Ophelia(Sir John Everett Millais)") componentInterface:executeAppFunc("setTrackingStatus","Ophelia") elseif gtrackingKeyFrameIndex == 2 then text:setText("The Cathedral(Frantisek Kupka)") componentInterface:executeAppFunc("setTrackingStatus","Cathedral") end found_sendflag = true lost_sendflag = false end text:setVisible(true) -- if the tracking is lost else if lost_sendflag == false then text:setVisible(false) componentInterface:executeAppFunc("setTrackingStatus","lost") found_sendflag = false lost_sendflag = true end end until coroutine.yield() end
SATCHのシナリオを「com.kddi.satch.xxxxxx」で保存。
xxxxxxのところは、ご自分で適当に設定してください。
このアプリケーションIDは、EclipseのAndroidManifest.xmlのパッケージ名と一致させます。
でないと、アプリをデプロイする際に、ライセンスエラーになります。
TOP
Eclipseのプロジェクト
ソースはSATCHのViewFlipperを参照。
ダウンロードできるようにしておきましたので、なんかの参考にしていただければ...。
ViewFlipper
このままでは、素直に使えません(^^)。
これをベースにして、プロジェクトを再作成してください。
その際必要なのは、
com.kddi.satch.sampleviewflipperのプロジェクト名をSATCHのシナリオ作成で使ったものに変更。
res/layout/map.xmlのGoogleのキーを自分のものに変更(この辺はSATCHのDevelopers siteのViewFlipperを参照)
GPSを使うので、AndroidManifest.xmlに以下を追加。
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
javaファイルで基本的に変更がかかるのは、SampleViewFlipper.javaだけです。
参考になるかどうか分かりませんが例です。SATCHのオリジナルと異なるのは、GPSの位置情報取得用のコードを入れています。
Mapsのオーバーレイを表示する部分は、参考にならないかも(^^)。
package com.kddi.satch.artdetectmultiviewflipper; import java.util.List; import com.google.android.maps.*; import android.location.*; import com.kddi.satch.artdetectactivity.ArtdetectActivity_simpleMap; import android.app.Activity; import android.content.Context; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ViewFlipper; public class ArtDetectionMultiActivity extends ArtdetectActivity_simpleMap{ private static final String THIS_CLASS_SHORT_NAME = ArtDetectionMultiActivity.class.getName().replace("com.kddi.satch.artdetectmultiviewflipper.", ""); private static final String THIS_LOGTAG = THIS_CLASS_SHORT_NAME; private static final String SCENARIO_NAME = "/assets/Scenario/Scenario_a/artDetection_multi.dpd"; protected String getSampleScenarioName() { return SCENARIO_NAME; } protected String getSampleLogTag() { return THIS_LOGTAG; } private ViewFlipper _viewFlipper; private MapView _mapView; private GoogleMapsItemizedOverlay _itemizedoverlay1; private GoogleMapsItemizedOverlay _itemizedoverlay2; private OverlayItem _overlayitem1; private OverlayItem _overlayitem2; private GeoPoint _point1; private GeoPoint _point2; private WebView _webView; private String _urlTargetPlace; private boolean _trackingStatus; private LocationManager mLocationManager; private static final int MENU_VIEW_DFUSION = 0; private static final int MENU_VIEW_WEB = 1; private static final int MENU_VIEW_MAP = 2; private static final int MENU_STREET_VIEW = 3; private void resetMembers() { _viewFlipper = null; _mapView = null; _itemizedoverlay1 = null; _itemizedoverlay2 = null; _overlayitem1 = null; _overlayitem2 = null; _point1 = null; _point2 = null; _webView = null; //_trackingX = _trackingY = _trackingZ = 0; //prev_lat1 = prev_lat1 = 0; _trackingStatus = false; _urlTargetPlace = "http://www.google.com"; } @Override protected boolean isRouteDisplayed() { // from MapActivity return false; } @Override public void onCreate(Bundle savedInstanceState) { //Log.i( getSampleLogTag(), ".... onCreate" ); super.onCreate(savedInstanceState); // initialize values resetMembers(); // initialize inflated views {// Web view LayoutInflater li = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); _webView = (WebView) li.inflate(R.layout.web, null); initWebView(); } {// Map view LayoutInflater li = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); _mapView = (MapView) li.inflate(R.layout.map, null); initMapView(); } mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); Criteria criteria = new Criteria(); criteria.setAccuracy(Criteria.ACCURACY_FINE); criteria.setAltitudeRequired(false); criteria.setBearingRequired(false); criteria.setCostAllowed(false); criteria.setPowerRequirement(Criteria.POWER_LOW); criteria.setSpeedRequired(false); String provider = mLocationManager.getBestProvider(criteria, true); mLocationManager.requestLocationUpdates(provider, 1000, 1, locationListener); // } @Override public void onDestroy() { //Log.i( getSampleLogTag(), ".... onDestroy" ); // release what we inflated _mapView = null; _webView = null; super.onDestroy(); // final clean-up resetMembers(); } @Override public void postInitComponent() { //Log.i( getSampleLogTag(), "postInitComponent" ); _kddiComponent.activateAutoFocusOnDownEvent(true); _kddiComponent.registerCommunicationCallback("setTrackingStatus", this, "setTrackingStatus"); } @Override public void initContentView() { //Log.i( getSampleLogTag(), "initContentView" ); if (_isInitializedCorrectly) { _viewFlipper = new ViewFlipper(this); // Child 0 : Detect Artworks _viewFlipper.addView(_frameLayout); // Child 1 : Web View _viewFlipper.addView(_webView); // Child 2 : Map View _viewFlipper.addView(_mapView); // Activity content view will be the view flipper setContentView(_viewFlipper); new Handler().postDelayed(new Runnable() { public void run() { openOptionsMenu(); } }, 1000 ); } } @Override public void releaseContentView() { //Log.i( getSampleLogTag(), "releaseContentView" ); if (_isInitializedCorrectly) { if (_viewFlipper != null) { _viewFlipper.removeAllViews(); } _viewFlipper = null; } } public void setTrackingStatus(String [] arrayOfString) { //Log.i("STATUS",arrayOfString[0]); if(arrayOfString.length ==1){ if(arrayOfString[0].equals("StarryNight")){ _trackingStatus = true; setMuseumPosition(40.761484, -73.977664); //_urlTargetPlace = "http://wisteriahill.sakura.ne.jp/jqm_viewflipper/index.html"; _urlTargetPlace = "http://ja.wikipedia.org/wiki/%E6%98%9F%E6%9C%88%E5%A4%9C"; }else if(arrayOfString[0].equals("Ophelia")){ _trackingStatus = true; setMuseumPosition(51.490833, -0.127222); _urlTargetPlace = "http://en.wikipedia.org/wiki/Ophelia_(painting)"; }else if(arrayOfString[0].equals("Cathedral")){ _trackingStatus = true; setMuseumPosition(50.087222, 14.408611); _urlTargetPlace = "http://wisteriahill.sakura.ne.jp/jqm_viewflipper/cathedral.html"; }else if(arrayOfString[0].equals("lost")){ _trackingStatus = false; _urlTargetPlace = "http://www.google.fr"; _point2 = null; } } } public void setMuseumPosition(double latitude,double longitude) { int lat2 = (int)(latitude*1E6); int lon2 = (int)(longitude*1E6); _point2 = new GeoPoint(lat2,lon2); } public void setTrackingStatus(boolean trackingStatus) { _trackingStatus = trackingStatus; } public void setUrlTargetPlace(int target_num) { MapController ctrl = _mapView.getController(); if(ctrl != null){ List<Overlay> mapOverlays = _mapView.getOverlays(); mapOverlays.clear(); initMapView(); if(target_num == 1){ ctrl.setCenter(_point1); }else if(target_num == 2){ ctrl.setCenter(_point2); } } _webView.loadUrl(_urlTargetPlace); } public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_VIEW_DFUSION, 0, "Detect Artworks").setIcon(R.drawable.sunflowers); menu.add(0, MENU_VIEW_WEB, 0, "Web view").setIcon(R.drawable.web); menu.add(0, MENU_VIEW_MAP, 0, "Map view").setIcon(R.drawable.map); //menu.add(0, MENU_STREET_VIEW, 0, "StreetView").setIcon(R.drawable.pegman); return true; } public boolean onOptionsItemSelected(MenuItem item) { switch ( item.getItemId() ) { case MENU_VIEW_DFUSION: _viewFlipper.setDisplayedChild(0); return true; case MENU_VIEW_WEB: _viewFlipper.setDisplayedChild(1); return true; case MENU_VIEW_MAP: _viewFlipper.setDisplayedChild(2); if (_trackingStatus == true){ setUrlTargetPlace(2); } else{ setUrlTargetPlace(1); } return true; case MENU_STREET_VIEW: return true; } return false; } private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } } public void initMapView() { _mapView.setBuiltInZoomControls(true); List<Overlay> mapOverlays = _mapView.getOverlays(); //overlay2 Drawable drawableMuseum = this.getResources().getDrawable(R.drawable.museum); _itemizedoverlay1 = new GoogleMapsItemizedOverlay(drawableMuseum, this.getApplicationContext()); if (_point2 == null){ double latitude2 = 0;//dummy double longitude2 = 0;//dummy int lat2 = (int)(latitude2*1E6); int lon2 = (int)(longitude2*1E6); _point2 = new GeoPoint(lat2,lon2); _overlayitem2 = new OverlayItem(_point2, "Hello!", "I'm 2"); _itemizedoverlay1.addOverlay(_overlayitem2); }else{ _overlayitem2 = new OverlayItem(_point2, "Hello!", "I'm 2"); _itemizedoverlay1.addOverlay(_overlayitem2); mapOverlays.add(_itemizedoverlay1); } // overlay1 Drawable drawableMyloc = this.getResources().getDrawable(R.drawable.person); _itemizedoverlay2 = new GoogleMapsItemizedOverlay(drawableMyloc, this.getApplicationContext()); if (_point1 == null) { double latitude1 = 35.36286726458948; double longitude1 = 138.73157501220703; int lat1 = (int)(latitude1*1E6); int lon1 = (int)(longitude1*1E6); _point1 = new GeoPoint(lat1,lon1); } _overlayitem1 = new OverlayItem(_point1, "Hello!", "I'm 1"); _itemizedoverlay2.addOverlay(_overlayitem1); mapOverlays.add(_itemizedoverlay2); } public void initWebView() { _webView.getSettings().setJavaScriptEnabled(true); _webView.getSettings().setBuiltInZoomControls(true); _webView.getSettings().setSupportZoom(true); final ArtDetectionMultiActivity activity = this; _webView.setWebChromeClient(new WebChromeClient() { public void onProgressChanged(WebView view, int progress) { // Activities and WebViews measure progress with different scales. // The progress meter will automatically disappear when we reach 100% ((Activity) activity).setProgress(progress * 1000); } }); // to handle its own URL requests : _webView.setWebViewClient(new MyWebViewClient()); _webView.loadUrl("http://www.google.fr"); } //------------------------------------ private LocationListener locationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { double latitude = location.getLatitude(); double longitude = location.getLongitude(); int lat = (int)(latitude*1E6); int lon = (int)(longitude*1E6); _point1 = new GeoPoint(lat,lon); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { switch (status) { case LocationProvider.AVAILABLE: //Log.v("Status", "AVAILABLE"); break; case LocationProvider.OUT_OF_SERVICE: //Log.v("Status", "OUT_OF_SERVICE"); break; case LocationProvider.TEMPORARILY_UNAVAILABLE: //Log.v("Status", "TEMPORARILY_UNAVAILABLE"); break; } } }; }
コード内のパッケージ名やファイル名、SCENARIO_NAMEのパスは修正してください。
TOP
公開用Google ApiKey取得
ViewFlipperサンプルでは、MapViewを使ってGoogle Mapsを表示しています。
このサンプルを使って新しくプロジェクトを作成し
apkを公開する場合、公開用のGoogle Apiキーを取得する必要があります。
New
以下は、Google Maps Android API v1用のキーについての記述です。
Google Maps Android API v2では、キー取得の方法が変わっていますので、ご注意ください。
ここでは、既にキーストアが作成されているものとします。
キーストアの作成やデジタル署名したapkの作成方法は、
PhoneGapでネイティブアプリ
の、「ネイティブアプリを作って、ダウンロード・インストール」の項を参照。
まず、DOS窓を開きます。
以下のコマンドを発行。
keytool -list -v -keystore <作成したキーストアのフルパス>
New
keytoolコマンドのオプションに-vを追加しました。
vオプションが無い場合は、SHA1のフィンガープリントしか表示してくれないようです。
vオプションをつけることで、MD5/SHA1/SHA256の3つのフィンガープリントを表示してくれます。
Google Maps Android API v1では、MD5を使います。
パスワードを聞いてきますので、これもキーストア作成時のパスワードを使用。
証明書のフィンガープリントが表示されます。
Sign Up for the Android Maps API
のページを開きます。
ページの下の、I have read and agree ...にチェックを入れ、My certificate's MD5 fingerprint:の欄に先ほどのフィンガープリントを入力して、Generate API Keyのボタンをクリック。
表示されたキーが公開用のキーになります。
これを、res->layout->map.xmlのandroid:apiKeyにセットします。
これで、MapViewでGoogle Mapsが表示されるようになります。
TOP
トップページ| サイトマップ|