如何在Android中组合叠加位图和捕获的图像?

时间:2015-10-26 17:35:44

标签: android bitmap android-camera surfaceview android-bitmap

我要求我需要创建自定义相机并允许用户在捕获图像时放置徽标。徽标可以放大/缩小,并可在任何地方的摄像机视图中移动。我已经编写了以下代码来执行此操作,我能够成功放大/缩小并移动徽标图像,但是当我将从相机拍摄的徽标和图片组合时,它没有正确组合。徽标图像放置在不同的位置,它的大小减少了。请有人帮助我,因为我已经被困在这里,无法找到问题所在。我还附上了手机中的截图供参考。请检查一下。

在点击捕捉按钮之前,我已将徽标移至左下角

enter image description here

点击捕获按钮后,两个图像组合如下。

enter image description here

public class CustomCamera extends Activity implements OnTouchListener,
    SurfaceHolder.Callback {

private Matrix matrix = new Matrix();
private Matrix savedMatrix = new Matrix();
private static final int NONE = 0;
private static final int DRAG = 1;
private static final int ZOOM = 2;
private int mode = NONE;
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float d = 0f;
private float newRot = 0f;
private float[] lastEvent = null;
String logoImageId = "";
Bitmap bitmap = null;
private Camera camera = null;
private SurfaceView cameraSurfaceView = null;
private SurfaceHolder cameraSurfaceHolder = null;
private boolean previewing = false;
RelativeLayout relativeLayout;
int currentCameraId = 0;
private Button btnCapture = null;
ImageButton useOtherCamera = null;
ImageView logoImageView;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().setFormat(PixelFormat.TRANSLUCENT);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);

    setContentView(R.layout.camera_layout);
    logoImageView = (ImageView) findViewById(R.id.logoImageView);
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        logoImageId = extras.getString("logoImageId ");
    }
    try {
        File file = new File(Environment.getExternalStorageDirectory()
                + "/" + getPackageName() + "/logo/" + logoImageId 
                + ".jpg");
        bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    logoImageView.setImageBitmap(bitmap);
    logoImageView.setOnTouchListener(this);
    relativeLayout = (RelativeLayout) findViewById(R.id.containerImg);
    relativeLayout.setDrawingCacheEnabled(true);
    cameraSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
    cameraSurfaceHolder = cameraSurfaceView.getHolder();
    cameraSurfaceHolder.addCallback(this);
    btnCapture = (Button) findViewById(R.id.button);
    btnCapture.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            camera.takePicture(null, null, cameraPictureCallbackJpeg);
        }
    });

}

public boolean onTouch(View v, MotionEvent event) {
    // handle touch events here
    ImageView view = (ImageView) v;
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        savedMatrix.set(matrix);
        start.set(event.getX(), event.getY());
        mode = DRAG;
        lastEvent = null;
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        oldDist = spacing(event);
        if (oldDist > 10f) {
            savedMatrix.set(matrix);
            midPoint(mid, event);
            mode = ZOOM;
        }
        lastEvent = new float[4];
        lastEvent[0] = event.getX(0);
        lastEvent[1] = event.getX(1);
        lastEvent[2] = event.getY(0);
        lastEvent[3] = event.getY(1);
        d = rotation(event);
        break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_POINTER_UP:
        mode = NONE;
        lastEvent = null;
        break;
    case MotionEvent.ACTION_MOVE:
        if (mode == DRAG) {
            matrix.set(savedMatrix);
            float dx = event.getX() - start.x;
            float dy = event.getY() - start.y;
            matrix.postTranslate(dx, dy);
        } else if (mode == ZOOM) {
            float newDist = spacing(event);
            if (newDist > 10f) {
                matrix.set(savedMatrix);
                float scale = (newDist / oldDist);
                matrix.postScale(scale, scale, mid.x, mid.y);
            }
            if (lastEvent != null && event.getPointerCount() == 3) {
                newRot = rotation(event);
                float r = newRot - d;
                float[] values = new float[9];
                matrix.getValues(values);
                float tx = values[2];
                float ty = values[5];
                float sx = values[0];
                float xc = (view.getWidth() / 2) * sx;
                float yc = (view.getHeight() / 2) * sx;
                matrix.postRotate(r, tx + xc, ty + yc);
            }
        }
        break;
    }

    view.setImageMatrix(matrix);

    return true;
}

/**
 * Determine the space between the first two fingers
 */
private float spacing(MotionEvent event) {
    float x = event.getX(0) - event.getX(1);
    float y = event.getY(0) - event.getY(1);
    return FloatMath.sqrt(x * x + y * y);
}

/**
 * Calculate the mid point of the first two fingers
 */
