美文网首页iOS Developer小斑iOS Swift && Objective-C
CIFilter_看了这个,你就可以打造自己的美图秀秀

CIFilter_看了这个,你就可以打造自己的美图秀秀

作者: Jorn丶Wu | 来源:发表于2016-09-21 23:38 被阅读2544次

    上篇文章iOS_最全的二维码篇说要给大家简绍一下强大而好玩工具CIFilter,所以这今天晚上给大家分享一个demo。我保证你看了这篇文章之后,肯定能做出自己的美图工具,我发誓(虽然并没卵用)。

    CIFilter,其实就是一个滤镜。喜欢摄影的小伙伴,可能接触过PS,而接触过PS的小伙伴,对滤镜肯定不陌生。而且有了解相关知识的小伙伴,对于颜色和图片处理的认知也一定信手捏来。什么RGB,什么CMYK,什么灰度图片,什么高斯模糊,什么锐化,什么对比度,什么饱和度,什么颜色通道,为什么值在255之间等等。我为什么知道这些,其实小Jorn我大一的时候,刚上大学,课不是很多,时间充足,那时候,都还不知道LOL(呵呵,现在,此处省略1W字),还带着高中的稚气和志气。想想要学点啥一技之长。记得高中时候,有次去拍一寸照,看那sb老板,不懂PS,硬是给我照片乱修。结果照片老丑,还硬坑我20块钱。所以大学就想到自己学学PS,在处理照片的时候可以自己修。而且,PS还可以做很多平面设计。说不定以后可以去做设计的工作。一个好的设计师,薪资还是很高的(_)。所以自己学了一年多的PS(堪称大神了,然并卵),后来学的差不多了。海报设计,网页设计,UI设计,还有其他各种设计,图文排版,图片处理,婚纱处理,P图等什么滴都自己做过(厉害吧)。大二的时候又学了一年的AI,后来还想学AE来着(因为大学嘛,越到后来,你懂得。游戏也开始玩起来了)。学了PS和AI,其实我还是觉得很不错的,不只在一个地方看到,PS和AI就像左右手,这也是做平面设计的工作者必备的两技能。一个负责位图,一个负责矢量图,功能都超强大。现在iOS上用的icon基本都是用这两工具设计的。虽然现在不慎混到了程序猿的大流。不过想想懂这也不是无可用武之地,至少在图片处理,颜色的认知上还有挺有帮助的(呵呵,安慰一下自己)。(扯远了。。。)

    言归正传,你学会使用CIFilter,你就可以随意处理你想要的效果。系统给我们提供的滤镜种类是非常的多,不是十几个,是几十个。没错!

    CoreImage是个非常强大框架,集图片的几乎所有操作编辑于一身,CIFilter只是其中的一个工具,主要作用是给图片渲染不同的效果
    CIFilter的种类很多,所以苹果的官方文档也只能给出部分常用的种类的说明。
    官方文档给出的部分说明:点击这里
    虽然官方文档很简洁,但国外的大神们已经证明这是个相当强悍的框架,
    不仅功能强大,而且可以直接使用GPU,效率奇高,甚至可以实时的对视频进行渲染。

    下面让我们来看看,如何具体使用它:
    首先你需要导入CoreImage.framework框架;进行Mac(不是iOS)开发的同学请导入QuartzCore.framework框架,包含在其中了。
    然后我们先来看看3个主要的类:
    CIContext:它与CoreGraphicsOpenGL context类似,所有CoreImage的处理流程都通过它来进行;
    CIImage:它用来存放图片数据,可以通过UIImage,图片文件或像素数据创建;
    CIFilter:通过它来定义过滤器的详细属性。
    CIContext有两种初始化方法,分别对应GPUCPU

    创建基于GPU的CIContext对象
    context = [CIContext contextWithOptions: nil];
    创建基于CPU的CIContext对象

    context = [CIContext contextWithOptions: [NSDictionarydictionaryWithObject:[NSNumber numberWithBool:YES]
        forKey:kCIContextUseSoftwareRenderer]];
    

    一般采用第一种基于GPU的,因为效率要比CPU高很多,但是要注意的是基于GPU的CIContext对象无法跨应用访问。 比如你打开UIImagePickerController要选张照片进行美化,如果你直接在UIImagePickerControllerDelegate的委托方法里调用CIContext对象进行处理,那么系统会自动将其降为基于CPU的,速度会变慢,所以正确的方法应该是在委托方法里先把照片保存下来,回到主类里再来处理。

    CIFilter的强大之处在于,可以叠加来得到多种效果。看过iOS_最全的二维码篇这篇文章的小伙伴肯定知道了什么叫叠加,其实如果你按那篇文章我说的练习一下,你就会发现,得到的图片也还是不过清晰。因为,二维码生成的原图太小,放大就很模糊。其实我在用PS处理手机拍的图片时,一开始少不了这三步,补点光,太暗;增加的对比度,不够鲜明;锐化一下,细节不过清晰。对,就是锐化一下。等下会让你获得一副清晰的二维码图。

    首先让你知道,怎么查看到底有哪些滤镜:

            /* Categories */
    //        public let kCICategoryDistortionEffect: String ///失真效果
    //        public let kCICategoryGeometryAdjustment: String ///几何调整
    //        public let kCICategoryCompositeOperation: String ///复合操作
    //        public let kCICategoryHalftoneEffect: String ///半色调效果
    //        public let kCICategoryColorAdjustment: String ///颜色调整
    //        public let kCICategoryColorEffect: String ///颜色效果
    //        public let kCICategoryTransition: String ///翻转
    //        public let kCICategoryTileEffect: String ///瓦片效果
    //        public let kCICategoryGenerator: String ///生成器
    //        @available(iOS 5.0, *)
    //        public let kCICategoryReduction: String ///削减
    //        public let kCICategoryGradient: String ///梯度
    //        public let kCICategoryStylize: String ///风格
    //        public let kCICategorySharpen: String ///锐化
    //        public let kCICategoryBlur: String ///模糊
    //        public let kCICategoryVideo: String ///视频
    //        public let kCICategoryStillImage: String ///静态图片
    //        public let kCICategoryInterlaced: String ///交叉
    //        public let kCICategoryNonSquarePixels: String ///非方形像素
    //        public let kCICategoryHighDynamicRange: String ///高动态范围
    //        public let kCICategoryBuiltIn: String ///内建
    //        @available(iOS 9.0, *)
    //        public let kCICategoryFilterGenerator: String ///滤镜生成器
    

    这是系统含有的所有大类。
    想知道有哪些filter类型或想查找想要的filter类型,可以通过先查找大的分类(如上),然后在查找子项。

            let names = CIFilter.filterNames(inCategory: kCICategoryGenerator) ///kCICategoryGenerator大类
            print(names)
    

    这样就会输出该大类包含的所有滤镜。如上会输出所有的生成器类型CIFilter种类:

     ///生成器大类所包含的所有生成器子类,如:"`CICode128BarcodeGenerator`"(条形码生成器),"CIQRCodeGenerator"(二维码生成器)
    //        ["CIAztecCodeGenerator",
    //         "CICheckerboardGenerator",
    //         "CICode128BarcodeGenerator", ///条形码生成器
    //         "CIConstantColorGenerator",
    //         "CILenticularHaloGenerator",
    //         "CIPDF417BarcodeGenerator",
    //         "CIQRCodeGenerator", ///二维码生成器
    //         "CIRandomGenerator",
    //         "CIStarShineGenerator",
    //         "CIStripesGenerator",
    //         "CISunbeamsGenerator"]
    

    然后就可以创建滤镜对象了,有两方法,含参数的仅iOS8之后可用,iOS上不设输入参数,系统会使用默认值,但是mac是会报错,输入参数不明确:

    /** Creates a new filter of type 'name'.
             On OSX, all input values will be undefined.
             On iOS, all input values will be set to default values. */
            /// 要是是mac开发,创建filter对象必须提供输入参数,iOS可以忽略,系统会使用默认值。
            //init?(name: String)
            //@available(iOS 8.0, *) ///iOS 8.0 之后
            //init?(name: String, withInputParameters params: [String : Any]?)
    

    看看该滤镜需要设置那些输入参数,如此:

            let filter = CIFilter(name: "CIQRCodeGenerator")
            let inpoutkeys = filter?.inputKeys ///查看这个filter的所有输入参数
            let outputKeys = filter?.outputKeys ///查看这个filter的所有输出参数
            
            print("inpoutkeys:",inpoutkeys)
            print("outputKeys:",outputKeys)
    

    设置参数用KVC来设置,常用的key,系统已经作为常量给出,可以cmd加鼠标左键点击CIFilter类名进去查看。
    如上,二维码生成器滤镜需要量输入参数:

    ///eg.1 ///示例代码KVO
            /// 1. 实例化二维码滤镜
            let filter = CIFilter(name: "CIQRCodeGenerator")///二维码
            
            /// 2. 恢复滤镜的默认属性 ///值得注意
            filter?.setDefaults()
            
            /// 3. 将字符串转换成二进制数据,(生成二维码所需的数据)
            let string = "hello word"
            let data = string.data(using: String.Encoding.utf8)///Swift 3.0
            
            /// 4. 通过KVO把二进制数据添加到滤镜inputMessage中
            filter?.setValue(data, forKey: "inputMessage")
            filter?.setValue("H", forKey: "inputCorrectionLevel")
            
            /// 5. 获得滤镜输出的图像
            let outputImage = filter?.outputImage ///CIImage
            
            /// 6. 将CIImage转换成UIImage,并放大显示
            //let originQRCodeImage = UIImage(ciImage: outputImage!, scale: 0.07, orientation: UIImageOrientation.up) ///原生二维码图片 ///这样将图片放大会变得模糊
    

    这样得到的originQRCodeImage是模糊的,把scale设为一时得到实际大小,但太小。在上篇文章我提过,需要进行重绘(效果80分)。这里我们可以使用缩放滤镜来缩放。生产高质量的、按比例缩放的源图像的版本(这是文档说明,然我并没发现有啥牛掰,还是模糊)。
    CIFilter为"CILanczosScaleTransform"(兰索斯缩放变化滤镜),但为了达到彩色的效果我们先把颜色滤镜加上,CIFliter为"CIFalseColor"(伪色滤镜):

    let colorFilter = CIFilter(name: "CIFalseColor")///颜色滤镜
            colorFilter!.setDefaults()
            colorFilter!.setValue(outputImage
                , forKey:kCIInputImageKey)
            
            colorFilter!.setValue(CIColor(red: 33.0 / 225.0, green: 192.0 / 225.0, blue: 174.0 / 225.0, alpha: 1.0), forKey:"inputColor0")///二维码元素(像素)
            colorFilter!.setValue(CIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1), forKey:"inputColor1")///背景
            
            let colorImgae = colorFilter!.outputImage
    
     let scaleFilter = CIFilter(name: "CILanczosScaleTransform") ///兰索斯缩放变化滤镜
            scaleFilter?.setDefaults()
            scaleFilter?.setValue(colorImgae, forKey: kCIInputImageKey)
            scaleFilter?.setValue(1.0, forKey: kCIInputScaleKey)
            scaleFilter?.setValue(1.0, forKey: kCIInputAspectRatioKey)
            let scaleImage = scaleFilter?.outputImage
    

    所以通过添加锐化滤镜来锐化一下,CIFilter为"CISharpenLuminance"(亮度锐化,对光度有作用,度色度没影响):

     let sharpenFilter = CIFilter(name: "CISharpenLuminance") ///细节锐化滤镜
            ///It operates on the luminance of the image; the chrominance of the pixels remains unaffected.
            sharpenFilter?.setDefaults()
            sharpenFilter?.setValue(scaleImage, forKey: kCIInputImageKey)
            sharpenFilter?.setValue(10.0, forKey: kCIInputSharpnessKey)
            let sharpenImage = sharpenFilter?.outputImage
    

    最后得到图片:

    let newQRCodeImage = UIImage(ciImage: sharpenImage!)
            let imgBtn = UIButton(type: .custom)
            imgBtn.frame = self.view.frame
            imgBtn.setImage(newQRCodeImage, for: .normal)
            self.view.addSubview(imgBtn)
    

    通过参数的设置,得到的图片效果70分;

    而在进行重绘后,再进行锐化处理的话,你就会发现效果是真的不错(95分)。

    因为升为了Switft3.0代码,所以代码需要少量修改。主要就是Swift3.0把CoreGraphics的全局方法改为了实例方法,

    
    func createUIimageWithCGImage(ciImage image: CIImage, widthAndHeightValue wh: CGFloat) -> CIImage {
            let ciRect = image.extent.integral///根据容器得到适合的尺寸
            let scale = min(wh / ciRect.width, wh / ciRect.height)
            
            ///获取bitmap
            let width  = size_t(ciRect.width * scale)
    
            let height  = size_t(ciRect.height * scale)
            let cs = CGColorSpaceCreateDeviceGray()///灰度颜色通道 ///CGColorSpaceRef
            
            let info_UInt32 = CGImageAlphaInfo.none.rawValue
            let bitmapRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 0, space: cs, bitmapInfo: info_UInt32)
            
            let contex = CIContext(options: nil) ///  创建基于GPU的CIContext对象,性能和效果更好
            let bitmapImageRef = contex.createCGImage(image, from: CGRect(x: ciRect.origin.x, y: ciRect.origin.y, width: ciRect.size.width, height: ciRect.size.height)) ///CGImageRef
            
            ///swift 3.0, 把全局方法改为了实例方法
            bitmapRef!.interpolationQuality = CGInterpolationQuality.high///写入质量高,时间长
            bitmapRef!.scaleBy(x: scale, y: scale) ///调整“画布”的缩放
            bitmapRef?.draw(bitmapImageRef!, in: ciRect, byTiling: true)///绘制图片
            
            ///保存
            let scaledImage = bitmapRef!.makeImage() ///cgimage
            
            ///bitmapRef和bitmapImageRef不用主动释放,Core Foundation自动管理
            //let originImage = UIImage(CGImage: scaledImage!) ///原生灰度图片(灰色)
            
            let ciImage = CIImage(cgImage: scaledImage!) ///ciimage
            //let newQRCodeImage = UIImage(cgImage: scaledImage!) ///uiimage
            
            return ciImage
        }
    

    附录:

    ///附:你要是细心,或者有点好奇心,你可能会问,为什么我们看到的二维码中间都有一个小图片,
    ///确实现在的大多二维码生成工具都喜欢中间贴上一个小图,但是上述生成的二维码并没有,
    ///其实这很简单,这也是我没有在这个小问题给出示例的原因。其实二维码在缺少小部分的情况下,并不影响存储信息的完整性
    ///所以小图片是另外加上去的,只是遮掉了一小块二维码内容,这并不影响什么。
    ///然而在一张图上添加另一张图,相信你也觉得这并不是什么问题。自己试试吧。
    ///如:用quartz2D 、drawImga的方法即可。

    下图:1.锐化;2.重绘;3.重绘+锐化


    1.锐化;2.重绘;3.重绘+锐化.png

    相关文章

      网友评论

      • xinyu391:楼主这句话,很误人啊
        "但是要注意的是基于GPU的CIContext对象无法跨应用访问。 比如你打开UIImagePickerController要选张照片进行美化,如果你直接在UIImagePickerControllerDelegate的委托方法里调用CIContext对象进行处理,那么系统会自动将其降为基于CPU的,速度会变慢"
      • c4a7903a42a0:嗨 博主你好,我看到文中CILanczosScaleTransform这个filter设置的值为1,这样也能起到放大的效果吗?
        Jorn丶Wu:@wizzardj 这是调整CIFilter的输出图片大小,没有锚点。
        c4a7903a42a0:@JornWu丶WwwwW 好的明白了,另外我想问一下,关于缩放的锚点,是不是设置不了?总是从(0,0)开始缩放?
        Jorn丶Wu:应该没有,默认值就是1.00,我贴出来的那个代码只是用法,并非实际值。:blush:
      • 熊皮皮:那么,锐化的作用就是保留高频数据、增强细节信息?
        Jorn丶Wu:@熊皮皮 这个最好百科看一下图像锐化,比较详细…
      • sea_waves:博主的demo下载链接呢?
        sea_waves: @JornWu丶WwwwW 好的,谢谢啦
        Jorn丶Wu:@seawaves 这个没demo,代码基本贴出来了……整理一下吧……

      本文标题:CIFilter_看了这个,你就可以打造自己的美图秀秀

      本文链接:https://www.haomeiwen.com/subject/mftzettx.html