Superposición de imágenes en la vista previa de la cámara SurfaceView

Tengo un SurfaceView que se utiliza para dibujar imágenes, y me gustaría superponerlas a una transmisión en vivo desde la cámara del teléfono.

Actualmente, el SurfaceView que contiene las imágenes tiene un fondo blanco, pero si tuviera que superponerlas en la alimentación de la cámara del teléfono, tendrían que ser transparentes. La cámara y el dibujo de animación no se pueden hacer en el mismo SurfaceView .

¿Cuál es el mejor curso para utilizar múltiples vistas que implican administrar la cámara y dibujar imágenes? ¿Es posible hacer un SurfaceView transparente?

Bueno, así es como lo hice … Espero que alguien lo encuentre útil a pesar de que las cosas de Qualcomm AR estén fuera … podría ser obseleto … oh y básicamente lo que hace es generar dos cubos funky a partir de ese Ejemplo de Android, funcionalidad adicional se introducen los eventos táctiles, aunque los vectores rotacionales están apagados por mucho, solo para fines de demostración, y por supuesto, los cubos superpuestos en la parte superior de la vista previa de la cámara se pueden mover en una pantalla.

 public class TakeRecieptPicture extends Activity implements Callback { private Camera camera; private SurfaceView mSurfaceView; SurfaceHolder mSurfaceHolder; private TouchSurfaceView mGLSurfaceView; ShutterCallback shutter = new ShutterCallback(){ @Override public void onShutter() { // TODO Auto-generated method stub // No action to be perfomed on the Shutter callback. } }; PictureCallback raw = new PictureCallback(){ @Override public void onPictureTaken(byte[] data, Camera camera) { // TODO Auto-generated method stub // No action taken on the raw data. Only action taken on jpeg data. } }; PictureCallback jpeg = new PictureCallback(){ @Override public void onPictureTaken(byte[] data, Camera camera) { // TODO Auto-generated method stub FileOutputStream outStream = null; try{ outStream = new FileOutputStream("/sdcard/test.jpg"); outStream.write(data); outStream.close(); }catch(FileNotFoundException e){ Log.d("Camera", e.getMessage()); } catch (IOException e) { // TODO Auto-generated catch block Log.d("Camera", e.getMessage()); } } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); mGLSurfaceView = new TouchSurfaceView(this); addContentView(mGLSurfaceView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); mSurfaceView = new SurfaceView(this); addContentView(mSurfaceView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT)); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT|LayoutParams.FLAG_BLUR_BEHIND); } private void takePicture() { // TODO Auto-generated method stub camera.takePicture(shutter, raw, jpeg); } @Override public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { // TODO Auto-generated method stub Camera.Parameters p = camera.getParameters(); p.setPreviewSize(arg2, arg3); try { camera.setPreviewDisplay(arg0); } catch (IOException e) { e.printStackTrace(); } camera.startPreview(); } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub camera = Camera.open(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { // TODO Auto-generated method stub camera.stopPreview(); camera.release(); } } 

TouchSurfaceView se define a continuación:

 class TouchSurfaceView extends GLSurfaceView { public TouchSurfaceView(Context context) { super(context); cr = new CubeRenderer(true); this.setEGLConfigChooser(8, 8, 8, 8, 16, 0); this.setRenderer(cr); this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); this.getHolder().setFormat(PixelFormat.TRANSPARENT); } public boolean onTrackballEvent(MotionEvent e) { cr.mAngleX += e.getX() * TRACKBALL_SCALE_FACTOR; cr.mAngleY += e.getY() * TRACKBALL_SCALE_FACTOR; requestRender(); return true; } @Override public boolean onTouchEvent(MotionEvent e) { float x = e.getX(); float y = e.getY(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dx = x - mPreviousX; float dy = y - mPreviousY; cr.mAngleX += dx * TOUCH_SCALE_FACTOR; cr.mAngleY += dy * TOUCH_SCALE_FACTOR; requestRender(); } mPreviousX = x; mPreviousY = y; return true; } private final float TOUCH_SCALE_FACTOR = 180.0f / 320; private final float TRACKBALL_SCALE_FACTOR = 36.0f; public CubeRenderer cr ; private float mPreviousX; private float mPreviousY; } 

Y el CubeRenderer está dado por:

 class CubeRenderer implements GLSurfaceView.Renderer { public CubeRenderer(boolean useTranslucentBackground) { mTranslucentBackground = useTranslucentBackground; mCube = new Cube(); } public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0, 0, -5.0f); gl.glRotatef(mAngle, 0, 1, 0); gl.glRotatef(mAngle*0.25f, 1, 0, 0); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); mCube.draw(gl); gl.glRotatef(mAngle*2.0f, 0, 1, 1); gl.glTranslatef(0.5f, 0.5f, 0.5f); mCube.draw(gl); mAngle += 1.2f; } public void onSurfaceChanged(GL10 gl, int width, int height) { gl.glViewport(0, 0, width, height); float ratio = (float) width / height; gl.glMatrixMode(GL10.GL_PROJECTION); gl.glLoadIdentity(); gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { gl.glDisable(GL10.GL_DITHER); gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST); if (mTranslucentBackground) { gl.glClearColor(0,0,0,0); } else { gl.glClearColor(1,1,1,1); } gl.glEnable(GL10.GL_CULL_FACE); gl.glShadeModel(GL10.GL_SMOOTH); gl.glEnable(GL10.GL_DEPTH_TEST); } public void setAngle(float _angle){ } private boolean mTranslucentBackground; private Cube mCube; private float mAngle; public float mAngleX; public float mAngleY; } 

