1.高端数码相机都具有背景虚化功能。背景虚化就是使景深变浅,使焦点聚集在主题上。一般的相机最好的虚拟方法便是用微距拍摄,如果主景与背景相距比较远,由于光学透镜对非焦点处景物的不能清晰成像的特点,可以免强实现类似虚化效果。如下。

2.相机拍摄背景虚化照片一般需要经过四个步骤:

(1)使变焦倍率(焦距)尽可能大;

(2)拍摄物与背景尽可能距离远;

(3)镜头与拍摄物尽可能距离近;

(4)光圈在满足拍摄需要的同时尽可能大,即F值小;

3.对于不支持背景虚化的相机,可以使用软件实现背景虚化,以满足不同客户的需求。

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

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

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

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

前景背景分离这个里使用OPENCV和grabCut技术实现,项目导入我自己编绎的opencv的AAR包,把OPENCV库放入LIBS文件夹,修改APP的build.gradle,添加LIBS:

repositories {mavenLocal()mavenCentral()flatDir {dirs 'libs'}
}
并在dependencies 节点添加如下声明 
compile fileTree(dir: 'libs', include: '*.aar')
4.附上代码:
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) {@Overridepublic void onManagerConnected(int status) {switch (status) {case LoaderCallbackInterface.SUCCESS:{//Log.i(TAG, "OpenCV loaded successfully");} break;default:{super.onManagerConnected(status);} break;}}};@Overridepublic 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);}}@Overrideprotected 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//}}@Overridepublic 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());}@Overrideprotected 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;}}@Overridepublic 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() {@Overridepublic 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;@Overrideprotected void onPreExecute() {super.onPreExecute();dlg.setMessage("Processing Image...");dlg.setCancelable(false);dlg.setIndeterminate(true);dlg.show();}@Overrideprotected 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;}@Overrideprotected 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();}}
}

5.完整工程可以在GITHUB上看到https://github.com/blogercn/backgroundblur
6.用到的关健函数解析:
a.Imgproc.grabCut,抠动,抠出前景
b.Imgproc.blur,对背景模糊处理
c.copyTo.背景背景合并图像

7.效果如下:

opencv图像处理之在手机上实现背景虚化相关推荐

  1. OpenCV在Android上实现人脸背景虚化

    1. 背景 在手机拍照技术日新月异的今天,很多手机厂商都陆续上了双摄,并衍生出人像模式(背景虚化).虽然博主不是很懂双摄虚化的原理,但是看到一些样张之后,还是被深深吸引,觉得很漂亮,很有虚幻的感觉. ...

  2. uni-app在手机上打开背景图片不显示

    uniapp项目在浏览器上打开背景图显示正常, 但在手机上打开时背景图没显示 , 解决办法: 把图片弄成动态的变量引入 <view :style="{backgroundImage:` ...

  3. 怎么虚化照片背景?分享几种照片背景虚化方法

    照片背景虚化是一种常用的摄影技巧,可以将主体与背景分离,突出主体,增加照片的艺术感.通过虚化背景,可以使主体更加突出.更加清晰,同时也可以去除背景中的干扰元素,从而提高照片的观赏性.我们如何给一张没有 ...

  4. opencv在手机上实现照片背景虚化

    概述 使用androidstudio开发,在手机上实现照片背景虚化 详细 代码下载:http://www.demodashi.com/demo/10599.html 一.准备工作 1.需要下载安装an ...

  5. Java OpenCV 图像处理32.4 视频分析和对象跟踪 切换背景

    Java OpenCV 图像处理32.4 视频分析和对象跟踪 切换背景 方法 含义 解释 bitwise_and "与"操作,即对图像(灰度图像或彩色图像均可)每个像素值进行二进制 ...

  6. 【OpenCV图像处理入门学习教程五】基于背景差分法的视频目标运动侦测

    OpenCV图像处理入门学习教程系列,上一篇第四篇:基于LoG算子的图像边缘检测 运动目标检测 关于运动目标检测的方法总结,目前能够实现运动物体检测的方法主要有以下几种: 1)背景差分法:能完整快速地 ...

  7. python按钮虚化,深度学习与图像处理实例:人像背景虚化与背景替换

    简单人像背景虚化处理思路如下: 对图像内容分割,提取人像,背景 背景模糊处理 人像与模糊处理后的背景融合 本实例使用DeepLabV3图像分割深度学习模型实现.代码如下: import numpy a ...

  8. 深度学习与图像处理实例:人像背景虚化与背景替换

    简单人像背景虚化处理思路如下: 对图像内容分割,提取人像,背景 背景模糊处理 人像与模糊处理后的背景融合 本实例使用DeepLabV3图像分割深度学习模型实现.代码如下: import os from ...

  9. Google Pixel 2拍照黑科技:单摄搞定背景虚化+内部潜伏神秘芯片

    安妮 夏乙 发自 凹非寺 量子位 出品 | 公众号 QbitAI Google最新亲儿子Google Pixel 2系列一发布,拍照效果的好评就已铺天盖地. 凭借着几乎毫无亮点的单摄像头,这款手机在D ...

最新文章

  1. 58回应“简历数据泄露”:将展开追查并加固安全系统
  2. Linux下对文件操作时出现乱码怎么办?
  3. python中的异常处理 try..except
  4. IOS开发基础之团购案例17-xib和UITableView两种方式实现
  5. C++输入cin详解
  6. 一张图看懂阿里云网络产品【四】NAT网关
  7. 并发问题的解决思路以及Go语言调度器工作原理
  8. python: 基本的日期与时间转换
  9. centos oracle 安装 踩坑实录 (三:踩坑与填坑大全)
  10. 数据分析与可视化概述
  11. 最新彩虹DS仿小储云模板源码
  12. 一款GaN HEMT内匹配功率放大器设计过程详解
  13. 工行u盾显示316_工行银行网上交易老是提示插入u盾
  14. C#毕业设计——基于C#+asp.net+SQL server的物料管理系统(ERP)设计与实现(毕业论文+程序源码)——物料管理系统(ERP)
  15. IPhone4S自定义铃声
  16. PEEKABOO——冲刺总结
  17. 基于Kotlin实现学生信息管理系统【100010063】
  18. 给你一台大疆无人机,你能用来做点啥?(三)------倾斜摄影建模基础
  19. 12星座之追女必杀技~
  20. Vs2008编译vtk5.10详细教程

热门文章

  1. java获取ip地址以及获取浏览器信息工具
  2. 学习笔记-TP5框架学习笔记\(路由\)
  3. Oracle 12C R2-新特性-自动锁住不经常使用的用户
  4. 阻塞/非阻塞 同步/异步
  5. 这个世界只有一种病,那就是贫穷!
  6. 智能学习与教育市场现状研究分析-
  7. 灰狼优化算法GWO优化SVM支持向量机惩罚参数c和核函数参数g,有例子
  8. el-popover 最小宽度 min-width
  9. 顶级React开发工具
  10. 计算机课件制作教程ppt,PPt多媒体课件制作图文教程