ios - Swift CIfilter 从 collectionView 中选择

标签 ios swift uiimage core-image ciimage

我正在开发一个应用程序,它可以让用户选择照片并应用滤镜并保存。 基本上是 Instagram 应用程序相机的副本,用户可以在其中从图库中选择一张照片,应用滤镜,然后将其发布。

该应用程序运行良好,我唯一的问题是在使用过滤后的图像加载 collectionView 时,过程有点慢。 我已经阅读了一些内容(我是 swift 的新手,这是我第一次使用核心图像)并且我尝试应用我学到的所有建议。 但是我相信该应用程序仍然运行缓慢。

所以这是我所做的。

我已经创建了一个带有过滤器的模型:

public protocol Filter {
 // reference to the core image filter
var filter: CIFilter { get }
 // output of the filter.
var outputImage: CIImage? { get }
}

 // common to all filters.
 extension Filter {
   public var outputImage: CIImage? { return self.filter.outputImage }
}

//Bloom
public class Bloom: Filter {

public let filter: CIFilter

public init(inputImage: CIImage, inputRadius: CGFloat = 10.0, 
 inputIntensity: CGFloat = 1.0) {
    let parameters:[String : Any] = [
        "inputImage":inputImage,
        "inputRadius":inputRadius,
        "inputIntensity":inputIntensity        ]
    guard let filter = CIFilter(name:"CIBloom", withInputParameters: parameters) else { fatalError() }
    self.filter = filter
  }
}


// Box Blur
public class BoxBlur: Filter {

public let filter: CIFilter

public init(inputImage: CIImage, inputRadius: CGFloat = 10.0) {
    let parameters:[String : Any] = [
        "inputImage":inputImage,
        "inputRadius":inputRadius        ]
    guard let filter = CIFilter(name:"CIBoxBlur", withInputParameters: parameters) else { fatalError() }
    self.filter = filter
  }
}
...........

等等我需要的所有过滤器。

然后我创建了一个类来创建一个包含所有过滤图像的 UIImage 数组:

class filteredImages {
static var filterToApply: Filter!
static var filterNames = [
    "Original","Sepia","Poster",....
]

static var filteredImages = [UIImage]()
static var filteredImage: UIImage!

static func createImageArray(inputImage: CIImage, onSuccess: @escaping () -> () ) {
    filteredImages.removeAll()
    for filter in filterNames {
        switch filter {
        case "Original":
            filteredImage = UIImage(ciImage:inputImage)
            filteredImages.append(filteredImage)
        case "Sepia":
            filterToApply = SepiaTone(inputImage: inputImage, inputIntensity: 0.8)
            filteredImage = UIImage(ciImage: filterToApply.outputImage!)
            filteredImages.append(filteredImage)
............
      }
      onSuccess()
     }
   }
}

最后在我的 Controller 中:

var filteredImagesArray = [UIImage]()
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    let inputImage = CIImage(image: (originalImage.image?.resized(toWidth: 120))!)!
    filteredImages.createImageArray(inputImage: inputImage) {
        self.filteredImagesArray = filteredImages.filteredImages
    }
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FilterCell", for: indexPath) as! FilterCell

        cell.filteredImage.image = filteredImagesArray[indexPath.row]
        cell.filterName.text = filteredImages.filterNames[indexPath.row]
        cell.layer.borderWidth = 0.7
        cell.layer.borderColor = UIColor.white.cgColor
    return cell
}

我还有一个减少“原始”图像的扩展:

extension UIImage {
func resized(toWidth width: CGFloat) -> UIImage? {
    let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
    UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
    defer { UIGraphicsEndImageContext() }
    draw(in: CGRect(origin: .zero, size: canvasSize))
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}

有没有办法让它更快? 我错过了什么吗?

谢谢。

------------根据拉迪斯拉夫的要求更新

这是我用来从库中获取图像的代码:

  enum Section: Int {
    case allPhotos = 0
    case smartAlbums
    case userCollections

