Android 将图像叠加到相机预览 SurfaceView
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3548666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Overlay images onto Camera preview SurfaceView
提问by GobiasKoffi
I have a SurfaceView
that is being used to draw images, and I would like to overlay them onto a live-feed from the phone's camera.
我有一个SurfaceView
用于绘制图像的图像,我想将它们叠加到手机摄像头的实时馈送上。
Currently, the SurfaceView
that contains the images have a white-background, but if I were to overlay them onto the phone's camera feed, they would have to be transparent. The camera and animation drawing cannot be done on the same SurfaceView
.
目前,SurfaceView
包含图像的 具有白色背景,但如果我要将它们叠加到手机的相机源上,它们必须是透明的。相机和动画绘制不能在同一个SurfaceView
.
What is the best course to pursue the use of multiple views that involve managing the camera and drawing images? Is it possible to make a SurfaceView
transparent?
追求使用涉及管理相机和绘制图像的多个视图的最佳方法是什么?能不能做成SurfaceView
透明的?
回答by bala singareddy
Well here's how I did it ... I hope somebody finds it useful though the Qualcomm AR stuff is out.. it might be obselete.. oh and basically what this does is -- generate two funky cubes from that Android Example, additional functionality introduced are the touch events, though the rotational vectors are off by a lot-- just for a demonstration purpose anyway and ofcourse the cubes overlaid on top of the camera preview which can be moved on a screen..
好吧,这就是我是怎么做的......我希望有人发现它有用,尽管 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();
}
}
The TouchSurfaceView is defined below:
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;
}
And the CubeRenderer is given by:
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;
}
And finally the Cube itself is given by:
最后,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;
}
Well hope somebody finds this useful...
好吧,希望有人觉得这很有用......
回答by matekm
I'm doing augmented application too and hit the same problem you hit. There is very few information on how to solve it right. But I found a framework called mixare- it allow you to create AR app for android. You should definitely look at it source- it looks pretty promising. Hope this will help you.
我也在做增强应用程序,并遇到了您遇到的相同问题。关于如何正确解决它的信息很少。但是我找到了一个叫做mixare的框架——它允许你为 android 创建 AR 应用程序。你绝对应该看看它的来源- 它看起来很有希望。希望这会帮助你。
回答by Frank
I have had success with the following approach.
我通过以下方法取得了成功。
First make a layout xml file that looks something like this (note the order of the two views):
首先制作一个布局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
is a subclass of SurfaceView
with the drawing and animation thread implementations. The other SurfaceView will be the surface that handles the Camera preview. Inside of onCreate
you should set up your views like this:
OverlayView
是SurfaceView
具有绘图和动画线程实现的子类。另一个 SurfaceView 将是处理相机预览的表面。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);
You should add a SurfaceHolder.Callback
implementation to the SurfaceHolder
of mView
that handles the animation thread. An example of implementing this within the subclass and using animation/drawing threads can be found in the old LunarLander example here:
http://developer.android.com/resources/samples/LunarLander/src/com/example/android/lunarlander/LunarView.html
您应该添加SurfaceHolder.Callback
实现到SurfaceHolder
的mView
是手柄动画线程。可以在此处的旧 LunarLander 示例中找到在子类中实现此功能并使用动画/绘图线程的示例:http:
//developer.android.com/resources/samples/LunarLander/src/com/example/android/lunarlander/ LunarView.html
Besides that you set up the camera SurfaceView the same way as this example: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
除此之外,您以与此示例相同的方式设置相机 SurfaceView:http: //developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
回答by pootle
Just found a slightly strange aftershock from upgrading my handset to 4.0.4. I have a translucent gl whole screen overlay on a whole screen camera preview, which worked quite happily on an earlier ics build (I think it was 4.0.3, but not certain). After upgrading to 4.0.4, the preview went a bit haywire, with the camera image showing psychedelic primary areas of colour on any of the brighter parts of the camera image (darker parts looked OK). Eventually found that changing glclearcolour to 0,0,0,0 from 0.5, 0.5, 0.5. 0 sorted it out.
刚刚发现我的手机升级到4.0.4后有一点奇怪的余震。我在全屏相机预览上有一个半透明的 gl 全屏覆盖,它在早期的 ics 版本上运行得非常愉快(我认为它是 4.0.3,但不确定)。升级到 4.0.4 后,预览有点混乱,相机图像在相机图像的任何较亮部分(较暗的部分看起来不错)上显示出迷幻的主要颜色区域。最终发现将glclearcolour从0.5、0.5、0.5改为0,0,0,0。0 整理出来了。
It seems that even though the alpha was zero on the unused parts of the gl overlay, the blending function was still taking account of the grey gl background.
似乎即使 gl 叠加层未使用部分的 alpha 为零,混合功能仍在考虑灰色 gl 背景。