private void midPoint(PointF point, MotionEvent event) {
    float x = event.getX(0) + event.getX(1);
    float y = event.getY(0) + event.getY(1);
    point.set(x / 2, y / 2);
}

/**
 * Calculate the degree to be rotated by.
 * 
 * @param event
 * @return Degrees
 */
private float rotation(MotionEvent event) {
    double delta_x = (event.getX(0) - event.getX(1));
    double delta_y = (event.getY(0) - event.getY(1));
    double radians = Math.atan2(delta_y, delta_x);
    return (float) Math.toDegrees(radians);
}

PictureCallback cameraPictureCallbackJpeg = new PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        // TODO Auto-generated method stub
        Bitmap cameraBitmap = BitmapFactory.decodeByteArray(data, 0,
                data.length);

        int wid = cameraBitmap.getWidth();
        int hgt = cameraBitmap.getHeight();

        Bitmap newBitmap = Bitmap.createBitmap(wid, hgt,
                Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(newBitmap);
        canvas.drawBitmap(cameraBitmap, 0f, 0f, null);
        canvas.drawBitmap(bitmap, matrix, null);

        File storagePath = new File(
                Environment.getExternalStorageDirectory() + "/PhotoAR/");
        storagePath.mkdirs();

        File myImage = new File(storagePath, Long.toString(System
                .currentTimeMillis()) + ".jpg");

        try {
            FileOutputStream out = new FileOutputStream(myImage);
            newBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);

            out.flush();
            out.close();
        } catch (FileNotFoundException e) {
            Log.d("In Saving File", e + "");
        } catch (IOException e) {
            Log.d("In Saving File", e + "");
        }

    }
};

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    // TODO Auto-generated method stub

    if (previewing) {
        camera.stopPreview();
        previewing = false;
    }
    try {

        if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
            camera.setDisplayOrientation(90);
        }

        camera.setPreviewDisplay(cameraSurfaceHolder);
        camera.startPreview();
        previewing = true;
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    try {
        camera = Camera.open();
    } catch (RuntimeException e) {
        Toast.makeText(
                getApplicationContext(),
                "Device camera  is not working properly, please try after sometime.",
                Toast.LENGTH_LONG).show();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO Auto-generated method stub
    camera.stopPreview();
    camera.release();
    camera = null;
    previewing = false;
}

}

这是我的xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<RelativeLayout
    android:id="@+id/containerImg"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />

    <ImageView
        android:id="@+id/logoImageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:contentDescription="@string/app_name"
        android:scaleType="matrix" />
</RelativeLayout>

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="right|center_vertical"
    android:background="@drawable/camera" />

提前致谢。

3 个答案:

答案 0 :(得分:3)

