概述

使用androidstudio开发,在手机上实现照片背景虚化

详细

一、准备工作

1、需要下载安装androidstudio和相关JDK,这两者下载安装和普通软件一样,

JDK:

http://www.oracle.com/technetwork/java/javase/downloads/index.html

androidstuido:

http://www.android-studio.org/

2、本例子在安卓手机上开发图像美化效果,用以在手机相机上实现类似高羰数码相机的背景虚化特效

3.软件下载安装配置完成后,下载本实例解压,打开androidstudio,选择FILE-》OPEN菜单,在弹出的对话中选择实例解压的位置,打开就行了

二、程序实现

1、主程序包含一个源码主文件MainActivity一个布局文件layout及相当菜单资源

2、实现思路怎样

要使用软件技术精确的背景虚化,需要经过三个步骤:

一是选定区域,根据远区使用抠图技术实现前背景分离

二对背景根据需要使用高斯或者平均值等模糊方法处理

三把处理后的背景和前景合并

3、具体设计到哪些代码

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView; import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc; public class MainActivity extends Activity { static final int REQUEST_OPEN_IMAGE = 1; String mCurrentPhotoPath;
Bitmap mBitmap;
ImageView mImageView;
int touchCount = 0;
Point tl;
Point br;
boolean targetChose = false;
ProgressDialog dlg;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
//Log.i(TAG, "OpenCV loaded successfully"); } break;
default:
{
super.onManagerConnected(status);
} break;
}
}
}; @Override
public void onResume()
{
super.onResume();
if (!OpenCVLoader.initDebug()) {
Log.d("OpenCV", "Internal OpenCV library not found. Using OpenCV Manager for initialization");
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
} else {
Log.d("OpenCV", "OpenCV library found inside package. Using it!");
mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mImageView = (ImageView) findViewById(R.id.imgDisplay);
dlg = new ProgressDialog(this);
tl = new Point();
br = new Point();
// if (!OpenCVLoader.initDebug()) {
// Handle initialization error
//}
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
int scaleFactor = 1;
private void setPic() {
int targetW = 720;//mImageView.getWidth();
int targetH = 1128;//mImageView.getHeight();
Log.i(">>>>>", "targetW="+targetW);
Log.i(">>>>>", "targetH=" + targetH);
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
Log.i(">>>>>", "photoW="+photoW);
Log.i(">>>>>", "photoH=" + photoH); scaleFactor = Math.max(photoW / targetW, photoH / targetH)+1;
Log.i(">>>>>", "photoW / targetW="+(photoW / targetW));
Log.i(">>>>>", "photoH / targetH="+(photoH / targetH)); bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true; mBitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(mBitmap);
Log.i(">>>>>", "mBitmap.getWidth()="+mBitmap.getWidth());
Log.i(">>>>>", "mBitmap.getHeight()=" + mBitmap.getHeight());
} @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_OPEN_IMAGE:
if (resultCode == RESULT_OK) {
Uri imgUri = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA }; Cursor cursor = getContentResolver().query(imgUri, filePathColumn,
null, null, null);
cursor.moveToFirst(); int colIndex = cursor.getColumnIndex(filePathColumn[0]);
mCurrentPhotoPath = cursor.getString(colIndex);
cursor.close();
setPic();
}
break;
}
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId(); switch (id) {
case R.id.action_open_img:
Intent getPictureIntent = new Intent(Intent.ACTION_GET_CONTENT);
getPictureIntent.setType("image/*");
Intent pickPictureIntent = new Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
Intent chooserIntent = Intent.createChooser(getPictureIntent, "Select Image");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] {
pickPictureIntent
});
startActivityForResult(chooserIntent, REQUEST_OPEN_IMAGE);
return true;
case R.id.action_choose_target: if (mCurrentPhotoPath != null)
targetChose = false;
mImageView.setOnTouchListener(new View.OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
int cx = (mImageView.getWidth()-mBitmap.getWidth())/2;
int cy = (mImageView.getHeight()-mBitmap.getHeight())/2;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (touchCount == 0) {
tl.x = event.getX();//300;//
tl.y = event.getY();//300;//
touchCount++;
}
else if (touchCount == 1) {
br.x = event.getX();//1100;//
br.y = event.getY();//1200;// Paint rectPaint = new Paint();
rectPaint.setARGB(255, 255, 0, 0);
rectPaint.setStyle(Paint.Style.STROKE);
rectPaint.setStrokeWidth(3);
Bitmap tmpBm = Bitmap.createBitmap(mBitmap.getWidth(),
mBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas tmpCanvas = new Canvas(tmpBm); tmpCanvas.drawBitmap(mBitmap, 0, 0, null);
tmpCanvas.drawRect(new RectF((float) tl.x, (float) tl.y, (float) br.x, (float) br.y),
rectPaint);
mImageView.setImageDrawable(new BitmapDrawable(getResources(), tmpBm)); targetChose = true;
touchCount = 0;
mImageView.setOnTouchListener(null);
}
} return true;
}
}); return true;
case R.id.action_cut_image:
if (mCurrentPhotoPath != null && targetChose) {
new ProcessImageTask().execute();
targetChose = false;
}
return true;
} return super.onOptionsItemSelected(item);
} private class ProcessImageTask extends AsyncTask<Integer, Integer, Integer> {
Mat img;
Mat foreground;
@Override
protected void onPreExecute() {
super.onPreExecute();
dlg.setMessage("Processing Image...");
dlg.setCancelable(false);
dlg.setIndeterminate(true);
dlg.show();
} @Override
protected Integer doInBackground(Integer... params) {
//Mat img = new Mat(mBitmap.getHeight(), mBitmap.getHeight(), CvType.CV_8UC3);
//Utils.bitmapToMat(mBitmap, img);
long ll = System.currentTimeMillis();
Log.i(">>>>>", "start="+ll);
img = Imgcodecs.imread(mCurrentPhotoPath);
Imgproc.resize(img, img, new Size(img.cols()/scaleFactor, img.rows()/scaleFactor));
Log.i(">>>>>", "11111=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
Mat background = new Mat(img.size(), CvType.CV_8UC3,
new Scalar(255, 255, 255)); Mat firstMask = new Mat();
Mat bgModel = new Mat();
Mat fgModel = new Mat();
Mat mask;
Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(Imgproc.GC_PR_FGD));
Mat dst = new Mat();
Rect rect = new Rect(tl, br);
Log.i(">>>>>", "22222="+System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
Imgproc.grabCut(img, firstMask, rect, bgModel, fgModel,
1, Imgproc.GC_INIT_WITH_RECT);
Log.i(">>>>>", "33333=" + System.currentTimeMillis() + "@@@@@" + (System.currentTimeMillis() - ll));
Core.compare(firstMask, source, firstMask, Core.CMP_EQ);
Log.i(">>>>>", "44444=" + System.currentTimeMillis() + "@@@@@" + (System.currentTimeMillis() - ll));
foreground = new Mat(img.size(), CvType.CV_8UC3,
new Scalar(255, 255, 255));
/////
img.copyTo(foreground);
Imgproc.blur(foreground, foreground, new Size(20, 20));
Log.i(">>>>>", "55555=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll));
/////
img.copyTo(foreground, firstMask);
Log.i(">>>>>", "66666=" + System.currentTimeMillis()+"@@@@@"+(System.currentTimeMillis()-ll)); firstMask.release();
source.release();
bgModel.release();
fgModel.release(); Imgcodecs.imwrite(mCurrentPhotoPath + ".png", foreground); return 0;
} @Override
protected void onPostExecute(Integer result) {
super.onPostExecute(result); Bitmap jpg = BitmapFactory
.decodeFile(mCurrentPhotoPath + ".png"); mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
mImageView.setAdjustViewBounds(true);
mImageView.setPadding(2, 2, 2, 2);
mImageView.setImageBitmap(jpg);
mImageView.invalidate(); dlg.dismiss();
}
}
}

4、配置文件说明

三、运行效果

运行,右键项目:Run as -》Android Application

1、运行时的截图

四、其他补充

1、Imgproc.grab分割前景效果比较好,但速度比较慢,如果是确认是固定的比如人脸,水果,植物,可以使用其他OPENCV提代的其他分割方法以加快速度

2.有关模糊,可以根据需要选择合适的模糊算法,比如高斯,比如运动模糊等

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

opencv在手机上实现照片背景虚化的更多相关文章

  1. opencv图像处理之在手机上实现背景虚化

    http://m.blog.csdn.net/blogercn/article/details/75004162 1.高端数码相机都具有背景虚化功能.背景虚化就是使景深变浅,使焦点聚集在主题上.一般的 ...

  2. 微信小程序客服消息开发实战:实时在手机上接收小程序客服消息通知,以及在手机上回复

    在微信小程序开发中,可以非常方便的集成客服功能,只需要一行代码便可以将用户引导至客服会话界面.这行代码就是: <button open-type="contact" bind ...

  3. PhotoShop CS6实现照片背景虚化效果

    在摄影实践中,虚化背景是突出主体的常用手段.但是由于消费级DC镜头的实际焦距都很短,因此实现浅景深而虚化背景的难度较大.如果我们希望用消费级DC也能达到虚化背景突出主体的效果,那么,Photoshop ...

  4. fontforge制作自定义字体及在手机上应用举例——张鑫旭

    一.看似无关紧要的事件背景 之所以花时间折腾fontforge这个软件,去制作什么自定义的字体是有原因滴. 之前提过,最近我抽空将公司的手机软件HTML5网页化.期间碰到这么一个问题,页面低栏上的电话 ...

  5. h5 audio标签在手机上不能自动播放????

    最近在做一个微信端的项目,快到接近尾声的时候,发现还没放入音频,于是乎,放入音频,在电脑端测试一切正常,无阻碍. 后来在手机上测试,发现背景音乐不能播放,于是开始找错,刚开始以为是IIS服务器出错,结 ...

  6. 便捷的方式在手机上查看Unity3D的Console Log(调试信息)

    Logs Viewer 功能描述 Using this tool you can easily check your editor console logs inside the game itsel ...

  7. fastclick与zepto的 tap事件关于在手机上click事件的300ms延迟的区别

    之前翻译过一篇关于fastclick的快速点击文章http://www.cnblogs.com/lilyimage/p/3568773.html,fastclick可以解决在手机上点击事件的300ms ...

  8. UIView点击事件。弹出视图,背景虚化。

    @interface CountryViewController //背景 @property (strong, nonatomic) UIView *BackView; end //设置背景虚化 - ...

  9. 背景虚化 Google Camera App Nokia Refocus HTC One M8 的 Duo景深相机

    背景虚化是单反中一种比较常见的拍照形式,参看 http://www.techbang.com/posts/%2017842 https://refocus.nokia.com/

随机推荐

  1. 快速近似最近邻搜索库 FLANN - Fast Library for Approximate Nearest Neighbors

    What is FLANN? FLANN is a library for performing fast approximate nearest neighbor searches in high ...

  2. how to configure logback for Mybatis to print my SQL

    To log SQL statements for particular mybatis mapper set DEBUG (TRACE to see query parameters and res ...

  3. 血淋淋的事实告诉你:你为什么不应该在JS文件中保存敏感信息

    在JavaScript文件中存储敏感数据,不仅是一种错误的实践方式,而且还是一种非常危险的行为,长期以来大家都知道这一点. 而原因也非常简单,我们可以假设你为你的用户动态生成了一个包含API密钥的Ja ...

  4. UVA 156 (13.08.04)

     Ananagrams  Most crossword puzzle fans are used to anagrams--groupsof words with the same letters i ...

  5. Ubuntu Linux自动发邮件配置及邮件发送脚本

    测试环境:Ubuntu 11.10 1. 安装mutt及msmtp软件 sudo apt-get install mutt sudo apt-get install msmtp 2. 编辑配置文件vi ...

  6. 开源 java CMS - FreeCMS2.2 网站管理

    项目地址:http://www.freeteam.cn/ 网站管理 FreeCMS支持站点群模式,并支持无限树级管理. 网站的相关文件在site文件夹下,每一个网站有自己的文件夹,源文件文件夹名就是自 ...

  7. Android NFC近场通信03----读写MifareClassic卡

                                           Android NFC近场通信02----读写MifareClassic卡 一.MifareClassic卡 相关 一般来 ...

  8. 转: telnet命令学习

    1.每天一个linux命令(58):telnet命令 转自: http://www.cnblogs.com/peida/archive/2013/03/13/2956992.html telnet命令 ...

  9. C# GDI+技术

    C# GDI+技术 GDI+概述         GDI+是GDI(即Windows早期版本号中附带的Graphics Device Interface)的后继者.它是一种构成Windows XP操作 ...

  10. 成员函数的const究竟修饰的是谁

    demo <pre name="code" class="cpp">class Test { public: const void OpVar(in ...