J'ai une SurfaceView
qui est utilisée pour dessiner des images et j'aimerais les superposer à un flux en direct de la caméra du téléphone.
Actuellement, la SurfaceView
contenant les images a un fond blanc, mais si je les superposais dans le flux de caméra du téléphone, elles devraient être transparentes. Le dessin de la caméra et de l'animation ne peut pas être fait sur la même SurfaceView
.
Quelle est la meilleure voie à suivre pour utiliser plusieurs vues impliquant la gestion de la caméra et le dessin des images? Est-il possible de rendre une SurfaceView
transparente?
Eh bien voici comment je l'ai fait ... J'espère que quelqu'un trouvera cela utile même si le contenu de Qualcomm AR est sorti .. il pourrait être obsolète .. Oh et en gros, cela produit - générer deux cubes géniaux à partir de cet exemple Android , les fonctionnalités tactiles supplémentaires sont introduites dans les événements tactiles, bien que les vecteurs de rotation soient souvent désactivés - juste à des fins de démonstration et les cubes superposés au-dessus de l’aperçu de la caméra pouvant ê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é 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;
}
Espérons que quelqu'un trouve cela utile ...
Je fais aussi une application augmentée et je rencontre le même problème que vous. Il y a très peu d'informations sur la façon de le résoudre correctement. Mais j'ai trouvé un framework appelé mixare - il vous permet de créer une application AR pour Android. Vous devriez certainement le regarder source - il semble assez prometteur. J'espère que ceci vous aidera.
J'ai eu du succès avec l'approche suivante.
Commencez par créer un fichier XML de mise en page qui ressemble à ceci (notez l’ordre des deux vues):
<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. Dans onCreate
, vous devriez configurer vos vues de la manière suivante:
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 implémentation SurfaceHolder.Callback
à la SurfaceHolder
de mView
qui gère le fil d'animation. Un exemple d'implémentation de ceci dans la sous-classe et d'utilisation de fils d'animation/de dessin peut être trouvé dans l'ancien exemple de LunarLander ici: http://developer.Android.com/resources/samples/LunarLander/src/com/example /Android/lunarlander/LunarView.html
En outre, vous configurez la caméra SurfaceView de la même manière que dans cet exemple: http://developer.Android.com/resources/samples/ApiDemos/src/com/example/Android/apis/graphics/CameraPreview. html
Might ce code help?
Je viens de trouver une réplique légèrement étrange de la mise à niveau de mon téléphone à la version 4.0.4. J'ai un fond d'écran gl entier translucide sur un aperçu de la caméra à l'écran, ce qui a fonctionné assez bien sur une version antérieure 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 a été un peu défoncée, l’image de la caméra montrant des zones primaires de couleurs psychédéliques sur l’une des parties les plus claires de l’image de la caméra (les parties plus sombres semblaient correctes). Finalement, nous avons trouvé que changer la couleur de glclear en 0,0,0,0 de 0,5, 0,5, 0,5. 0 trié.
Il semble que même si l'alpha était égal à zéro sur les parties non utilisées de la superposition de gl, la fonction de fusion tenait toujours compte de l'arrière-plan gris.