Core Image Filter

Bắt đầu

Trước khi bắt đầu chúng ta hãy thảo luận một chút về framework CoreImage

  • CIContext: tất cả quá trình xử lý của core image đều kết thúc trên CIContext, nó là một cái gì đó giống như context trong core graphics hay opengl
  • CIImage: class này sẽ giữ dữ liệu ảnh, nó có thể được tạo ra từ UIImage, từ file ảnh
  • CIFilter: class này trực tiếp định nghĩa các thuộc tính của đối tượng filter – những gì được hiển thị, ví dụ như filter vibrance, color, cropping và nhiều thứ khác Chúng ta sẽ sử dụng lần lượt từng class đó trong project

Project CoreImageDemo

  • Tạo project với template Single View Apllication và nhập tên CoreImageDemo, select iPhone và sử dụng ngôn ngữ Swift

Screen Shot 2016-06-26 at 20.19.08.png

  • Download một ảnh bất kì để phục vụ cho việc sử dụng filter
  • Kéo UIImageView vào Main.storyboard và thiết lập option Aspect Fit từ attrubites inspector
  • Kéo constraint cho image view đó với superview 3 constraint o Top space to layout guide, set constant về 0 nếu cần o Add center constraint o Add equal width constraint
  • Cuối cùng để ràng buộc được chiều cao của image view bạn hãy kéo constraint với chính nó và lựa chọn aspect ratio. Như vậy khi chiều width thay đổi thì height luôn tự động thay đổi theo tỉ lệ
  • Kéo outlet và đặt tên imageView
  • Build and run project bạn sẽ thấy một màn hình trống rỗng

Basic image filtering

Bốn bước cơ bản để thực hiện filter

  1. Tạo một đối tượng CIImage
  2. Tạo một CIContext
  3. Tạo một CIFilter
  4. Nhận filter output

Các bạn có thể xem đoạn mã sau


//  đường dẫn tới ảnh
let fileURL = NSBundle.mainBundle().URLForResource("image", withExtension: "png")
 
// ảnh được tạo ra với đầu vào là đường dẫn ảnh
let beginImage = CIImage(contentsOfURL: fileURL)
 
// tạo một filter với name CISepiaTone và set image cho filter cùng tham số 0.5 (kCIInputIntensityKey)
let filter = CIFilter(name: "CISepiaTone")
filter.setValue(beginImage, forKey: kCIInputImageKey)
filter.setValue(0.5, forKey: kCIInputIntensityKey)
 
// Nhận đầu ra sau khi filter và hiển thị ảnh
let newImage = UIImage(CIImage: filter.outputImage)
self.imageView.image = newImage

Kết quả sau khi filter

Screen Shot 2016-06-26 at 23.28.19.png

Screen Shot 2016-06-26 at 21.52.17.png

Sử dụng context

  • Như đã đề cập trước đó, bạn cần một CIContext để áp dụng vào filter, điều mà ví dụ trên không có đề cập tới. Trong trường hợp này chúng ta đang chỉ filter với một image. Nhưng trong trường hợp chúng ta cần drawback một lượng lớn thì chúng ta cần tới CIContext để có thể reuse nhằm mục đích tăng performance. Ví dụ trong trường hợp bạn sử dụng slider để thay đổi giá trị, thì khi đó cần filter liên tục, vậy tối ưu hoá hiệu năng là điều rất cần.

  • Để tối ưu hoá bạn hãy xoá đoạn mã trên và thay vào đó là đoạn mã sau

// Tạo CIContext
let context = CIContext(options:nil)
 
// Tạo CIImage
let cgimg = context.createCGImage(filter.outputImage, fromRect: filter.outputImage.extent())
 
// Nhận output
let newImage = UIImage(CGImage: cgimg)
self.imageView.image = newImage

Changing Filter Values

  • Bạn hãy tạo một slider để thay đổi giá trị tham số filter (realtime)
  • Bạn cần một vài instance variables, nó bao gồm 3 properties như sau
var context: CIContext!
var filter: CIFilter!
var beginImage: CIImage!
  • Thay đổi mã trong viewDidLoad để sử dụng 3 properties trên
beginImage = CIImage(contentsOfURL: fileURL)
 