好的,有几件事需要解决

  1. 为表面视图设置正确的尺寸,用于相机的尺寸
  2. 根据屏幕方向旋转捕获的位图
  3. 你的代码将出现内存错误,因为你正在加载它直接内存并且不回收(这个我不会修复你会找到答案,如果你谷歌:)提示:搜索injustdecodebounds和回收位图)< / LI>

    我知道你想看到工作代码,所以你去了:

        public class CameraActivity extends FragmentActivity implements OnTouchListener,
            SurfaceHolder.Callback {
    
        private Matrix matrix = new Matrix();
        private Matrix savedMatrix = new Matrix();
        private static final int NONE = 0;
        private static final int DRAG = 1;
        private static final int ZOOM = 2;
        private int mode = NONE;
        private PointF start = new PointF();
        private PointF mid = new PointF();
        private float oldDist = 1f;
        private float d = 0f;
        private float newRot = 0f;
        private float[] lastEvent = null;
        String logoImageId = "";
        Bitmap bitmap = null;
        private Camera camera = null;
        private SurfaceView cameraSurfaceView = null;
        private SurfaceHolder cameraSurfaceHolder = null;
        private boolean previewing = false;
        RelativeLayout relativeLayout;
        int currentCameraId = 0;
        private Button btnCapture = null;
        ImageButton useOtherCamera = null;
        ImageView logoImageView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
    
            getWindow().setFormat(PixelFormat.TRANSLUCENT);
            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
    
            setContentView(R.layout.activity_camera);
            logoImageView = (ImageView) findViewById(R.id.logoImageView);
            Bundle extras = getIntent().getExtras();
            if (extras != null) {
                logoImageId = extras.getString("logoImageId ");
            }
            try {
                /*File file = new File(Environment.getExternalStorageDirectory()
                        + "/" + getPackageName() + "/logo/" + logoImageId
                        + ".jpg");
                bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());*/
                bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
                logoImageView.setImageBitmap(bitmap);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            logoImageView.setOnTouchListener(this);
            relativeLayout = (RelativeLayout) findViewById(R.id.containerImg);
            relativeLayout.setDrawingCacheEnabled(true);
            cameraSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
            cameraSurfaceHolder = cameraSurfaceView.getHolder();
            cameraSurfaceHolder.addCallback(this);
            btnCapture = (Button) findViewById(R.id.button);
            btnCapture.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                    camera.takePicture(null, null, cameraPictureCallbackJpeg);
                }
            });
    
        }
    
        public boolean onTouch(View v, MotionEvent event) {
            // handle touch events here
            ImageView view = (ImageView) v;
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    savedMatrix.set(matrix);
                    start.set(event.getX(), event.getY());
                    mode = DRAG;
                    lastEvent = null;
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    oldDist = spacing(event);
                    if (oldDist > 10f) {
                        savedMatrix.set(matrix);
                        midPoint(mid, event);
                        mode = ZOOM;
                    }
                    lastEvent = new float[4];
                    lastEvent[0] = event.getX(0);
                    lastEvent[1] = event.getX(1);
                    lastEvent[2] = event.getY(0);
                    lastEvent[3] = event.getY(1);
                    d = rotation(event);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mode = NONE;
                    lastEvent = null;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mode == DRAG) {
                        matrix.set(savedMatrix);
                        float dx = event.getX() - start.x;
                        float dy = event.getY() - start.y;
                        matrix.postTranslate(dx, dy);
                    } else if (mode == ZOOM) {
                        float newDist = spacing(event);
                        if (newDist > 10f) {
                            matrix.set(savedMatrix);
                            float scale = (newDist / oldDist);
                            matrix.postScale(scale, scale, mid.x, mid.y);
                        }
                        if (lastEvent != null && event.getPointerCount() == 3) {
                            newRot = rotation(event);
                            float r = newRot - d;
                            float[] values = new float[9];
                            matrix.getValues(values);
                            float tx = values[2];
                            float ty = values[5];
                            float sx = values[0];
                            float xc = (view.getWidth() / 2) * sx;
                            float yc = (view.getHeight() / 2) * sx;
                            matrix.postRotate(r, tx + xc, ty + yc);
                        }
                    }
                    break;
            }
    
            view.setImageMatrix(matrix);
    
            return true;
        }
    
        /**
         * Determine the space between the first two fingers
         */
        private float spacing(MotionEvent event) {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return FloatMath.sqrt(x * x + y * y);
        }
    
        /**
         * Calculate the mid point of the first two fingers
         */
        private void midPoint(PointF point, MotionEvent event) {
            float x = event.getX(0) + event.getX(1);
            float y = event.getY(0) + event.getY(1);
            point.set(x / 2, y / 2);
        }
    
        /**
         * Calculate the degree to be rotated by.
         *
         * @param event
         * @return Degrees
         */
        private float rotation(MotionEvent event) {
            double delta_x = (event.getX(0) - event.getX(1));
            double delta_y = (event.getY(0) - event.getY(1));
            double radians = Math.atan2(delta_y, delta_x);
            return (float) Math.toDegrees(radians);
        }
    
        Camera.PictureCallback cameraPictureCallbackJpeg = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                // TODO Auto-generated method stub
                BitmapFactory.Options options = new BitmapFactory.Options();
                //o.inJustDecodeBounds = true;
                Bitmap cameraBitmapNull = BitmapFactory.decodeByteArray(data, 0,
                        data.length, options);
    
                int wid = options.outWidth;
                int hgt = options.outHeight;
                Matrix nm = new Matrix();
    
                Camera.Size cameraSize = camera.getParameters().getPictureSize();
                float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
                if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
                    nm.postRotate(90);
                    nm.postTranslate(hgt, 0);
                    wid = options.outHeight;
                    hgt = options.outWidth;
                    ratio = relativeLayout.getWidth()*1f/cameraSize.height;
    
                }else {
                    wid = options.outWidth;
                    hgt = options.outHeight;
                    ratio = relativeLayout.getHeight()*1f/cameraSize.height;
                }
    
                float[] f = new float[9];
                matrix.getValues(f);
    
                f[0] = f[0]/ratio;
                f[4] = f[4]/ratio;
                f[5] = f[5]/ratio;
                f[2] = f[2]/ratio;
                matrix.setValues(f);
    
                Bitmap newBitmap = Bitmap.createBitmap(wid, hgt,
                        Bitmap.Config.ARGB_8888);
    
                Canvas canvas = new Canvas(newBitmap);
                Bitmap cameraBitmap = BitmapFactory.decodeByteArray(data, 0,
                        data.length, options);
    
                canvas.drawBitmap(cameraBitmap, nm, null);
                cameraBitmap.recycle();
    
                canvas.drawBitmap(bitmap, matrix, null);
                bitmap.recycle();
    
                File storagePath = new File(
                        Environment.getExternalStorageDirectory() + "/PhotoAR/");
                storagePath.mkdirs();
    
                File myImage = new File(storagePath, Long.toString(System
                        .currentTimeMillis()) + ".jpg");
    
                try {
                    FileOutputStream out = new FileOutputStream(myImage);
                    newBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
    
                    out.flush();
                    out.close();
                } catch (FileNotFoundException e) {
                    Log.d("In Saving File", e + "");
                } catch (IOException e) {
                    Log.d("In Saving File", e + "");
                }
    
            }
        };
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                                   int height) {
            // TODO Auto-generated method stub
    
            if (previewing) {
                camera.stopPreview();
                previewing = false;
            }
            try {
    
                if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
                    camera.setDisplayOrientation(90);
                    Camera.Size cameraSize = camera.getParameters().getPictureSize();
                    int wr = relativeLayout.getWidth();
                    int hr = relativeLayout.getHeight();
                    float ratio = relativeLayout.getWidth()*1f/cameraSize.height;
                    float w = cameraSize.width*ratio;
                    float h = cameraSize.height*ratio;
                    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)h, (int)w);
                    cameraSurfaceView.setLayoutParams(lp);
                }else {
                    camera.setDisplayOrientation(0);
                    Camera.Size cameraSize = camera.getParameters().getPictureSize();
                    float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
                    float w = cameraSize.width*ratio;
                    float h = cameraSize.height*ratio;
                    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)w, (int)h);
                    cameraSurfaceView.setLayoutParams(lp);
                }
    
                camera.setPreviewDisplay(cameraSurfaceHolder);
                camera.startPreview();
                previewing = true;
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            try {
                camera = Camera.open();
                Camera.Parameters params = camera.getParameters();
    
                // Check what resolutions are supported by your camera
                List<Camera.Size> sizes = params.getSupportedPictureSizes();
    
                // setting small image size in order to avoid OOM error
                Camera.Size cameraSize = null;
                for (Camera.Size size : sizes) {
                    //set whatever size you need
                    //if(size.height<500) {
                        cameraSize = size;
                        break;
                    //}
                }
    
                if (cameraSize != null) {
                    params.setPictureSize(cameraSize.width, cameraSize.height);
                    camera.setParameters(params);
    
                    float ratio = relativeLayout.getHeight()*1f/cameraSize.height;
                    float w = cameraSize.width*ratio;
                    float h = cameraSize.height*ratio;
                    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams((int)w, (int)h);
                    cameraSurfaceView.setLayoutParams(lp);
                }
            } catch (RuntimeException e) {
                Toast.makeText(
                        getApplicationContext(),
                        "Device camera  is not working properly, please try after sometime.",
                        Toast.LENGTH_LONG).show();
            }
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            // TODO Auto-generated method stub
            camera.stopPreview();
            camera.release();
            camera = null;
            previewing = false;
        }
    }
    

    注意我采用小相机分辨率以避免OOM错误

