2016-12-21 10 views
1

私が作っているアプリケーションについては、カメラコンパスが必要です。アプリケーションはマニフェストのランドスケープモードに設定されています。
まずコンパスを実装しました。 Androidデベロッパーに示唆されているように、私は2つのセンサー - 加速度センサー磁場を使用しました。これは私がそれをした方法です:
私は自分の活動を実装してSensorEventListenerです。 onCreate()では、私は私のsensorManager使用して初期化します。Androidカメラはセンサー(加速度計と磁場)に影響します。電話機ユーザーの場合

sManager = (SensorManager) getSystemService(SENSOR_SERVICE); 


私はそうのようなonResume()で私のリスナーを登録:

sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),SensorManager.SENSOR_DELAY_NORMAL); 
sManager.registerListener(this, sManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),SensorManager.SENSOR_DELAY_NORMAL); 

onPause()でその登録解除もちろん

。 私は onAccuracyChanged()を使用しません。これは私が onSensorChanged()に何をすべきかです:

@Override 
public void onSensorChanged(SensorEvent event) { 
    switch (event.sensor.getType()) { 
     case Sensor.TYPE_MAGNETIC_FIELD: 
      mags = event.values.clone(); 
      break; 
     case Sensor.TYPE_ACCELEROMETER: 
      accels = event.values.clone(); 
      break; 
    } 

    if (mags != null && accels != null) { 
     gravity = new float[9]; 
     magnetic = new float[9]; 
     SensorManager.getRotationMatrix(gravity, magnetic, accels, mags); 
     float[] outGravity = new float[9]; 

     float inclination = (float) Math.acos(gravity[8]); 
     if (inclination < Math.toRadians(25) 
       || inclination > Math.toRadians(155)) { 
      // device is close to flat. Remap for landscape. 
      SensorManager.remapCoordinateSystem(gravity, SensorManager.AXIS_Y,SensorManager.AXIS_MINUS_X, outGravity); 
      SensorManager.getOrientation(outGravity, values); 
     } else { 
      // device is not flat. Remap for landscape and perpendicular 
      SensorManager.remapCoordinateSystem(gravity, SensorManager.AXIS_X,SensorManager.AXIS_Z, outGravity); 
      SensorManager.getOrientation(outGravity, values); 
     } 
     azimuth = Math.round(Math.toDegrees(values[0])); 
    } 
} 

あなたが見ることができるように、私は電話がテーブルの上に平らに置かれたときに区別し、(あなたが写真を撮るだろうというときのように)、ユーザーがそれを保持しているとき。このコードだけを使用すると、すべてが多かれ少なかれ動作します。私は、電話機がテーブルに横たわっているときと、テーブルに垂直に(約5-10度の違いがありますが、それと一緒に暮らすことができます)、正しい方位角の値を得ています。

問題は、カメラプレビューをアプリケーションに追加するときに開始されます。 私は自分の活動にSurfaceHolder.Callbackを実装しています。私はonCreate()に私のカメラを初期化:私は私のプロジェクトにカメラコードを追加すると

@Override 
public void surfaceCreated(SurfaceHolder surfaceHolder) { 
    camera = Camera.open(); 
    camera.setDisplayOrientation(0); 
} 

@Override 
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { 
    if (isCameraOn) { 
     camera.stopPreview(); 
     isCameraOn = false; 
    } 

    if (camera != null) { 
     try { 
      camera.setPreviewDisplay(surfaceHolder); 
      camera.startPreview(); 
      isCameraOn = true; 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

@Override 
public void surfaceDestroyed(SurfaceHolder surfaceHolder) { 
    camera.stopPreview(); 
    camera.release(); 
    camera = null; 
} 

、および携帯電話の画面、私のセンサーにカメラを示しています。

SurfaceView cameraView = (SurfaceView)findViewById(R.id.camera_view); 
surfaceHolder = cameraView.getHolder(); 
surfaceHolder.addCallback(this); 
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { 
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 

これは私がインターフェイスを実装する方法であります電話機が突然垂直になると正しく動作しません。電話機がテーブルの上に横になっていると、私が得ている方位角の値は正しいです。電話がテーブルに対して垂直に保持されているとき、方位角の値は約40度ずれています(安定していますが)。

私は解決策を探してみましたが(自分でもオンラインでも)、これまでの努力は無駄でした。私はこの問題にどのように取り組むべきかについていくつか指導をしたいと思う。
ありがとう!

+0

これは同じデバイスですか? –

+0

同じデバイスでチェックしています。それまでの間、私はいくつかの友人に自分のアプリケーションを送ってチェックしてもらいました(「コンパス」とカメラの両方で)。たいていの場合、違いは約5-10(私と一緒に暮らすことができます)でしたが、30度の差がある小切手はほとんどありませんでした(小切手の約10%)。彼らがカメラなしでチェックしたとき、最大差は約5-10でした。だから私の携帯電話のように悪くないが、まだ少し信頼性の低い。解決策が見つからない場合、私はおそらく今のところそれを残して、将来的にはより正確な精度が必要かどうかを確認します。 – Ungoliant

+0

問題は、カメラとコンパスの両方のコールバックがメイン(UI)スレッド上でCPUを競合する可能性があることです。セカンダリHandlerThreadでカメラを開く必要があります。 –

答えて

0

最初のTYPE_MAGNETIC_FIELDセンサーは、すべてのデバイスで使用できるわけではありません。 TYPE_ACCELEROMETERセンサーのみを使用して要件を満たすことができます。

加速度センサーを取得

Sensor accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 

ちょうど比較し、センサ変化イベントコール

@Override 
public void onSensorChanged(SensorEvent event) { 
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 
    mGravity = event.values; 
} 

はその後、すべての軸のセンサ値を取得するための関数の下に使用できる値をコピーします。

public int[] getDeviceAngles() { 
    float[] g = mGravity.clone(); 
    double normOfG = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]); 

    // Normalize the accelerometer vector 
    g[0] = (float) (g[0]/normOfG); 
    g[1] = (float) (g[1]/normOfG); 
    g[2] = (float) (g[2]/normOfG); 

    int x = (int) Math.round(Math.toDegrees(Math.atan2(g[1], g[0]))); 
    int pitch = (int) Math.round(Math.toDegrees(Math.atan2(g[1], g[2]))); 
    int rollValue = (int) Math.round(Math.toDegrees(Math.atan2(g[2], g[0]))); 
    int pitchValue = pitch * -1; 
    int[] values = new int[3]; 
    values[0] = x; 
    values[1] = pitchValue; 
    values[2] = rollValue; 
    //values contains: azimut, pitch and roll 
    return values; 
} 
関連する問題