您的位置:首页 > 产品设计 > UI/UE

iOS—使用GPUImage对照片和相机添加滤镜

2016-09-23 00:00 561 查看
摘要: 博主在设置切换前后摄像头的时候遇到了麻烦,暂时未能成功,最后一张效果图的切换摄像头功能未能实现。实现后会更新博客。

#1GPUImage 的下载与安装

GPUImage 是一个开源的图像处理库,提供了非常多的滤镜效果来加工图片。GPUImage 并不像一般的第三方库可以直接拖入到工程中使用,而是需要先在本地编译,然后将编译后的文件拖入到工程中使用。配置步骤如下:

:首先下载GPUImage https://github.com/BradLarson/GPUImage

:解压后,在framework 目录下,打开 GPUImage.xcodeproj 工程



把Headers文件夹下 Project中的头文件,全部拖到 Public文件夹下面



运行该工程

点击Products下的 libGPUImage.a,右键, show in finder



把该目录下的libGpuImage.a 和 User文件夹拖到我们新建的工程下面





.m中导入头文件 #import "GPUImage.h",就可以使用GPUImage了

#2使用GPUImage处理静态图片
直接上代码讲解。

@interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
{
// 相机
CameraViewController *camera;
//相册
UIImagePickerController *_photos;

UIImage *inputImage;
UIImageView *_imageView;
}
@end

在处理静态图片的时候我加入了从相册中选取图片,故导入UINavigationControllerDelegate,UIImagePickerControllerDelegate这个两个协议。

/懒加载  UIImagePickerController
-(UIImagePickerController *)getPhotos{
if (!_photos) {

_photos = [[UIImagePickerController alloc]init];

_photos.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
_photos.delegate = self;
}
return _photos;

}

使用懒加载的方法把UIImagePickerController加载出来。

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

//进去时候的默认图片;
inputImage = [UIImage imageNamed:@"u=884032455,526519386&fm=21&gp=0"];

UIImageView *imageView = [[UIImageView alloc] initWithImage:inputImage];

imageView.frame = CGRectMake(50,50, 400,400);
[self.view addSubview:imageView];
_imageView = imageView;

在 viewDidLoad 中设置放置图片的UIImageView的大小以及默认图片,然后再赋值给 _imageView(最开始我们设置的全局变量)。

// 效果一 控件
-(void)buttonOne{

UIButton *buttonOne = [UIButton buttonWithType:UIButtonTypeCustom];
buttonOne.frame = CGRectMake(10, HEIGHT - 200, 80, 30);
[buttonOne setTitle:@"效果一" forState:UIControlStateNormal];
buttonOne.backgroundColor = [UIColor blackColor];

[self.view addSubview:buttonOne];

[buttonOne addTarget:self action:@selector(buttonOneAction) forControlEvents:UIControlEventTouchUpInside];

}

这里就是我们创建效果的button了,很简单的代码。

-(void)buttonOneAction{

//设置滤镜的效果
GPUImageToonFilter *passthroughFilter = [[GPUImageToonFilter alloc] init];

//设置要渲染的区域
[passthroughFilter forceProcessingAtSize:inputImage.size];

[passthroughFilter useNextFrameForImageCapture];

//获取数据源
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage];
//加上滤镜
[stillImageSource addTarget:passthroughFilter];
//开始渲染

[stillImageSource processImage];
//获取渲染后的图片
UIImage *newImage = [passthroughFilter imageFromCurrentFramebuffer];

_imageView.image = newImage;
}

这一步是实现我们点击效果一按钮出发的事件。 其中我们设置的滤镜效果有很多。
在这里我就给大家列出来,不要嫌多

##2.1依照以上的方法就可以设置多个效果button,设设置完Button后不要忘了在 viewDidLoad 中加载出来。

