Java 如何并排显示2个摄像头预览?[用于硬纸板应用程序]
我正在尝试建立一个纸板安卓应用程序,显示2个摄像头的看法并排。 [就像Android应用程序的摄像头视图一样。] 因此,我研究了GitHub的硬纸板代码,进行了一些修改,到目前为止,我能够使用imageView并排复制相同的图像 到目前为止,代码是这样的 AndroidManifest.XMLJava 如何并排显示2个摄像头预览?[用于硬纸板应用程序],java,android,camera,google-cardboard,Java,Android,Camera,Google Cardboard,我正在尝试建立一个纸板安卓应用程序,显示2个摄像头的看法并排。 [就像Android应用程序的摄像头视图一样。] 因此,我研究了GitHub的硬纸板代码,进行了一些修改,到目前为止,我能够使用imageView并排复制相同的图像 到目前为止,代码是这样的 AndroidManifest.XML <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.vrtoolkit.cardboard.samples.treasurehunt" >
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
<uses-sdk android:minSdkVersion="14"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:screenOrientation="landscape"
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MainActivity.Java
package com.google.vrtoolkit.cardboard.samples.treasurehunt;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* Contains two sub-views to provide a simple stereo HUD.
*/
public class CardboardOverlayView extends LinearLayout {
private static final String TAG = CardboardOverlayView_bkp1.class.getSimpleName();
private final CardboardOverlayEyeView mLeftView;
private final CardboardOverlayEyeView mRightView;
private AlphaAnimation mTextFadeAnimation;
public CardboardOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(HORIZONTAL);
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
params.setMargins(0, 0, 0, 0);
mLeftView = new CardboardOverlayEyeView(context, attrs);
mLeftView.setLayoutParams(params);
addView(mLeftView);
mRightView = new CardboardOverlayEyeView(context, attrs);
mRightView.setLayoutParams(params);
addView(mRightView);
// Set some reasonable defaults.
setDepthOffset(0.016f);
setColor(Color.rgb(150, 255, 180));
setVisibility(View.VISIBLE);
mTextFadeAnimation = new AlphaAnimation(1.0f, 0.0f);
mTextFadeAnimation.setDuration(5000);
}
public void show3DToast(String message) {
setText(message);
setTextAlpha(1f);
mTextFadeAnimation.setAnimationListener(new EndAnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
setTextAlpha(0f);
}
});
startAnimation(mTextFadeAnimation);
}
public void show3DImage() {
setImg();
}
private abstract class EndAnimationListener implements Animation.AnimationListener {
@Override public void onAnimationRepeat(Animation animation) {}
@Override public void onAnimationStart(Animation animation) {}
}
private void setDepthOffset(float offset) {
mLeftView.setOffset(offset);
mRightView.setOffset(-offset);
}
//---------------------------------------------------------------------------------------------
private void setImg(){
mLeftView.imageView.setImageResource(R.drawable.mona_lisa);
mRightView.imageView.setImageResource(R.drawable.mona_lisa);
}
//------------------------------------------------------------------------------------------
private void setText(String text) {
mLeftView.setText(text);
mRightView.setText(text);
}
private void setTextAlpha(float alpha) {
mLeftView.setTextViewAlpha(alpha);
mRightView.setTextViewAlpha(alpha);
}
private void setColor(int color) {
mLeftView.setColor(color);
mRightView.setColor(color);
}
/**
* A simple view group containing some horizontally centered text underneath a horizontally
* centered image.
*
* This is a helper class for CardboardOverlayView.
*/
private class CardboardOverlayEyeView extends ViewGroup {
private final ImageView imageView;
private final TextView textView;
private float offset;
public CardboardOverlayEyeView(Context context, AttributeSet attrs) {
super(context, attrs);
imageView = new ImageView(context, attrs);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setAdjustViewBounds(true); // Preserve aspect ratio.
addView(imageView);
textView = new TextView(context, attrs);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14.0f);
textView.setTypeface(textView.getTypeface(), Typeface.BOLD);
textView.setGravity(Gravity.CENTER);
textView.setShadowLayer(3.0f, 0.0f, 0.0f, Color.DKGRAY);
addView(textView);
}
public void setColor(int color) {
//imageView.setColorFilter(color);
textView.setTextColor(color);
}
public void setText(String text) {
textView.setText(text);
}
public void setTextViewAlpha(float alpha) {
textView.setAlpha(alpha);
}
public void setOffset(float offset) {
this.offset = offset;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// Width and height of this ViewGroup.
final int width = right - left;
final int height = bottom - top;
// The size of the image, given as a fraction of the dimension as a ViewGroup. We multiply
// both width and heading with this number to compute the image's bounding box. Inside the
// box, the image is the horizontally and vertically centered.
final float imageSize = 1.0f;
// The fraction of this ViewGroup's height by which we shift the image off the ViewGroup's
// center. Positive values shift downwards, negative values shift upwards.
final float verticalImageOffset = -0.07f;
// Vertical position of the text, specified in fractions of this ViewGroup's height.
final float verticalTextPos = 0.52f;
// Layout ImageView
float imageMargin = (1.0f - imageSize) / 2.0f;
float leftMargin = (int) (width * (imageMargin + offset));
float topMargin = (int) (height * (imageMargin + verticalImageOffset));
imageView.layout(
(int) leftMargin, (int) topMargin,
(int) (leftMargin + width * imageSize), (int) (topMargin + height * imageSize));
// Layout TextView
leftMargin = offset * width;
topMargin = height * verticalTextPos;
textView.layout(
(int) leftMargin, (int) topMargin,
(int) (leftMargin + width), (int) (topMargin + height * (1.0f - verticalTextPos)));
}
}
}
package com.google.vrtoolkit.cardboard.samples.treasurehunt;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.widget.ImageView;
import com.google.vrtoolkit.cardboard.*;
import javax.microedition.khronos.egl.EGLConfig;
import java.nio.FloatBuffer;
/**
* A Cardboard sample application.
*/
public class MainActivity extends CardboardActivity implements CardboardView.StereoRenderer {
private static final int CAMERA_REQUEST = 1888;
private static final String TAG = "MainActivity";
private static final int CAPTURE_IMAGE_ACTIVITY_REQ = 0;
Uri fileUri = null;
ImageView photoImage = null;
private static final float CAMERA_Z = 0.01f;
private static final float TIME_DELTA = 0.3f;
private static final float YAW_LIMIT = 0.12f;
private static final float PITCH_LIMIT = 0.12f;
// We keep the light always position just above the user.
private final float[] mLightPosInWorldSpace = new float[]{0.0f, 2.0f, 0.0f, 1.0f};
private final float[] mLightPosInEyeSpace = new float[4];
private static final int COORDS_PER_VERTEX = 3;
private final WorldLayoutData DATA = new WorldLayoutData();
private FloatBuffer mFloorVertices;
private FloatBuffer mFloorColors;
private FloatBuffer mFloorNormals;
private FloatBuffer mCubeVertices;
private FloatBuffer mCubeColors;
private FloatBuffer mCubeFoundColors;
private FloatBuffer mCubeNormals;
private int mGlProgram;
private int mPositionParam;
private int mNormalParam;
private int mColorParam;
private int mModelViewProjectionParam;
private int mLightPosParam;
private int mModelViewParam;
private int mModelParam;
private int mIsFloorParam;
private float[] mModelCube;
private float[] mCamera;
private float[] mView;
private float[] mHeadView;
private float[] mModelViewProjection;
private float[] mModelView;
private float[] mModelFloor;
private int mScore = 0;
private float mObjectDistance = 12f;
private float mFloorDepth = 20f;
private Vibrator mVibrator;
private CardboardOverlayView mOverlayView;
public MainActivity() {
}
/**
* Sets the view to our CardboardView and initializes the transformation matrices we will use
* to render our scene.
* //@param savedInstanceState
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common_ui);
CardboardView cardboardView = (CardboardView) findViewById(R.id.cardboard_view);
cardboardView.setRenderer(this);
setCardboardView(cardboardView);
mModelCube = new float[16];
mCamera = new float[16];
mView = new float[16];
mModelViewProjection = new float[16];
mModelView = new float[16];
mModelFloor = new float[16];
mHeadView = new float[16];
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mOverlayView = (CardboardOverlayView) findViewById(R.id.overlay);
mOverlayView.show3DToast("Pull the magnet when you find an object.");
mOverlayView.show3DImage();
}
@Override
public void onRendererShutdown(){Log.i(TAG, "onRendererShutdown");
}
@Override
public void onSurfaceChanged(int width, int height) {
Log.i(TAG, "onSurfaceChanged");
}
/**
* Creates the buffers we use to store information about the 3D world. OpenGL doesn't use Java
* arrays, but rather needs data in a format it can understand. Hence we use ByteBuffers.
*
* @param config The EGL configuration used when creating the surface.
*/
@Override
public void onSurfaceCreated(EGLConfig config) {
Log.i(TAG, "onSurfaceCreated");
}
/**
* Prepares OpenGL ES before we draw a frame.
*
* @param headTransform The head transformation in the new frame.
*/
@Override
public void onNewFrame(HeadTransform headTransform) {
}
/**
* Draws a frame for an eye. The transformation for that eye (from the camera) is passed in as
* a parameter.
*
* @param transform The transformations to apply to render this eye.
*/
@Override
public void onDrawEye(EyeTransform transform) {
}
@Override
public void onFinishFrame(Viewport viewport) {
}
}
我注意到以下几点:
- 我不想要一个意图,我需要相机预览,以便以后我可以 用它做其他事情,比如拍照
- 如果我尝试用surfaceView替换imageView,我会在common_ui.xml中遇到一个错误“找不到渲染问题类:CardboardOverlayView.java”。但是文件就在那里,这是一个已知和报告的bug李>
- 我可以考虑的另一种方法是每秒捕获并保存图像,并用图像更新2个图像视图。然而我 我不确定这是不是正确的方法,或者怎么做
我希望问题足够详细。如果你需要更多信息,尽管问。基本上你需要将相机绘制成OpenGL纹理并显示纹理 我在这里编写了两个版本,可以随意修改代码并添加拉取请求:
我更新了@Mikle代码以与新的Google VR SDK配合使用:
我正在做这类任务,但没有取得成功。。你能帮帮我吗?我必须承认,我看不出有什么不同,但那个人也从来没有回答过:-(非常感谢您提供上述代码。我想替换touch上的图像。好的。我在Android Studio中导入了该项目。1.硬纸板项目非常有效,可以并排显示两个摄像头。2.OpenGL one显示了两个白色空白框,不启动摄像头,尽管logcat说“喵喵”…所以它没有崩溃..但必须看看到底是什么失败..总而言之,这是一个巨大的帮助,非常感谢。修复“2个白色空白框”有什么进展吗?@RudolfsJanitis我建议你使用纸板版,OpenGL版只是一个好玩的POC,不太成熟(基本上是“在我的机器上工作”级别)@Mikle但纸板版不是更慢吗?与OpenGL版本>>相比,纸板版上的视频操作如何?:)@RudolfsJanitis我不知道哪一个更慢,没有做基准测试。在我看来两者都不错。视频操作是什么意思?我添加了一些AR元素(我戴在摄像头识别的脸上的面具。FaceDetector)效果很好,但我没有在视频上尝试完全的效果。
package com.google.vrtoolkit.cardboard.samples.treasurehunt;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Vibrator;
import android.util.Log;
import android.widget.ImageView;
import com.google.vrtoolkit.cardboard.*;
import javax.microedition.khronos.egl.EGLConfig;
import java.nio.FloatBuffer;
/**
* A Cardboard sample application.
*/
public class MainActivity extends CardboardActivity implements CardboardView.StereoRenderer {
private static final int CAMERA_REQUEST = 1888;
private static final String TAG = "MainActivity";
private static final int CAPTURE_IMAGE_ACTIVITY_REQ = 0;
Uri fileUri = null;
ImageView photoImage = null;
private static final float CAMERA_Z = 0.01f;
private static final float TIME_DELTA = 0.3f;
private static final float YAW_LIMIT = 0.12f;
private static final float PITCH_LIMIT = 0.12f;
// We keep the light always position just above the user.
private final float[] mLightPosInWorldSpace = new float[]{0.0f, 2.0f, 0.0f, 1.0f};
private final float[] mLightPosInEyeSpace = new float[4];
private static final int COORDS_PER_VERTEX = 3;
private final WorldLayoutData DATA = new WorldLayoutData();
private FloatBuffer mFloorVertices;
private FloatBuffer mFloorColors;
private FloatBuffer mFloorNormals;
private FloatBuffer mCubeVertices;
private FloatBuffer mCubeColors;
private FloatBuffer mCubeFoundColors;
private FloatBuffer mCubeNormals;
private int mGlProgram;
private int mPositionParam;
private int mNormalParam;
private int mColorParam;
private int mModelViewProjectionParam;
private int mLightPosParam;
private int mModelViewParam;
private int mModelParam;
private int mIsFloorParam;
private float[] mModelCube;
private float[] mCamera;
private float[] mView;
private float[] mHeadView;
private float[] mModelViewProjection;
private float[] mModelView;
private float[] mModelFloor;
private int mScore = 0;
private float mObjectDistance = 12f;
private float mFloorDepth = 20f;
private Vibrator mVibrator;
private CardboardOverlayView mOverlayView;
public MainActivity() {
}
/**
* Sets the view to our CardboardView and initializes the transformation matrices we will use
* to render our scene.
* //@param savedInstanceState
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.common_ui);
CardboardView cardboardView = (CardboardView) findViewById(R.id.cardboard_view);
cardboardView.setRenderer(this);
setCardboardView(cardboardView);
mModelCube = new float[16];
mCamera = new float[16];
mView = new float[16];
mModelViewProjection = new float[16];
mModelView = new float[16];
mModelFloor = new float[16];
mHeadView = new float[16];
mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mOverlayView = (CardboardOverlayView) findViewById(R.id.overlay);
mOverlayView.show3DToast("Pull the magnet when you find an object.");
mOverlayView.show3DImage();
}
@Override
public void onRendererShutdown(){Log.i(TAG, "onRendererShutdown");
}
@Override
public void onSurfaceChanged(int width, int height) {
Log.i(TAG, "onSurfaceChanged");
}
/**
* Creates the buffers we use to store information about the 3D world. OpenGL doesn't use Java
* arrays, but rather needs data in a format it can understand. Hence we use ByteBuffers.
*
* @param config The EGL configuration used when creating the surface.
*/
@Override
public void onSurfaceCreated(EGLConfig config) {
Log.i(TAG, "onSurfaceCreated");
}
/**
* Prepares OpenGL ES before we draw a frame.
*
* @param headTransform The head transformation in the new frame.
*/
@Override
public void onNewFrame(HeadTransform headTransform) {
}
/**
* Draws a frame for an eye. The transformation for that eye (from the camera) is passed in as
* a parameter.
*
* @param transform The transformations to apply to render this eye.
*/
@Override
public void onDrawEye(EyeTransform transform) {
}
@Override
public void onFinishFrame(Viewport viewport) {
}
}