使用nice选取图片之后出来张暖雅17张无马赛克克是怎么回事?

8135人阅读
iOS8 Core Image In Swift:人脸检测以及马赛克Core Image不仅内置了诸多滤镜,还能检测图像中的人脸,不过Core Image只是检测,并非识别,检测人脸是指在图像中寻找符合人脸特征(只要是个人脸)的区域,识别是指在图像中寻找指定的人脸(比如某某某的脸)。Core Image在找到符合人脸特征的区域后,会返回该特征的信息,比如人脸的范围、眼睛和嘴巴的位置等。人脸检测并标记检测到的区域先做好以下几步:新建一个Single View Application工程然后在Storyboard里放入UIImageView,ContentMode设置为Aspect Fit将UIImageView连接到VC里放入一个名为“人脸检测”的UIButton,然后连接到VC的faceDetecting方法上关闭Auto Layout以及Size ClassesUIImageView的frame以及VC的UI如下:以下是工程中会用到的图,齐刷刷一排脸,点击图片显示原图:然后在VC上添加基本的属性:懒加载的originalImage、context(Core Image框架绕不开的对象)。class&ViewController:&UIViewController&{& &&@IBOutlet&var&imageView:&UIImageView!& &&lazy&var&originalImage:&UIImage&= {& & & &&return&UIImage(named:&&Image&)& & }()& &&lazy&var&context:&CIContext&= {& & & &&return&CIContext(options:&nil)& & }()......&在viewDidLoad方法里显示originalImage:override&func&viewDidLoad() {& &&super.viewDidLoad()& &&// Do any additional setup after loading the view, typically from a nib.& &&self.imageView.image&=&originalImage}&然后就可以准备实现faceDetecting方法了。在Core Image框架中,CIDetector对象提供了对图像检测的功能,只需要通过几个APIs就能完成CIDetector的初始化并得到检测结果:@IBAction&func&faceDetecing() {& &&let&inputImage =&CIImage(image:&originalImage)& &&let&detector =&CIDetector(ofType:&CIDetectorTypeFace,&& & & & & & & & & & & & & & context:&context,&& & & & & & & & & & & & & & options: [CIDetectorAccuracy:&CIDetectorAccuracyHigh])& &&var&faceFeatures: [CIFaceFeature]!& &&if&let&orientation:&AnyObject&= inputImage.properties()?[kCGImagePropertyOrientation] {& & & & faceFeatures = detector.featuresInImage(inputImage,&& & & & & & & & & & & & & & & & & & & & & & & & options: [CIDetectorImageOrientation: orientation]& & & & & & & & & & & & & & & & & & & & & & & &)&as&[CIFaceFeature]& & }&else&{& & & & faceFeatures = detector.featuresInImage(inputImage)&as&[CIFaceFeature]& & }& &&println(faceFeatures)......使用kCGImagePropertyOrientation的时候,可能需要导入ImageIO框架originalImage和context通过懒加载都得到了,在创建CIDetector对象的时候,必须告诉它要检测的内容,这里当然是传CIDetectorTypeFace了,除了CIDetectorTypeFace外,CIDetector还能检测二维码;然后传递一个context,多个CIDetector可以共用一个context对象;第三个参数是一个字典,我们能够指定检测的精度,除了CIDetectorAccuracyHigh以外,还有CIDetectorAccuracyLow,精度高会识别度更高,但识别速度就更慢。创建完CIDetector之后,把要识别的CIImage传递给它,在这里,我判断了CIImage是否带有方向的元数据,如果带的话调用就featuresInImage:options这个方法,因为方向对CIDetector来说至关重要,直接导致识别的成功与否;而有的图片没有方向这些元数据,就调用featuresInImage方法,由于这张《生活大爆炸》的图是不带方向元数据的,所以是执行的featuresInImage方法,但是大多数情况下应该会用到前者。featuresInImage方法的返回值是一个CIFaceFeature数组,CIFaceFeature包含了面部的范围、左右眼、嘴巴的位置等,我们通过使用bounds就能标记出面部的范围。我们很容易写出这样的代码:获取所有的面部特征用bounds实例化一个UIView把View显示出来实现出来就像这样:@IBAction&func&faceDetecing() {& &&let&inputImage =&CIImage(image:&originalImage)& &&let&detector =&CIDetector(ofType:&CIDetectorTypeFace,& & & & context:&context,& & & & options: [CIDetectorAccuracy:&CIDetectorAccuracyHigh])& &&var&faceFeatures: [CIFaceFeature]!& &&if&let&orientation:&AnyObject&= inputImage.properties()?[kCGImagePropertyOrientation] {& & & & faceFeatures = detector.featuresInImage(inputImage, options: [CIDetectorImageOrientation: orientation])&as&[CIFaceFeature]& & }&else&{& & & & faceFeatures = detector.featuresInImage(inputImage)&as&[CIFaceFeature]& & }&& && &&println(faceFeatures)& &&for&faceFeature&in&faceFeatures {& & & &&let&faceView =&UIView(frame: faceFeature.bounds)& & & & faceView.layer.borderColor&=&UIColor.orangeColor().CGColor& & & & faceView.layer.borderWidth&=&2&& & & && & & &&imageView.addSubview(faceView)& & }}这样写是否可以呢?如果你运行起来会得到这样的效果:这是因为我们的inputImage,其实是用originalImage初始化的,而我这张originalImage的真实大小比实际看到的大得多:它的宽实有600像素,我把它以@2x命名,实际显示有300像素,且在imageView里以Aspect Fit模式展示(imageViwe宽为300像素),在显示的时候被缩放了,但是在内存中它是完整的,除此之外,CIImage的坐标系统和UIView的坐标系统也不一样,CIImage的坐标系统就像数学坐标系统,原点在下,在UIView看来,就是倒置的,这是因Core Image、Core Graphics这些框架都来源于Mac OS X,在Mac OS X上这种坐标系统已存在多年,iOS直接引入了这些框架,这解决了Cocoa App和iOS App底层兼容性的问题,但是在上层就只能自己解决了。所以实际上它是这样的:我们需要做两步工作:调整transform,让它正过来缩放bounds,让它适配imageView然后再次很容易的写下了这样的代码:@IBAction&func&faceDetecing() {& &&let&inputImage =&CIImage(image:&originalImage)& &&let&detector =&CIDetector(ofType:&CIDetectorTypeFace,& & & & context:&context,& & & & options: [CIDetectorAccuracy:&CIDetectorAccuracyHigh])& &&var&faceFeatures: [CIFaceFeature]!& &&if&let&orientation:&AnyObject&= inputImage.properties()?[kCGImagePropertyOrientation] {& & & & faceFeatures = detector.featuresInImage(inputImage, options: [CIDetectorImageOrientation: orientation])&as&[CIFaceFeature]& & }&else&{& & & & faceFeatures = detector.featuresInImage(inputImage)&as&[CIFaceFeature]& & }&& && &&println(faceFeatures)&& && &&// 1.& &&let&inputImageSize = inputImage.extent().size& &&var&transform =&CGAffineTransformIdentity& & transform =&CGAffineTransformScale(transform,&1, -1)& & transform =&CGAffineTransformTranslate(transform,&0,&-inputImageSize.height)& &&for&faceFeature&in&faceFeatures {& & & &&var&faceViewBounds =&CGRectApplyAffineTransform(faceFeature.bounds, transform)& & & &&// 2.& & & &&let&scaleTransform =&CGAffineTransformMakeScale(0.5,&0.5)& & & & faceViewBounds =&CGRectApplyAffineTransform(faceViewBounds, scaleTransform)&& & & && & & &&let&faceView =&UIView(frame: faceViewBounds)& & & & faceView.layer.borderColor&=&UIColor.orangeColor().CGColor& & & & faceView.layer.borderWidth&=&2&& & & && & & &&imageView.addSubview(faceView)& & }}&现在看起来就没有问题了,在第一步里我们放置了一个调整坐标系统的tranform,在第二步对bounds进行了缩放(等同于把x、y、width、height全部乘以0.5),由于我们知道实际scale是0.5(原图600像素,imageView宽为300像素),就直接写死了0.5,但运行后出现了一点点偏移:这其实是因为我把imageView的ContentMode设为Aspect Fit的结果 :一般来讲,我们不会拉伸照片,通常会按宽、高进行适配,所以我们还需要对Aspect Fit进行处理,上面代码修改后如下:@IBAction&func&faceDetecing() {& &&let&inputImage =&CIImage(image:&originalImage)& &&let&detector =&CIDetector(ofType:&CIDetectorTypeFace,& & & & context:&context,& & & & options: [CIDetectorAccuracy:&CIDetectorAccuracyHigh])& &&var&faceFeatures: [CIFaceFeature]!& &&if&let&orientation:&AnyObject&= inputImage.properties()?[kCGImagePropertyOrientation] {& & & & faceFeatures = detector.featuresInImage(inputImage, options: [CIDetectorImageOrientation: orientation])&as&[CIFaceFeature]& & }&else&{& & & & faceFeatures = detector.featuresInImage(inputImage)&as&[CIFaceFeature]& & }&& && &&println(faceFeatures)&& && &&// 1.& &&let&inputImageSize = inputImage.extent().size& &&var&transform =&CGAffineTransformIdentity& & transform =&CGAffineTransformScale(transform,&1, -1)& & transform =&CGAffineTransformTranslate(transform,&0,&-inputImageSize.height)& &&for&faceFeature&in&faceFeatures {& & & &&var&faceViewBounds =&CGRectApplyAffineTransform(faceFeature.bounds, transform)&& & & && & & &&// 2.& & & &&var&scale =&min(imageView.bounds.size.width&/&inputImageSize.width,& & & & & &&imageView.bounds.size.height&/&inputImageSize.height)& & & &&var&offsetX = (imageView.bounds.size.width&-&inputImageSize.width&*&scale)&/&2& & & &&var&offsetY = (imageView.bounds.size.height&-&inputImageSize.height&*&scale)&/&2&& & & && & & & faceViewBounds =&CGRectApplyAffineTransform(faceViewBounds,&CGAffineTransformMakeScale(scale, scale))& & & & faceViewBounds.origin.x&+=&offsetX& & & & faceViewBounds.origin.y&+=&offsetY&& & & && & & &&let&faceView =&UIView(frame: faceViewBounds)& & & & faceView.layer.borderColor&=&UIColor.orangeColor().CGColor& & & & faceView.layer.borderWidth&=&2&& & & && & & &&imageView.addSubview(faceView)& & }}在第二步里,除了通过宽、高比计算scale外,还计算了x、y轴的偏移,以确保在宽或高缩放的情况下都能正常工作(最后除以2是因为缩放时是居中显示,上下或左右都各有一半)。编译、运行,在不同的高度下的效果图:面部马赛克检测到面部以后,我们还能做一些有趣的操作,比如打上马赛克:这是苹果官方例子上的一张图,展示了把一张照片中所有的面部打上马赛克的方法:基于原图,创建一个将所有部分都马赛克的图片为检测到的人脸创建一张蒙版图用蒙版图,将完全马赛克的图和原图混合起来我们在VC上添加一个名为“马赛克”的按钮,将其事件连接到VC的pixellated方法上,然后开始实现马赛克的效果。具体步骤如下:创建完全马赛克的图使用CIPixellate滤镜,其参数设置:设置inputImage为原图可以根据自己的需要,选择设置inputScale参数,inputScale取值为1到100,取值越大,马赛克就越大这一步的效果图:为检测到的人脸创建蒙版图和之前一样,使用CIDetector检测人脸,然后为每一张脸:使用CIRadialGradient滤镜创建一个把脸包围起来的圆使用CISourceOverCompositing滤镜把各个蒙版(有几张脸其实就有几个蒙版)组合起来这一步的效果图:混合马赛克图、蒙版图以及原图用CIBlendWithMask滤镜来混合三者,其参数设置如下:设置inputImage为马赛克图设置inputBackground为原图设置inputMaskImage为蒙版图完整实现代码如下:@IBAction&func&pixellated() {& &&// 1.& &&var&filter =&CIFilter(name:&&CIPixellate&)& &&println(filter.attributes())& &&let&inputImage =&CIImage(image:&originalImage)& & filter.setValue(inputImage, forKey:&kCIInputImageKey)& &&// filter.setValue(max(inputImage.extent().size.width, inputImage.extent().size.height) / 60, forKey: kCIInputScaleKey)& &&let&fullPixellatedImage = filter.outputImage& &&// let cgImage = context.createCGImage(fullPixellatedImage, fromRect: fullPixellatedImage.extent())& &&// imageView.image = UIImage(CGImage: cgImage)& &&// 2.& &&let&detector =&CIDetector(ofType:&CIDetectorTypeFace,& & & & & & & & & & & & & & & context:&context,& & & & & & & & & & & & & & & options:&nil)& &&let&faceFeatures = detector.featuresInImage(inputImage)& &&// 3.& &&var&maskImage:&CIImage!& &&for&faceFeature&in&faceFeatures {& & & &&println(faceFeature.bounds)& & & &&// 4.& & & &&let&centerX = faceFeature.bounds.origin.x&+&faceFeature.bounds.size.width&/&2& & & &&let&centerY = faceFeature.bounds.origin.y&+&faceFeature.bounds.size.height&/&2& & & &&let&radius =&min(faceFeature.bounds.size.width, faceFeature.bounds.size.height)&& & & &&let&radialGradient =&CIFilter(name:&&CIRadialGradient&,& & & & & & & & & & & & & & & & & & & withInputParameters: [& & & & & & & & & & & & & & & & & & & &&&inputRadius0&&: radius,& & & & & & & & & & & & & & & & & & & &&&inputRadius1&&: radius&+&1,& & & & & & & & & & & & & & & & & & & &&&inputColor0&&:&CIColor(red:&0, green:&1, blue:&0, alpha:&1),& & & & & & & & & & & & & & & & & & & &&&inputColor1&&:&CIColor(red:&0, green:&0, blue:&0, alpha:&0),& & & & & & & & & & & & & & & & & & & &&kCIInputCenterKey&:&CIVector(x: centerX, y: centerY)& & & & & & ])& & & &&println(radialGradient.attributes())& & & &&// 5.& & & &&let&radialGradientOutputImage = radialGradient.outputImage.imageByCroppingToRect(inputImage.extent())& & & &&if&maskImage ==&nil&{& & & & & & maskImage = radialGradientOutputImage& & & & }&else&{& & & & & &&println(radialGradientOutputImage)& & & & & & maskImage =&CIFilter(name:&&CISourceOverCompositing&,& & & & & & & & withInputParameters: [& & & & & & & & & &&kCIInputImageKey&: radialGradientOutputImage,& & & & & & & & & &&kCIInputBackgroundImageKey&: maskImage& & & & & & & & ]).outputImage& & & & }& & }& &&// 6.& &&let&blendFilter =&CIFilter(name:&&CIBlendWithMask&)& & blendFilter.setValue(fullPixellatedImage, forKey:&kCIInputImageKey)& & blendFilter.setValue(inputImage, forKey:&kCIInputBackgroundImageKey)& & blendFilter.setValue(maskImage, forKey:&kCIInputMaskImageKey)& &&// 7.& &&let&blendOutputImage = blendFilter.outputImage& &&let&blendCGImage =&context.createCGImage(blendOutputImage, fromRect: blendOutputImage.extent())& &&imageView.image&=&UIImage(CGImage: blendCGImage)}&我详细的分为了7个部分:用CIPixellate滤镜对原图先做个完全马赛克检测人脸,并保存在faceFeatures中初始化蒙版图,并开始遍历检测到的所有人脸由于我们要基于人脸的位置,为每一张脸都单独创建一个蒙版,所以要先计算出脸的中心点,对应为x、y轴坐标,再基于脸的宽度或高度给一个半径,最后用这些计算结果初始化一个CIRadialGradient滤镜(我将inputColor1的alpha赋值为0,表示将这些颜色值设为透明,因为我不关心除了蒙版以外的颜色,这点和苹果官网中的例子有太一样,苹果将其赋值为了1)由于CIRadialGradient滤镜创建的是一张无限大小的图,所以在使用之前先对它进行裁剪(苹果官网例子中没有对其裁剪。。),然后把每一张脸的蒙版图合在一起用CIBlendWithMask滤镜把马赛克图、原图、蒙版图混合起来输出,在界面上显示运行效果:一个简单的对照片进行马赛克处理的例子就完成了。我在GitHub上会保持更新。UPDATED:细心的朋友会发现马赛克的面积比检测到的面积要大:这是因为计算马赛克radius时没有考虑缩放的因素,只要先计算出scale,再把scale和现在的radius相乘就能得到精确的范围。计算scale:var&scale =&min(imageView.bounds.size.width&/&inputImage.extent().size.width,& & & & & & & &&imageView.bounds.size.height&/&inputImage.extent().size.height)修正radius:let&radius =&min(faceFeature.bounds.size.width, faceFeature.bounds.size.height)&*&scale修正后的马赛克效果与人脸检测效果:参考资料:
版权声明:如需转载,请注明出处,谢谢!
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:799610次
积分:9823
积分:9823
排名:第710名
原创:120篇
评论:303条
如果有任何问题欢迎随时与我沟通联系
或是CSDN私信
传送门:,如果有什么问题,我会尽力解答,还望共同学习
如需转载,请注明出处,谢谢!
欢迎Star、欢迎PR
文章:24篇
阅读:158991
文章:52篇
阅读:374093
阅读:48252
(3)(5)(8)(1)(5)(2)(4)(5)(5)(14)(6)(1)(3)(2)(3)(1)(5)(2)(1)(8)(8)(4)(1)(4)(17)(9)(1)(1)(1)

我要回帖

更多关于 视频去马赛克软件 的文章

 

随机推荐