将图像叠加到相机预览SurfaceView上

时间:2010-08-23 14:48:51

标签: android graphics camera surfaceview

我有SurfaceView用于绘制图像,我想将它们叠加到手机相机的实时信息中。

目前,包含图片的SurfaceView具有白色背景,但如果我将它们叠加到手机的相机Feed上,则必须是透明的。相机和动画绘图无法在同一SurfaceView上完成。

使用涉及管理相机和绘制图像的多个视图的最佳方法是什么?是否可以使SurfaceView透明?

5 个答案:

答案 0 :(得分:20)

嗯,这就是我如何做到的......我希望有人发现虽然Qualcomm AR的东西已经出来了但它很有用..它可能很有用...... 哦,基本上它的作用是 - 从Android示例生成两个时髦的立方体,引入的附加功能是触摸事件,虽然旋转矢量很多 - 只是为了演示目的而且当然立方体覆盖在顶部可以在屏幕上移动的相机预览...

 

     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定义如下:


   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;


}

CubeRenderer由:

给出    

    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;

}
   

最后Cube本身由:

给出    

    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;

    }
   

希望有人觉得这很有用......

答案 1 :(得分:6)

我也在做增强型应用程序,并遇到了同样的问题。关于如何正确解决问题的信息非常少。但是我找到了一个名为 mixare 的框架 - 它允许你为Android创建AR应用程序。你一定要看它source - 看起来很有前途。希望这会对你有所帮助。

答案 2 :(得分:6)

我使用以下方法取得了成功。

首先制作一个看起来像这样的布局xml文件(注意两个视图的顺序):

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

OverlayViewSurfaceView的子类,带有绘图和动画线程实现。另一个SurfaceView将是处理Camera预览的表面。在onCreate内,你应该像这样设置你的观点:

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

您应该将SurfaceHolder.Callback实现添加到处理动画线程的SurfaceHolder mView。在子类中实现它并使用动画/绘图线程的示例可以在这里的旧LunarLander示例中找到: http://developer.android.com/resources/samples/LunarLander/src/com/example/android/lunarlander/LunarView.html

除此之外,您以与此示例相同的方式设置相机SurfaceView: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html

答案 3 :(得分:1)

MIght this code有帮助吗?`

答案 4 :(得分:0)

刚从手机升级到4.0.4时发现了一个稍微奇怪的余震。我在整个屏幕相机预览上有一个半透明的gl整个屏幕叠加,它在早期的ics构建中非常愉快地工作(我认为它是4.0.3,但不确定)。升级到4.0.4后,预览变得有点乱,相机图像在相机图像的任何较亮部分显示迷幻的主要颜色区域(较暗的部分看起来不错)。最终发现将glclearcolour从0.5,0.5,0.5改为0,0,0,0。 0整理出来。

似乎即使在gl叠加层的未使用部分上alpha为零,混合功能仍然考虑了灰色gl背景。