Наложение изображений на камеру Предварительный просмотр SurfaceView
У меня есть SurfaceView
это используется для рисования изображений, и я хотел бы наложить их на прямую трансляцию с камеры телефона.
В настоящее время SurfaceView
которые содержат изображения, имеют белый фон, но если бы я наложил их на канал камеры телефона, они должны быть прозрачными. Камера и анимация не могут быть выполнены на одном и том же SurfaceView
,
Как лучше всего использовать несколько видов, которые включают управление камерой и рисование изображений? Можно ли сделать SurfaceView
прозрачный?
5 ответов
Ну, вот как я это сделал... Я надеюсь, что кто-то найдет это полезным, хотя материал 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;
}
И, наконец, сам куб определяется как:
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;
}
Надеюсь, кто-нибудь найдет это полезным
Я тоже делаю дополненное приложение и сталкиваюсь с той же проблемой, что и вы. Существует очень мало информации о том, как решить это правильно. Но я нашел фреймворк, который называется mixare - он позволяет вам создавать AR-приложения для Android. Обязательно посмотрите на него источник - он выглядит довольно многообещающе. Надеюсь, что это поможет вам.
У меня был успех со следующим подходом.
Сначала создайте 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
с реализациями потоков рисования и анимации. Другой 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);
Вы должны добавить 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
Просто нашел немного странный афтершок от обновления моего телефона до 4.0.4. У меня есть полупрозрачное наложение экрана на весь экран для предварительного просмотра камеры на весь экран, которое довольно хорошо работало на ранней сборке ics (я думаю, что это 4.0.3, но не уверен). После обновления до 4.0.4 предварительный просмотр стал немного медленным: изображение с камеры отображало психоделические основные области цвета на любой из более ярких частей изображения с камеры (более темные части выглядели нормально). В итоге установлено, что изменяется glclearcolour до 0,0,0,0 с 0,5, 0,5, 0,5. 0 разобрался.
Кажется, что даже при том, что альфа был нулевым на неиспользованных частях наложения gl, функция смешивания все еще учитывала серый фон gl.