Y finalmente, el Cubo mismo está dado por:

 class Cube{ public Cube() { int one = 0x10000; int vertices[] = { -one, -one, -one, one, -one, -one, one, one, -one, -one, one, -one, -one, -one, one, one, -one, one, one, one, one, -one, one, one, }; float[] colors = { 0f, 0f, 0f, 0.5f, 1f , 0f, 0f, 0.1f, 1f,1f,0f,0.5f, 0f, 1f, 0f, 0.1f, 0f, 0f, 1f, 0.1f, 1f, 0f, 1f, 0.2f, 1f, 1f, 1f, 0.1f, 0f, 1f, 1f, 0.1f, }; byte indices[] = { 0, 4, 5, 0, 5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 3, 7, 4, 3, 4, 0, 4, 7, 6, 4, 6, 5, 3, 0, 1, 3, 1, 2 }; ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4); vbb.order(ByteOrder.nativeOrder()); mVertexBuffer = vbb.asIntBuffer(); mVertexBuffer.put(vertices); mVertexBuffer.position(0); ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4); cbb.order(ByteOrder.nativeOrder()); mColorBuffer = cbb.asFloatBuffer(); mColorBuffer.put(colors); mColorBuffer.position(0); mIndexBuffer = ByteBuffer.allocateDirect(indices.length); mIndexBuffer.put(indices); mIndexBuffer.position(0); } public void draw(GL10 gl) { gl.glFrontFace(gl.GL_CW); gl.glVertexPointer(3, gl.GL_FIXED, 0, mVertexBuffer); gl.glColorPointer(4, gl.GL_FIXED, 0, mColorBuffer); gl.glDrawElements(gl.GL_TRIANGLES, 36, gl.GL_UNSIGNED_BYTE, mIndexBuffer); } private IntBuffer mVertexBuffer; private FloatBuffer mColorBuffer; private ByteBuffer mIndexBuffer; } 

Bueno, espero que alguien lo encuentre útil …

También estoy haciendo una aplicación aumentada y golpeo el mismo problema que golpeaste. Hay muy poca información sobre cómo resolverlo correctamente. Pero encontré un framework llamado mixare , que te permite crear aplicaciones AR para Android. Definitivamente deberías mirar su origen , parece bastante prometedor. Espero que esto te ayudará.

He tenido éxito con el siguiente enfoque.

Primero haga un archivo xml de diseño que se vea de la siguiente manera (observe el orden de las dos vistas):

       

OverlayView es una subclase de SurfaceView con las implementaciones de hilos de dibujo y animación. El otro SurfaceView será la superficie que maneja la vista previa de la cámara. Dentro de onCreate debes configurar tus vistas de esta manera:

  mView = (OverlayView)this.findViewById(R.id.overlay); mView.getHolder().setFormat(PixelFormat.TRANSLUCENT); mSurfaceView = (SurfaceView)this.findViewById(R.id.surface); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.addCallback(this); mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 

Debería agregar una implementación de SurfaceHolder al SurfaceHolder de mView que maneja el hilo de la animación. Un ejemplo de cómo implementar esto dentro de la subclase y usar animación / hilos de dibujo se puede encontrar en el antiguo ejemplo de LunarLander aquí: http://developer.android.com/resources/samples/LunarLander/src/com/example/android/lunarlander/ LunarView.html

Además de configurar la cámara SurfaceView de la misma manera que en este ejemplo: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html

¿ Este código ayuda?

Acabo de encontrar una réplica levemente extraña de actualizar mi teléfono a 4.0.4. Tengo una superposición translúcida de pantalla completa en una vista previa de la cámara de pantalla completa, que funcionó bastante bien en una versión anterior de ics (creo que era 4.0.3, pero no es cierto). Después de actualizar a 4.0.4, la vista previa se volvió un poco desconcertante, con la imagen de la cámara mostrando áreas de color primarias psicodélicas en cualquiera de las partes más shinys de la imagen de la cámara (las partes más oscuras parecían estar bien). Finalmente se encontró que el cambio de glclearcolour a 0,0,0,0 de 0.5, 0.5, 0.5. 0 lo resolvió.

Parece que a pesar de que el alfa era cero en las partes no utilizadas de la superposición de gl, la función de fusión seguía teniendo en cuenta el fondo gris gl.