答案 1 :(得分:1)

相机预览和拍摄的最终照片通常使用不同的分辨率和宽高比;因此,在后处理中应用叠加层时需要考虑这一点。

更准确地说,您需要在&#34; apply overlay&#34;中考虑以下因素:过程:

  • 相机预览分辨率
  • 表面预览尺寸(,因为用户根据他的所见放置了叠加层)
  • 最终图片解决方案

答案 2 :(得分:1)

相反,将Ovelay放在相机上,您可以将捕获的图像作为位图加载,并在位图上绘制叠加徽标。保存位图。

下面的代码将合并两个位图图像,这些图像是您捕获的图像和徽标。

public Bitmap combineImages(Bitmap frame, Bitmap image) {
        Bitmap cs = null;
        Bitmap rs = null;

        rs = Bitmap.createScaledBitmap(frame, image.getWidth() + 50,
                image.getHeight() + 50, true);

        cs = Bitmap.createBitmap(rs.getWidth(), rs.getHeight(),
                Bitmap.Config.RGB_565);

        Canvas comboImage = new Canvas(cs);

        comboImage.drawBitmap(image, 25, 25, null);
        comboImage.drawBitmap(rs, 0, 0, null);
        if (rs != null) {
            rs.recycle();
            rs = null;
        }
        Runtime.getRuntime().gc();
        return cs;
    }

希望这会让你对此有所了解。

一些可以帮助您的链接。

1)Merge two bitmaps in android

2)Merging image from camera with image from drawables

3)how to merge to two bitmap one over another