filter = CIFilter(name: "CISepiaTone")
filter.setValue(beginImage, forKey: kCIInputImageKey)
filter.setValue(0.5, forKey: kCIInputIntensityKey)
 
let outputImage = filter.outputImage
 
context = CIContext(options:nil)
let cgimg = context.createCGImage(outputImage, fromRect: outputImage.extent())
  • Để có thể thay đổi output theo giá trị của slider và có sử dụng instance properties thì chúng ta cần sử dụng đoạn mã sau

    • Get output CIImage từ CIFilter
    • Convert CIImage sang CGImage
    • Convert CGImage sang UIImage và hiển thị
@IBAction func amountSliderValueChanged(sender: UISlider) {
 
    let sliderValue = sender.value
 
    filter.setValue(sliderValue, forKey: kCIInputIntensityKey)
    let outputImage = filter.outputImage
 
    let cgimg = context.createCGImage(outputImage, fromRect: outputImage.extent())
 
    let newImage = UIImage(CGImage: cgimg)
    self.imageView.image = newImage
}

Getting Photos from the Photo Album

  • Giờ bạn có thể thay đổi giá trị của filter với bất cứ ảnh nào trong album. Bạn có thể sử dụng UIImagePickerController để lấy ảnh từ album.
  • Bạn có thể tạo một button để bring picker đó lên
@IBAction func loadPhoto(sender : AnyObject) {
  let pickerC = UIImagePickerController()
  pickerC.delegate = self
  self.presentViewController(pickerC, animated: true, completion: nil)
}

  • Tiếp theo để có thể lấy được ảnh bạn phải implement delegate UIImagePickerControllerDelegate
class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info: NSDictionary!) {
  self.dismissViewControllerAnimated(true, completion: nil);
 
  let gotImage = info[UIImagePickerControllerOriginalImage] as UIImage
 
  beginImage = CIImage(image:gotImage)
  filter.setValue(beginImage, forKey: kCIInputImageKey)
  self.amountSliderValueChanged(amountSlider)
}
  • Function trên với mục đích lấy ảnh dạng CIImage và filter theo giá trị hiện tại của slider

Lưu ảnh sau khi filter vào album sử dụng AssetLibrary

@IBAction func savePhoto(sender: AnyObject) {
    // 1
    let imageToSave = filter.outputImage
 
    // 2
    let softwareContext = CIContext(options:[kCIContextUseSoftwareRenderer: true])
 
    // 3
    let cgimg = softwareContext.createCGImage(imageToSave, fromRect:imageToSave.extent())
 
    // 4
    let library = ALAssetsLibrary()
    library.writeImageToSavedPhotosAlbum(cgimg,
      metadata:imageToSave.properties(),
      completionBlock:nil)
}
  • Câu hỏi đặt ra liệu có bao nhiêu loại filter. Đoạn mã sau sẽ cho bạn biết có bao nhiêu loại filter
func logAllFilters() {
  let properties = CIFilter.filterNamesInCategory(kCICategoryBuiltIn)
  println(properties)
 
  for filterName: AnyObject in properties {
    let fltr = CIFilter(name:filterName as String)
    println(fltr.attributes())
  }
}
  • Kết quả sau khi log các loại filter
[CIAttributeFilterDisplayName: Color Monochrome, inputColor: {
    CIAttributeClass = CIColor;
    CIAttributeDefault = "(0.6 0.45 0.3 1)";
    CIAttributeType = CIAttributeTypeColor;
}, inputImage: {
    CIAttributeClass = CIImage;
    CIAttributeType = CIAttributeTypeImage;
}, CIAttributeFilterCategories: (
    CICategoryColorEffect,
    CICategoryVideo,
    CICategoryInterlaced,
    CICategoryNonSquarePixels,
    CICategoryStillImage,
    CICategoryBuiltIn
), inputIntensity: {
    CIAttributeClass = NSNumber;
    CIAttributeDefault = 1;
    CIAttributeIdentity = 0;
    CIAttributeSliderMax = 1;
    CIAttributeSliderMin = 0;
    CIAttributeType = CIAttributeTypeScalar;
}, CIAttributeFilterName: CIColorMonochrome]

Vậy là mình đã hướng dẫn các bạn sử dụng Core Image để filter ảnh, trên đây là kiến thức basic khi sử dụng core image bạn cần biết

All Rights Reserved