// 删除效果控件
-(void)buttonOriginal{

UIButton *buttonOriginal = [UIButton buttonWithType:UIButtonTypeCustom];
buttonOriginal.frame = CGRectMake(120, HEIGHT - 100, 120, 30);
[buttonOriginal setTitle:@"删除效果" forState:UIControlStateNormal];
buttonOriginal.backgroundColor = [UIColor blueColor];

[self.view addSubview:buttonOriginal];

[buttonOriginal addTarget:self action:@selector(buttonOriginalAction) forControlEvents:UIControlEventTouchUpInside];

}

为了完整,我添加了一个删除效果的Button,以到达还原图片的效果

- (void)buttonOriginalAction {

_imageView.image = inputImage;
}

就是把选中的原图再次赋给图片,就达到了还原的效果。

// 进入相册 控件
-(void)buttonPhoto{

UIButton *buttonPhoto = [UIButton buttonWithType:UIButtonTypeCustom];
buttonPhoto.frame = CGRectMake(280, HEIGHT - 100, 120, 30);
[buttonPhoto setTitle:@"相册" forState:UIControlStateNormal];
buttonPhoto.backgroundColor = [UIColor blueColor];

[self.view addSubview:buttonPhoto];

[buttonPhoto addTarget:self action:@selector(buttonPhotoAction) forControlEvents:UIControlEventTouchUpInside];

}

##2.2添加一个进入相册的控件

- (void)buttonPhotoAction{

[self presentViewController:_photos animated:YES completion:nil];

}

通过这个方法就可以进如到相册中去。

#pragma mark -<UINavigationControllerDelegate,UIImagePickerControllerDelegate>

// 协议方法 UIImagePickerControllerDelegate
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{

//相册返回(销毁控制器)
[picker dismissViewControllerAnimated:YES completion:nil];

//把相册的照片赋给控件页面上的 UIImageView → UIImage
_imageView.image = info[UIImagePickerControllerOriginalImage];
inputImage = _imageView.image;

}

以上代码就是在进入相册的时候出来的时候要销毁控制器。不然会出错。最后再把照片赋给全局变量的 UIImageView → UIImage。



#3使用GPUImage制作实时滤镜

制作实时滤镜就是在相机或者摄影的时候把滤镜添加上去,这里我就只做了相机的实时滤镜

// 进入照相机 控件
-(void)buttonCamera{

UIButton *buttonCamera = [UIButton buttonWithType:UIButtonTypeCustom];
buttonCamera.frame = CGRectMake(180, HEIGHT - 300, 180, 50);
[buttonCamera setTitle:@"相机 咔!咔!咔!" forState:UIControlStateNormal];
buttonCamera.backgroundColor = [UIColor blueColor];

[self.view addSubview:buttonCamera];

[buttonCamera addTarget:self action:@selector(buttonCameraAction) forControlEvents:UIControlEventTouchUpInside];

}

##3.1创建一个相机的button,以及实现他的点击功能,这些方法都要写在 处理静态图片的的.m文件中。

-(void)buttonCameraAction{

[self presentViewController:camera  animated:YES completion:nil];

}

这个点击方法就是进入到相机中拍照。

创建 CameraViewController 这个类,在这个类里面写相机的一些功能。
首先导入 #import AssetsLibrary/AssetsLibrary.h>这是用来拍照的时候将图片保存到相册中的头文件

@interface CameraViewController ()
{
//创建一个全局的效果的button
UIButton *buttonEffect;
//
UIButton *_tempBtn;

}

//全局变量的相机
@property (strong, nonatomic) GPUImageStillCamera *mCamera;
//滤镜
@property (strong, nonatomic) GPUImageFilter *mFilter;
//视图
@property (strong, nonatomic) GPUImageView *mGPUImageView;

@property (strong, nonatomic) UIView *btnBgView;
//摄像头的位置
@property(nonatomic, readonly) AVCaptureDevicePosition position;

@end

代码中有注释,创建这些全局变量 { } 中的内容一定要记得初始化,因为没有生成 set 和 get 方法。

// 初始化 btnBgView(懒加载)
- (UIView *)btnBgView{
if (!_btnBgView) {
_btnBgView = [[UIView alloc] initWithFrame:CGRectMake(80,HEIGHT - 250,WIDTH - 80, 80)];

_btnBgView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.1];
[self.view addSubview:_btnBgView];
}
return _btnBgView;
}