    static let count = 3
}
var allPhotos: PHFetchResult<PHAsset>!
var allPhotosFromAlbum = PHFetchResult<PHAsset>()
var smartAlbums: [PHAssetCollection] = []
var userCollections: PHFetchResult<PHAssetCollection>!
let subtypes:[PHAssetCollectionSubtype] = [
    .smartAlbumFavorites,
    .smartAlbumPanoramas,
    .smartAlbumScreenshots,
    .smartAlbumSelfPortraits,
    .smartAlbumVideos,
    .smartAlbumRecentlyAdded,
    .smartAlbumSelfPortraits
]
 override func viewDidLoad() {
    super.viewDidLoad()
    // Create a PHFetchResult object for each section in the table view.
    let allPhotosOptions = PHFetchOptions()
    allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    allPhotos = PHAsset.fetchAssets(with: allPhotosOptions)
    let options = PHFetchOptions()
    options.predicate = NSPredicate(format: "estimatedAssetCount > 0")
    options.sortDescriptors = [NSSortDescriptor(key: "localizedTitle", ascending: false)]
    smartAlbums = fetchSmartCollections(with: .smartAlbum, subtypes: subtypes)
    userCollections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .albumRegular, options: options)
}

这是我用来获取带有子类型的 PHAssetCollection 的函数:

private func fetchSmartCollections(with: PHAssetCollectionType, subtypes: [PHAssetCollectionSubtype]) -> [PHAssetCollection] {
    var collections:[PHAssetCollection] = []
    let options = PHFetchOptions()
    options.includeHiddenAssets = false

    for subtype in subtypes {
        if let collection = PHAssetCollection.fetchAssetCollections(with: with, subtype: subtype, options: options).firstObject, collection.photosCount > 0 {
            collections.append(collection)
        }
    }

    return collections
}

我在 tableView 中显示结果,然后根据选择将相册中的所有图像传递给另一个 Controller 。

这是我实际显示要选择的图像的 Controller 代码(我们称它为 mMainVC):

fileprivate let imageManager = PHCachingImageManager()
var fetchResult: PHFetchResult<PHAsset>!
var assetCollection: PHAssetCollection!

 override func viewDidLoad() {
    super.viewDidLoad()
if fetchResult == nil {
        let allPhotosOptions = PHFetchOptions()
        allPhotosOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        fetchResult = PHAsset.fetchAssets(with: allPhotosOptions)
    }
}

这里是从 fetchResult 获取图像的函数:

func selectImageFromAssetAtIndex(index: Int) {
    let asset = fetchResult.object(at: index)
    let size = scrollViewImage.frame.size.width

    PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: size, height: size), contentMode: .aspectFill, options: nil, resultHandler: { (image, info) in
        DispatchQueue.main.async {
            self.displayImageInScrollView(image: image!)
        }
    })
}

--------------------屏幕截图和视频

enter image description here enter image description here

这是视频的链接:https://drive.google.com/file/d/0B6U8olIA_ZS8U0tpN0hKOWdrVm8/view?usp=sharing

最佳答案

我觉得你做的一切都很好,唯一的问题是

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    let inputImage = CIImage(image: (originalImage.image?.resized(toWidth: 120))!)!
    filteredImages.createImageArray(inputImage: inputImage) {
        self.filteredImagesArray = filteredImages.filteredImages
    }
}

createImageArray 在主线程上被调用,这就是您的应用卡住的原因。

我会向每个 collectionView cell 添加状态 loadingactivityIndi​​cator 并且单元格将在 loading 状态,直到您从 createImageArray 调用返回结果,然后您将使用过滤后的图像填充单元格,例如:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)
    DispatchQueue.global(qos: .userInitiated).async {[weak self] in
        let inputImage = CIImage(image: (originalImage.image?.resized(toWidth: 120))!)!
        filteredImages.createImageArray(inputImage: inputImage) {
            self.filteredImagesArray = filteredImages.filteredImages
            DispatchQueue.main.async {
                let indexPaths = collectionView.indexPathsForVisibleItems

                collectionView.reloadItems(at: indexPaths)
            }
        }
    }
}

因此在您重新加载可见项目时 self.filteredImagesArray 将被设置并且您将能够禁用 loading 状态并显示来自 过滤图像数组

关于ios - Swift CIfilter 从 collectionView 中选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46745733/

相关文章:

image - 如何将 jpg 或 png 图像添加到 UIImage,然后在 UIImageView 中显示?

objective-c - 使用 mask 在 CALayer 上遮挡动画

ios - 如何在 iOS 中编写应用程序更新?

ios - 按下右栏按钮项目移动左栏按钮项目

ios - 是否需要在转义完成 block 后调用 return?

ios - 如何将图像放在 UIActionSheet 上?

swift - UICollectionViewFlowLayout.scrollingDirection 改变强制重新加载 - Swift 4

ios - swift 3 : Create UIImage from UIBezierPath

ios - 如何将 rx_tap (UIButton) 绑定(bind)到 ViewModel?

iphone - 自定义 Facebook 好友选择器?