[核心图像:当改变滑块的强度时,照片效果在真实的iPhone中反应缓慢/变化

问题描述 投票:0回答:1

下面的代码应用图像选择器并在contentView中显示过滤的图像,在这种情况下,我使用了SepiaTone效果。当我在滑块中移动时,更改滤镜强度。感光反应延迟,滑动不流畅。

但是,当使用App Store中的某些应用程序(如“ Afterlight”)及其照片滤镜时,当用户移动滑块时,平滑地转换为照片效果。

那么有什么区别,那些应用程序使用其他框架吗?如果我们仍然使用Core Image,如何在不断变化的滤镜强度下提高性能?

ImagePicker

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {

    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker

        init(_ parent: ImagePicker) {
            self.parent = parent
        }

        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let uiImage = info[.originalImage] as? UIImage {
                parent.image = uiImage
            }

            picker.dismiss(animated: true, completion: nil)
        }
    }

    @Binding var image: UIImage?

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }

    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {

    }
}

ContentView

import CoreImage
import CoreImage.CIFilterBuiltins
import SwiftUI

struct ContentView: View {

    @State private var image: Image?
    @State private var filterIntensity = 0.5

    @State private var showingImagePicker = false
    @State private var inputImage: UIImage?

    @State private var currentFilter = CIFilter.sepiaTone()
    let context = CIContext()

    var body: some View {
        let intensity = Binding<Double>(
            get: {
                self.filterIntensity
        },
            set: {
                self.filterIntensity = $0
                self.applyProcessing()
        })

        return NavigationView {
            VStack {
                ZStack {
                    Rectangle()
                        .fill(Color.secondary)

                    if image != nil {
                        image?
                            .resizable()
                            .scaledToFit()
                    } else {
                        Text("Tap to select a picture")
                            .foregroundColor(.white)
                            .font(.headline)
                    }
                }
                .onTapGesture {
                    self.showingImagePicker = true
                }

                HStack {
                    Text("Intensity")
                    Slider(value: intensity)
                }
                .padding(.vertical)

                HStack {
                    Button("Change Filter") {
                        // change filter
                    }

                    Spacer()

                    Button("Save") {
                        // save the picture
                    }
                }
            }
            .padding([.horizontal, .bottom])
            .navigationBarTitle("Instafilter")
            .sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
                ImagePicker(image: self.$inputImage)
            }
        }
    }

    func loadImage() {
        guard let inputImage = inputImage else { return }

        let beginImage = CIImage(image: inputImage)
        currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
        applyProcessing()
    }

    func applyProcessing() {
        currentFilter.intensity = Float(filterIntensity)
        guard let outputImage = currentFilter.outputImage else { return }

        if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
            let uiImage = UIImage(cgImage: cgImage)
            image = Image(uiImage: uiImage)
        }
    }
}
performance swiftui core-image
1个回答
0
投票

这有助于在后台线程中执行图像过滤,以免在处理图像时阻塞主队列。同样,不对任何更改做出反应而是一起“分组更改”并且每50毫秒仅进行一次图像计算将是有意义的。两者都可以使用Combine框架来实现,这是基于您的代码的示例。效果被分隔在单独的类ImageEffect中,该类使用debounce operator优化后,只要inputImage / filterIntensity发生更改,就使用Combine在后台执行图像处理。

import CoreImage
import CoreImage.CIFilterBuiltins
import SwiftUI
import Combine

class ImageEffect: ObservableObject {

    @Published var filterIntensity = 0.5
    @Published var inputImage: UIImage?
    @Published var outputImage: UIImage?

    @Published var currentFilter = CIFilter.sepiaTone()
    let context = CIContext()
    var subscriptions = Set<AnyCancellable>()
    let queue = DispatchQueue(label: "Image processing")

    init() {
        self.$inputImage
            .map { inputImage -> CIImage? in
                guard let inputImage = inputImage else { return nil }
                return CIImage(image: inputImage)
            }
            .combineLatest(self.$filterIntensity)
            .debounce(for: .milliseconds(50), scheduler: queue)
            .map { inputImage, filterIntensity -> UIImage? in
                guard let inputImage = inputImage else { return nil }

                self.currentFilter.inputImage = inputImage
                self.currentFilter.intensity = Float(filterIntensity)

                guard let outputImage = self.currentFilter.outputImage else { return nil }

                guard let cgImage = self.context.createCGImage(outputImage, from: outputImage.extent) else { return nil }

                return UIImage(cgImage: cgImage)

            }
            .receive(on: RunLoop.main)
            .sink { image in
                self.outputImage = image
            }
            .store(in: &self.subscriptions)
    }

}

struct ImageEffectView: View {

    @ObservedObject var imageEffect = ImageEffect()
    @State private var showingImagePicker = false

    var body: some View {
        NavigationView {
            VStack {
                ZStack {
                    Rectangle()
                        .fill(Color.secondary)

                    if imageEffect.outputImage != nil {
                        Image(uiImage: imageEffect.outputImage!)
                            .resizable()
                            .scaledToFit()
                    } else {
                        Text("Tap to select a picture")
                            .foregroundColor(.white)
                            .font(.headline)
                    }
                }
                .onTapGesture {
                    self.showingImagePicker = true
                }

                HStack {
                    Text("Intensity")
                    Slider(value: $imageEffect.filterIntensity)
                }
                .padding(.vertical)

                HStack {
                    Button("Change Filter") {
                        // change filter
                    }

                    Spacer()

                    Button("Save") {
                        // save the picture
                    }
                }
            }
            .padding([.horizontal, .bottom])
            .navigationBarTitle("Instafilter")
            .sheet(isPresented: $showingImagePicker) {
                ImagePickerView(image: self.$imageEffect.inputImage)
            }
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.