初始化 btnBgView。

##3.2步骤 1 第一个参数表示相片的尺寸,第二个参数表示前、后摄像头

- (void)viewDidLoad {
[super viewDidLoad];

//摄像头方向
_position = AVCaptureDevicePositionFront;

_mCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset640x480 cameraPosition:_position];

竖屏方向

_mCamera.outputImageOrientation = UIInterfaceOrientationPortrait;

步骤2 滤镜

_mFilter = [[GPUImageVignetteFilter alloc] init];

步骤3 创建GPUImageView及 尺寸

_mGPUImageView = [[GPUImageView alloc]initWithFrame:self.view.bounds];

步骤4 添加滤镜到相机上

[_mCamera addTarget:_mFilter];
[_mFilter addTarget:_mGPUImageView];

步骤5 添加视图到VIEW上

[self.view addSubview:_mGPUImageView];

//步骤6 启动相机
[_mCamera startCameraCapture];

将按键视图放置顶层

[self.view bringSubviewToFront:buttonEffect];

self.btnBgView.hidden = YES;
self.btnBgView.frame = CGRectMake(WIDTH,HEIGHT - 250,WIDTH - 80, 80);

##3.3按键创建

[self creatSetectBtn];
[self buttonRt ];
[self crateBtn];
[self buttonEffect];
[self Camare];

// 将按钮的的初始值设为 nil;
_tempBtn = nil;
}

接下来我们就开始创建一个个的控件,

创建拍照按钮

-(void)crateBtn{

//添加一个按钮触发拍照
UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake((self.view.bounds.size.width-80)*0.5, self.view.bounds.size.height-100, 80, 80)];

btn.backgroundColor = [UIColor redColor];
[btn setTitle:@"拍照" forState:UIControlStateNormal];

[self.view addSubview:btn];
[btn addTarget:self action:@selector(takePhoto) forControlEvents:UIControlEventTouchUpInside];

}

实现点击拍照按钮将照片保存到相册中

-(void)takePhoto{
//步骤7
[_mCamera capturePhotoAsJPEGProcessedUpToFilter:_mFilter withCompletionHandler:^(NSData *processedJPEG, NSError *error){

//将相片保存到手机相册(iOS8及以上,该方法过期但是可以用,不想用请搜索PhotoKit)
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageDataToSavedPhotosAlbum:processedJPEG metadata:_mCamera.currentCaptureMetadata completionBlock:^(NSURL *assetURL, NSError *error2)
{
if (error2) {
NSLog(@"保存失败");
}
else {
NSLog(@"保存成功 - assetURL: %@", assetURL);
}

}];
}];
}

返回按钮

-(void)buttonRt{

UIButton *rt = [UIButton buttonWithType:UIButtonTypeCustom];
rt.frame = CGRectMake(0, 0, 80, 80);
rt.backgroundColor = [UIColor redColor];
[rt setTitle:@"返回" forState:UIControlStateNormal];
[self.view addSubview:rt];
[rt addTarget:self action:@selector(rtAction) forControlEvents:UIControlEventTouchUpInside];
}

从相机页面返回到处理静态图片的页面

-(void)rtAction{

[self dismissViewControllerAnimated:YES completion:nil];

}

设置btnBgView的位置,设置 其 为隐藏状态

-(void)resumeState{

[UIView animateWithDuration:1.0 animations:^{
self.btnBgView.transform = CGAffineTransformMakeTranslation(WIDTH, 0);
}];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.btnBgView.hidden = YES;
});
}

##3.4创建滤镜按钮,这里的滤镜按钮是总按钮,弹出很多个滤镜选项的按钮

-(void)buttonEffect{

buttonEffect = [UIButton buttonWithType:UIButtonTypeCustom];
buttonEffect.frame = CGRectMake(WIDTH - 80, HEIGHT - 250, 80, 80);
buttonEffect.backgroundColor = [UIColor redColor];
[buttonEffect setTitle:@"滤镜" forState:UIControlStateNormal];
[self.view addSubview: buttonEffect];
[buttonEffect addTarget:self action:@selector(effectAction) forControlEvents:UIControlEventTouchUpInside];

}

