目前章节
1.从零开始安卓端相机功能开发(一)了解用什么去开发以及流程
2.从零开始安卓端相机功能开发(二)让我们来开发一个相机
3.从零开始开发Android相机app(三)简单介绍图像滤镜功能
源码地址:https://github.com/307572384/GPItest/commit/a89a605cec14bd573cd90994c973cfdd00f97991?diff=unified
1. 前期基础知识详解
滤镜;主要是用来实现图像的各种特殊效果。它在Photoshop中具有非常神奇的作用。所有的滤镜在Photoshop中都按分类放置在菜单中,使用时只需要从该菜单中执行这命令即可。滤镜的操作是非常简单的,但是真正用起来却很难恰到好处。滤镜通常需要同通道、图层等联合使用,才能取得最佳艺术效果。如果想在最适当的时候应用滤镜到最适当的位置,除了平常的美术功底之外,还需要用户对滤镜的熟悉和操控能力,甚至需要具有很丰富的想象力。这样,才能有的放矢的应用滤镜,发挥出艺术才华。
以上来源于百度百科,当然我们的Android相机开发的图像滤镜也不是那么简单的需要自己有一些动手能力和一定的英语阅读水平和数学能力才能够熟悉的一些东西,这里我个人建议要想变得更强英语和数学这两个要变得非常强才可以,毕竟有些外国文章写得非常不错可以用来参考,但是翻译却很少所以得提高自己的能力才行。这个是我这几天的学习感受。
2.滤镜效果如何实现分析
首先我们写滤镜效果可以使用现成的如GPUImage或者是其他的现成付费SDK也可以自己写当然这种的话就比较麻烦涉及到算法之类的,我个人比较推荐GPUImage这一款开源项目。
GPUImage 是iOS下一个开源的基于GPU的图像处理库,提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜。GPUImage for Android是它在Android下的实现,同样也是开源的。其中提供了几十多种常见的图片滤镜API,且其机制是基于GPU渲染,处理速度相应也比较快,是一个不错的图片实时处理框架。
而且现在还在更新状态中。
需要的可以去看看GPUImageGithub开源项目
滤镜处理对象:通常分为两类:1.静态图片;2.实时相机预览;3.视频添加滤镜;
实现方式有多种,比如通过调用Android系统提供的图像处理API,可以设置图片的色调、饱和度、亮度,也可以调用ColorMatrix进行更加精确的图片色彩调控,还可以使用更加精细化的像素处理方式—提取图片像素点,然后对每个像素点进行处理,使图片变换不同的色彩效果,以上的方式都是调用Android系统提供的API进行处理,难点在于图像处理算法的研究,这也是专业图像处理人员的工作之一,尝试不同色彩矩阵的配合,可以创建出不同的色彩效果。
GPUImage是iOS的一个开源库,后来也有了Android的版本,可以实现五十多种的滤镜效果,不用开发者自己进行滤镜算法的实现,处理起来更加的方便,而且GPUImage可以做到的不仅仅是像ColorMatrix一样的色彩特效,还可以进一步实现美颜相机需要的其他特效,比如磨皮,美白等,功能会更加强大。
3.我们来实现静态的滤镜实现吧
环境搭建
首先,要使用这个库自然是要先导入依赖,在app的gradle文件中添加:
repositories {
google()
jcenter()
}
dependencies {
compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'
}
至于怎么创建Assets文件我们就使用这个
Android图像滤镜框架GPUImage从配置到应用
然后里面的素材图片大家可以随便写一个然后导入进去。
4.GPUImage API调用:
GPUImage主要通过一个GPUImageFilter类来提供各种滤镜效果实现类,比如我们来实现一个将图片变成的鱼眼的滤镜:
“GPUImageBulgeDistortionFilter” 【凸起失真,鱼眼效果】这个是我们需要实现的效果。
我们来看一下鱼眼效果
这里是静态滤镜的MainActivity里面有滤镜的主要功能:包括滤镜显示到屏幕上和拖拉调整图片饱和度的功能
务必在AndroidManifest中先添加联网权限
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import junit.framework.Assert;
import java.io.IOException;
import java.io.InputStream;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageBulgeDistortionFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageSaturationFilter;
public class MainActivity extends AppCompatActivity {
private GPUImage gpuImage;
//显示处理结果
private ImageView resultIv;
//进度条
private SeekBar seekBar;
private Button bt_net;//点击跳转到图片网络滤镜转换
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultIv = (ImageView)findViewById(R.id.resultIv);
bt_net=(Button)findViewById(R.id.button) ;
seekBar = (SeekBar)this.findViewById(R.id.seekbar);
seekBar.setMax(10);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//通过进度条的值更改饱和度
resultIv.setImageBitmap(getGPUImageFromAssets(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//初始化图片
resultIv.setImageBitmap(getGPUImageFromAssets(0));
bt_net.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,NetActivity.class);
startActivity(intent);
}
});
}
//根据传进来的数值设置素材饱和度
public Bitmap getGPUImageFromAssets(int progress)
{
//获得Assets资源文件
AssetManager as = getAssets();
InputStream is = null;
Bitmap bitmap = null;
try{
is = as.open("link.jpg");
bitmap = BitmapFactory.decodeStream(is);
is.close();
}catch (IOException e)
{
Log.e("GPUImage","Error");
}
gpuImage = new GPUImage(this);
gpuImage.setImage(bitmap);
gpuImage.setFilter(new GPUImageBulgeDistortionFilter());
bitmap = gpuImage.getBitmapWithFilterApplied();
//显示处理图片后的照片
return bitmap;
}
}
PS:这里注意一下有些滤镜功能是没有饱和度如鱼眼功能
这里是MainActivity的activity_layout布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.beta.gpitest.MainActivity">
<ImageView
android:id="@+id/resultIv"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_marginBottom="23dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="93dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="跳转到网络图片滤镜效果"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/resultIv" />
<Button
android:id="@+id/setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:text="setting"
app:layout_constraintBaseline_toBaselineOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
如果我们需要联网进行滤镜效果的话,由于访问网络图片,所以需要放在子线程中进行,所以这里通过AsynTask(Android异步线程,不清楚的可以看下这篇文章AsynTask使用简介),现在子线程请求完网络图片并转换为Bitmap传递给主线程中对图片进行滤镜处理并显示出来。
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
public class NetActivity extends AppCompatActivity {
private GPUImage gpuImage;
//显示处理结果
private ImageView resultIv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.net_main);
resultIv = (ImageView) findViewById(R.id.imagex);
//开启异步线程加载图片并处理
MyAsynTask asynTask = new MyAsynTask();
asynTask.execute();
}
class MyAsynTask extends AsyncTask<Integer,Integer,Bitmap>{
@Override
protected Bitmap doInBackground(Integer... params) {
//写入图片的url
Bitmap bitmap = getGPUImageFromURL("https://img-blog.csdn.net/20180422104130848?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTEwMTE3Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70");
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
// 使用GPUImage处理图像
gpuImage = new GPUImage(getApplicationContext());
gpuImage.setImage(bitmap);
gpuImage.setFilter(new GPUImageGrayscaleFilter());
bitmap = gpuImage.getBitmapWithFilterApplied();
//显示处理后的图片存储到bitmap
resultIv.setImageBitmap(bitmap);
}
}
public static Bitmap getGPUImageFromURL(String url) {
Bitmap bitmap = null;
try {
URL iconUrl = new URL(url);
URLConnection conn = iconUrl.openConnection();
HttpURLConnection http = (HttpURLConnection) conn;
int length = http.getContentLength();
conn.connect();
// 获得图像的字符流
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, length);
bitmap = BitmapFactory.decodeStream(bis);
bis.close();
is.close();// 关闭流
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}
网络图片的layout这个很简单就只是一个imageview:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/imagex"
android:layout_width="match_parent"
android:layout_height="229dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
5.最后叨一叨:
这个静态滤镜和联网滤镜功能已经实现了,接下来我需要做的是实现人脸识别美颜+组合滤镜功能,不知道大家有没有学习过或者使用过lightroom这款滤镜调整的WIN平台下的软件因为我本身副职业是走的是摄影这条路所以有所学习到,但是我认为GpuImage的滤镜功能就我暂时学到的可能有点少所以想要实现像LightRoom的那些大片滤镜功能就稍微有些复杂不过还是慢慢的一步一步走下去比较好一点。
下面我们来看看我们走到哪一步了。