将图像叠加到相机预览SurfaceView上
我有一个用于绘制图像的SurfaceView
,我想将它们叠加到手机相机的实时反馈上。
目前,包含图像的SurfaceView
有一个白色背景,但如果我将它们覆盖到手机的摄像头上,它们必须是透明的。 相机和animation绘图不能在同一个SurfaceView
。
追求使用涉及pipe理相机和绘制图像的多个视图的最佳方法是什么? 是否有可能使SurfaceView
透明?
那么我就是这样做的…我希望有人认为它是有用的,虽然高通AR的东西已经出来..它可能obselete ..哦,基本上这是做什么 – 从该Android示例生成两个时髦的多维数据集,附加function介绍的是触摸事件,虽然旋转vector是非常多的 – 只是为了演示的目的,而且当然立方体覆盖在相机预览的顶部,可以在屏幕上移动。
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; }
最后立方体本身是由:
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; }
那么希望有人认为这有用…
我也在做扩展的应用程序,并遇到同样的问题,你打。 很less有关于如何正确解决的信息。 但是我发现了一个名为mixare的框架 – 它允许您为android创buildAR应用程序。 你一定要看看它的来源 – 它看起来很有希望。 希望这会帮助你。
我用以下方法取得了成功。
首先制作一个看起来像这样的布局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>
OverlayView
是SurfaceView
的子类,具有绘图和animation线程的实现。 另一个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
实现添加到处理animation线程的SurfaceHolder
的mView
中。 一个在子类中使用animation/绘图线程的例子可以在这里的旧LunarLander例子中find: 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
这个代码很好吗?`
刚刚发现一个奇怪的余震,从我的手机升级到4.0.4。 我在整个屏幕相机预览上覆盖了一个半透明的gl全屏,在早期的ics build(我认为它是4.0.3,但不是确定的)上工作得非常愉快。 升级到4.0.4之后,预览有些失常,相机图像在相机图像的任何较亮的部分显示迷幻的主要颜色区域(较暗的部分看起来确定)。 最终发现,从0.5,0.5,0.5改变glclearcolour为0,0,0,0。 0整理出来。
看起来,尽pipegl覆盖图的未使用部分上的alpha值为零,但是混合函数仍然考虑了灰色gl背景。