点击滤镜按钮 弹出一个btnBgView,根据判断这个视图是否显示,来进行 弹出 还是 隐藏。 在工程的最开始的位置,我们已经提前对btnBgView进行了初始化。且在上一步的操作中将其默认状态设置为了 隐藏。

-(void)effectAction{

if (self.btnBgView.hidden) {

[UIView animateWithDuration:1 animations:^{
self.btnBgView.transform = CGAffineTransformMakeTranslation(-WIDTH, 0);
}];
self.btnBgView.hidden = NO;
}else{

[self resumeState];
}
}

设置一个Button 不设置其颜色,相当于看不见,但是还是存在的,将这个button 添加到我们刚才创建的 btnBgView 上。

- (UIButton *)addSetBtn:(NSString *)btnTitle withBtnTag:(NSInteger)btnTag withBtnX:(CGFloat)btnX{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(btnX, 0, (self.btnBgView.frame.size.width - 8) / 5, 80);
btn.tag = btnTag;

[btn setTitle:btnTitle forState:UIControlStateNormal];
[btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];

[self.btnBgView addSubview:btn];

return btn;
}

将上面的button 通过循环创建5个滤镜效果 按钮

- (void)creatSetectBtn{

for (NSInteger i = 0; i<5; i ++) {
CGFloat x = (self.btnBgView.frame.size.width - 8) / 5 * i + 2 *i;

[self addSetBtn:[NSString stringWithFormat:@"效果%ld",i + 1] withBtnTag:i withBtnX:x];
}

}

滤镜按钮点击状态,初始化最开始我们创建的 UIButton *_tempBtn

- (void)btnState:(UIButton *)btn{
if (!_tempBtn.enabled && _tempBtn != nil) {
_tempBtn.enabled = YES;
_tempBtn.selected = !_tempBtn.selected;
_tempBtn.backgroundColor = [UIColor clearColor];
}
btn.selected = !btn.selected;
if (btn.selected) {
btn.backgroundColor = [UIColor redColor];
btn.enabled = NO;
_tempBtn = btn;
}

}

##3.5滤镜切换


-(void)changeEffct:(GPUImageFilter *)mFilter withBtn:(UIButton *)btn{

//移除上一个效果
[_mCamera removeTarget:_mFilter];

_mFilter = mFilter;

// 添加滤镜到相机上[_mCamera addTarget:_mFilter]; [_mFilter addTarget:_mGPUImageView];
//调用收缩滤镜方法的方法
[self resumeState];
[self btnState:btn];

}

切换滤镜的方法

- (void)btnAction:(UIButton *)btn{

switch (btn.tag) {
case (EffctTypeOne):{
//创建一个新的滤镜
GPUImageBulgeDistortionFilter *mfilter = [[GPUImageBulgeDistortionFilter alloc]init];

//调用切换滤镜方法
[self changeEffct:mfilter withBtn:btn];
}
break;
case (EffctTypeTwo):{
GPUImagePinchDistortionFilter *mfilter = [[GPUImagePinchDistortionFilter alloc]init];
[self changeEffct:mfilter withBtn:btn];
}
break;
case (EffctTypeThree):{
GPUImageStretchDistortionFilter *mfilter = [[GPUImageStretchDistortionFilter alloc]init];
[self changeEffct:mfilter withBtn:btn];
}
break;
case (EffctTypeFour):{
GPUImageGlassSphereFilter *mfilter = [[GPUImageGlassSphereFilter alloc]init];

[self changeEffct:mfilter withBtn:btn];
}
break;
case (EffctTypeFive):{
GPUImageVignetteFilter *mfilter = [[GPUImageVignetteFilter alloc]init];
[self changeEffct:mfilter withBtn:btn];
}
break;

default:
break;
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  GPUImage 滤镜 相机