从照片 SwiftUI 中获取图像时内存不足

Posted

技术标签:

【中文标题】从照片 SwiftUI 中获取图像时内存不足【英文标题】:Running out of memory while fetching images from Photos SwiftUI 【发布时间】:2021-05-12 16:41:29 【问题描述】:

我正在开发一个可以检测狗品种的应用程序,我希望当用户打开他们的照片库时,他们只会看到带有狗的图像。为此,我使用了非常基本的 Vision 宠物识别器模型,问题是在 1000 张照片上运行需要一段时间且内存过多。我想知道是否有任何解决方案。

PhotoLibraryViewModel.swift

import Photos
import UIKit
import Vision

class PhotoLibraryViewModel: ObservableObject 
    
    @Published var uiImages = [UIImage]()
    var allPhotos : PHFetchResult<PHAsset>? = nil
        
    init() 
        getPhotos()
    
    
    private func getPhotos() 
        phphotoLibrary.requestAuthorization  [weak self] status in
            switch status 
            case .authorized:
                let fetchOptions = PHFetchOptions()
                fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
                self?.allPhotos = PHAsset.fetchAssets(with: .image, options: fetchOptions)
                self?.setCompositionalLayout()
            case .denied, .restricted:
                print("Not allowed")
            case .notDetermined:
                print("Not determined yet")
            case .limited:
                print("limited")
            @unknown default:
                fatalError()
            
        
    
    
    private func setCompositionalLayout() 
        print("all photos: " + "\(allPhotos!.count)")
        
        allPhotos?.enumerateObjects()  [self] photo, _, _  in
            
            
            
            let options = PHImageRequestOptions()
            options.version = .original
            
            PHImageManager.default().requestImage(for: photo, targetSize: CGSize(width: (screen.width - 60) / 3, height: (screen.width - 60) / 3), contentMode: PHImageContentMode.aspectFit, options: options)  [self] uiImage, _ in
                
                guard let finalUIImage = uiImage else 
                    print("failed to make finalUIImage")
                    return
                
                
                checkImage(uiImage: finalUIImage)

            
        
    
    
    private func checkImage(uiImage: UIImage) 
        
        var animalRecognitionRequest = VNRecognizeAnimalsRequest(completionHandler: nil)
        
        let animalRecognitionWorkQueue = DispatchQueue(label: "PetClassifierRequest", qos: .userInteractive, attributes: [], autoreleaseFrequency: .workItem)
        
        guard let cgImage = uiImage.cgImage else 
            print("failed to convert image")
            return
        
        
        animalRecognitionWorkQueue.async 
            let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
            do 
                try requestHandler.perform([animalRecognitionRequest])
             catch 
                print("error: " + "\(error)")
            
        
        
        animalRecognitionRequest = VNRecognizeAnimalsRequest  [self] request, error in
            if let results = request.results as? [VNRecognizedObjectObservation] 
                for result in results 
                    let animals = result.labels
                    
                    for animal in animals 
                        if animal.identifier == "Dog" 
                            DispatchQueue.main.async 
                                uiImages.append(uiImage)
                                print("dog detected")
                            
                            continue
                        
                    
                
            
        
    


PhotoLibraryView.swift

import SwiftUI

struct PhotoLibraryView: View 
    @StateObject var photoLibraryViewModel = PhotoLibraryViewModel()
    
    var body: some View 
        
        NavigationView 
            ZStack 
                LinearGradient(gradient: Gradient(colors: [Color(#colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1)), Color(#colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1))]), startPoint: .top, endPoint: .bottom)
                    .edgesIgnoringSafeArea(.all)
                
                ScrollView 
                    // Compositional Layout....
                    LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 15), count: 3)) 
                        ForEach(0..<photoLibraryViewModel.uiImages.count, id: \.self)  index in
                            Image(uiImage: photoLibraryViewModel.uiImages[index])
                                .resizable()
                                .frame(width: (screen.width - 60) / 3, height: (screen.width - 60) / 3)
                                .cornerRadius(13)
                        
                    
                    .padding(.horizontal)
                
            
            .navigationTitle("Dog images")
        
    


【问题讨论】:

@matt 是对的,您不直接存储 UIImages,因为图像大小非常大。因此,您可以在网格中加载图像时存储 PHAsset 并请求图像 感谢大家的帮助,但是我怎么能在没有数组或 UIImages 的图像上运行 VNRecognizeAnimalsRequest 呢? 【参考方案1】:
@Published var uiImages = [UIImage]()

红旗! [UIImage] 一词立即令人怀疑。图像(尤其是直接来自照片)很大。图像数组是耗尽内存的好方法。

您可以保留一组图像的引用,但不能保留一组实际图像。

【讨论】:

以上是关于从照片 SwiftUI 中获取图像时内存不足的主要内容,如果未能解决你的问题,请参考以下文章

从照片库加载图像并按日期排序的内存问题

电脑上看图片显示内存不足

C# graphics图像复制时提示内存不足

windows照片查看器无法显示此图片,因为计算机内存不足?

windows7看图片提示内存不足

位图 - 内存不足异常