ios 将Swift的Vision库识别的文本分配给结构体的instance属性以供显示时出现问题

hxzsmxv2  于 2023-06-07  发布在  iOS
关注(0)|答案(1)|浏览(218)

我正在尝试使用Swift的Vision库从图像中读取文本。我跟着这个指南-https://developer.apple.com/documentation/vision/recognizing_text_in_images
关于我的代码,有问题的图像是self.image,它是一个UIImage,要显示的文本是self.recognizedText,它是一个String。在将文本识别请求识别的文本分配给完成处理程序recognizeTextHandler中的self.recognizedText时遇到问题。请注意,我记得在执行请求之前将self.image转换为CGImage对象。
我下面附上的代码不是我的完整代码。我在将self.recognizedText分配给Vision识别的文本的地方进行了注解。我省略了UI组件和用于控制呈现的UI组件的某些状态(布尔值)。我在SwiftUI框架中开发iOS。

struct AnnotatorView: View {
    @State private var image: UIImage?
    @State private var recognizedText: String = "No text recognized."
    
     func recognizeTextHandler(request: VNRequest, error: Error?) -> Void {
        guard let results = request.results as? [VNRecognizedTextObservation] else {return}

        let recognizedStrings: Array<String> = results.compactMap({result in result.topCandidates(1).first!.string})

        // Problematic code.
        self.recognizedText = recognizedStrings.joined()
    }
    
    func performTextRecognition(requestHandler: VNImageRequestHandler, request: VNRecognizeTextRequest) -> String {
        do {
            try requestHandler.perform([request])
            return "Text recognition succeeded."
        } catch {
            return "Could not perform text recognition request because of the following error: \(error)"
        }
    }
    
    var body: some View {
        VStack(spacing: 15){
            
            // Camera opening button.
            
            // Image opening button.
            
            // Fullscreen cover that displays camera and sets self.image to a UIImage object.

            // Fullscreen cover that displays image and recognized text.
            .fullScreenCover(isPresented: self.$isAnnotatedImageDisplayed) {
                VStack {
                  // Fullscreen cover closing button.
                
                    if let cgImage: CGImage = self.image?.cgImage {
                        let requestHandler: VNImageRequestHandler = VNImageRequestHandler(cgImage: cgImage)
                        let recognizeTextRequest = VNRecognizeTextRequest(completionHandler: recognizeTextHandler)     
                        let textRecognitionStatus: String = performTextRecognition(requestHandler: requestHandler, request: recognizeTextRequest)
                    
                      // Display whether recognition request went through, the image taken and text recognized (if any).
                      Text(textRecognitionStatus)
                    
                      // Display image.
                    
                      if (!self.recognizedText.isEmpty) {
                        Text("\(self.recognizedText)")
                    } else {
                        Text("No text recognized because the image is not good enough.")
                    }
                  } else {
                    Text("You haven't taken any pictures yet!")
                    Text("\(self.recognizedText)")
    }}}}}}

struct AnnotatorView_Previews: PreviewProvider {
    static var previews: some View {
        AnnotatorView()
    }
}

我已尝试在控制台上进行调试,但控制台拒绝记录任何信息。我在互联网上寻找解决方案,但一无所获。无论如何,我修复这个问题的第一次尝试是测试我的文本识别请求是否已经通过。我在全屏封面上显示这个代码- Text(textRecognitionStatus)。但是,当我这样做时,我看到以下消息-“文本识别成功”-我认为这意味着文本识别请求已经通过,没有任何错误。我曾尝试使用数组来存储已识别的文本而不是文本,认为这可能与突变有关,但它没有产生任何影响。我研究了结构突变的常见问题,但这些问题中的大多数都与结构本身之外的突变有关。我认为这个问题可能与在SwiftUI的声明式框架中添加控制流语句有关,但所有其他文本都能正确显示。如果我在这里做了任何简单的语法相关的问题,例如,额外的括号或缺少括号,这可能是我在将代码复制到StackOverflow时犯的错误。

pgky5nke

pgky5nke1#

这里是一个工作示例,就像我之前说的,这可能是一个时间问题,因为你在body中工作。
但另一个需要考虑的是,VNRecognizeTextRequest需要JPEG,因为它没有alpha/透明度。

import SwiftUI
import Vision
import VisionKit
struct TextRecognitionView: View {
    let model: TextRecognitionModel = .init()
    @State private var image: UIImage?
    @State private var recognizedText: String? = nil
    var body: some View {
        VStack(spacing: 15){
            VStack {
                switch image { //Unwrap the Image
                case .none:
                    Text("You haven't taken any pictures yet!")
                case .some(let image):
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                    switch recognizedText { //Unwrap the text
                    case .none:
                        ProgressView() //Show this while recognizing
                    case .some(let text):
                        Text(text) //Show text
                    }
                }
                
                Button("set random text image") {
                    self.image = Text("Random text \((0...100).randomElement()!)")
                        .frame(width: 100, height: 100)
                        .snapshot().validJPEG() // Vision requires JPEG image likely because of transparency/alpha
                    self.recognizedText = nil //Clear the text
                    Task {
                        do {
                            self.recognizedText = try await model.performRequest(image: image!)
                        } catch {
                            self.recognizedText = error.localizedDescription //Show an error to the user
                            print(error)
                        }
                    }
                }
            }
        }
    }
}

struct TextRecognitionModel {
    /// async await version of a VNRecognizeTextRequest + VNImageRequestHandler
    func performRequest(image: UIImage) async throws -> String {
        guard let cgImage: CGImage = image.cgImage  else {
            throw RequestErrors.unableToRetrieveImage
        }
        let requestHandler: VNImageRequestHandler = VNImageRequestHandler(cgImage: cgImage)
        
        return try await withCheckedThrowingContinuation({ continuation in
            let request = VNRecognizeTextRequest(completionHandler: { request, error in
                if let error {
                    continuation.resume(throwing: error)
                } else {
                    let results = request.results as? [VNRecognizedTextObservation] ?? []
                    let recognizedStrings: Array<String> = results.compactMap({result in result.topCandidates(1).first!.string})
                    
                    continuation.resume(returning: recognizedStrings.joined())
                }
            })
            do {
                try requestHandler.perform([request])
            } catch {
                continuation.resume(throwing: error)
            }
        })
    }
}

enum RequestErrors: LocalizedError {
    case unableToRetrieveImage
}

struct TextRecognitionView_Previews: PreviewProvider {
    static var previews: some View {
        TextRecognitionView()
    }
}

extension View {
    func snapshot() -> UIImage {
        let controller = UIHostingController(rootView: self)
        let view = controller.view
        
        let targetSize = controller.view.intrinsicContentSize
        view?.bounds = CGRect(origin: .zero, size: targetSize)
        view?.backgroundColor = .clear
        
        let renderer = UIGraphicsImageRenderer(size: targetSize)
        
        return renderer.image { _ in
            view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
        }
    }
}

extension UIImage {
    func validJPEG() -> UIImage {
        guard let data = self.jpegData(compressionQuality: 1) else {
            return .init()
        }
        
        guard let jpegImage = UIImage(data: data) else {
            return .init()
        }
        return jpegImage
    }
}

相关问题