2010-08-23 14 views
31

J'ai un SurfaceView qui est utilisé pour dessiner des images, et je voudrais les superposer sur un flux en direct à partir de l'appareil photo du téléphone.Superposition d'images sur l'aperçu de la caméra SurfaceView

Actuellement, le SurfaceView qui contient les images a un arrière-plan blanc, mais si je devais les superposer sur l'alimentation de caméra du téléphone, elles devraient être transparentes. La caméra et le dessin d'animation ne peuvent pas être réalisés sur le même SurfaceView.

Quel est le meilleur moyen de poursuivre l'utilisation de plusieurs vues impliquant la gestion de la caméra et le dessin d'images? Est-il possible de faire un SurfaceView transparent?

Répondre

1

POURRIEZ this code aide? `

+0

Ma classe DrawonTop étend également SurfaceView et implémente l'interface SurfaceHolder.Callback. Pensez-vous que cela me causera des problèmes si j'essaie de le superposer sur l'aperçu de la caméra? J'ai lu que SurfaceViews ne peut pas être transparent, mais je me demande si c'est juste un tas de foutaises. – GobiasKoffi

+0

En plus de cela, la classe DrawOnTop ne doit-elle pas être appelée dans une sorte d'UIthread? Ce n'est pas fait dans l'exemple que vous avez suggéré. – GobiasKoffi

+0

Le lien ne fonctionne plus. –

6

que je fais l'application augmentée trop et a frappé le même problème que vous frappez. Il y a très peu d'informations sur la façon de le résoudre correctement. Mais j'ai trouvé un cadre appelé mixare - il vous permet de créer une application AR pour Android. Vous devriez certainement le regarder source - il semble très prometteur. J'espère que ceci vous aidera.

5

J'ai eu du succès avec l'approche suivante.

d'abord un fichier xml de mise en page qui ressemble à ceci (notez l'ordre des deux points de vue):

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" android:layout_height="fill_parent" 
    android:orientation="vertical"> 

    <com.yourcustom.OverlayView 
     android:id="@+id/overlay" android:layout_width="fill_parent" 
     android:layout_height="fill_parent"> 
    </com.yourcustom.OverlayView> 

    <SurfaceView android:id="@+id/surface" 
     android:layout_width="fill_parent" android:layout_height="fill_parent"> 
    </SurfaceView> 

</FrameLayout> 

OverlayView est une sous-classe de SurfaceView avec les implémentations de fil de dessin et d'animation. L'autre SurfaceView sera la surface qui gère l'aperçu de la caméra. A l'intérieur de onCreate vous devez configurer votre point de vue comme celui-ci:

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); 

Vous devez ajouter une mise en œuvre SurfaceHolder.Callback au SurfaceHolder de mView qui gère le fil d'animation. Un exemple de mise en œuvre de cela dans la sous-classe et l'utilisation de threads animation/dessin se trouve dans l'ancien exemple LunarLander ici: http://developer.android.com/resources/samples/LunarLander/src/com/example/android/lunarlander/LunarView.html

plus que vous configurez la caméra SurfaceView la même manière que cet exemple: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html

+0

vous oubliez de fermer

+4

Ceci est faux car com.yourcustom.OverlayView doit être le deuxième dans le Framelayout afin d'être sur le dessus ... – Lumis

20

Eh bien, voici comment je l'ai fait ... J'espère que quelqu'un le trouve utile si le Qualcomm AR est sorti .. il peut être obsolète .. oh et fondamentalement ce que cela fait est - générer deux cubes funky de cet exemple Android, les fonctionnalités supplémentaires introduites sont les événements tactiles, bien que les vecteurs de rotation soient très éloignés - juste dans un but de démonstration de toute façon et bien sûr les cubes superposés au-dessus de l'aperçu de la caméra qui peut être déplacé sur un écran ..


    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(); 
    } 
    } 

Le TouchSurfaceView est défini ci-dessous:


    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; 


} 

Et le CubeRenderer est donnée par:


    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; 

} 

Et enfin le cube lui-même est donné par:


    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; 

    } 

Eh bien, espérons que quelqu'un trouve cela utile ...

+1

+ 1 réponse de travail complète. – Behnam

+0

comment puis-je changer l'angle de la caméra? sa rotation à -90degrees maintenant.merci beaucoup – onexf

0

Je viens de trouver une réplique un peu étrange de la mise à niveau de mon combiné à 4.0.4. J'ai un écran translucide tout en superposition sur un aperçu de la caméra à l'écran, ce qui a fonctionné assez bien sur une version précédente de ics (je pense que c'était 4.0.3, mais pas certain). Après la mise à niveau vers la version 4.0.4, la prévisualisation s'est un peu détraquée, l'image de la caméra montrant des zones de couleur primaires psychédéliques sur l'une des parties les plus lumineuses de l'image de la caméra (les parties sombres semblaient correctes). Finalement trouvé que changer glclearcolour à 0,0,0,0 de 0,5, 0,5, 0,5. 0 trié.

Il semble que même si l'alpha était nul sur les parties inutilisées de la superposition gl, la fonction de fusion tenait toujours compte du fond gris gl.