使用VNRecognizeTextRequest识别PKCanvasView手写文字失败求助
解决PKCanvasView手写文字无法被Vision Kit识别的问题
我在SwiftUI App中使用Vision Kit识别PKCanvasView上的手写文字(支持Apple Pencil或手指输入),但点击“Recognize Text”按钮始终返回“No text recognized.”。测试环境为Xcode 16.x、iPadOS 18(真机和模拟器均测试),完整代码如下:
import SwiftUI import PencilKit import Vision @main struct PencilVisionApp: App { var body: some Scene { WindowGroup { PencilDrawingView() } } } struct PencilDrawingView: View { @State private var canvasView = PKCanvasView() @State private var currentTool: PKTool = PKInkingTool(.pen, color: .black, width: 5) @State private var recognizedText: String = "" var body: some View { VStack(spacing: 16) { Text("Draw with Apple Pencil") .font(.headline) PencilCanvas(canvasView: $canvasView, tool: $currentTool) .frame(height: 300) .background(Color(.systemGray6)) .cornerRadius(10) .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray)) HStack(spacing: 12) { Button("Undo") { canvasView.undoManager?.undo() } Button("Redo") { canvasView.undoManager?.redo() } Button("Eraser") { currentTool = PKEraserTool(.vector) } Button("Pen") { currentTool = PKInkingTool(.pen, color: .black, width: 5) } Button("Recognize Text") { recognizeTextFromDrawing() } } if !recognizedText.isEmpty { VStack(alignment: .leading, spacing: 8) { Text("Recognized Text:") .font(.headline) ScrollView { Text(recognizedText) .frame(maxWidth: .infinity, alignment: .leading) .padding() .background(Color(.secondarySystemBackground)) .cornerRadius(8) } } } Spacer() } .padding() } private func recognizeTextFromDrawing() { guard !canvasView.drawing.strokes.isEmpty else { recognizedText = "Canvas is empty — nothing to recognize." return } let bounds = canvasView.drawing.bounds.insetBy(dx: -10, dy: -10) let image = canvasView.drawing.image(from: bounds, scale: 3.0) guard let cgImage = image.cgImage else { recognizedText = "Failed to generate image." return } let request = VNRecognizeTextRequest { request, error in if let error = error { recognizedText = "Recognition failed: \(error.localizedDescription)" return } let observations = request.results as? [VNRecognizedTextObservation] ?? [] let text = observations.compactMap { $0.topCandidates(1).first?.string }.joined(separator: "\n") // DispatchQueue.main.async { recognizedText = text.isEmpty ? "No text recognized." : text // } } request.recognitionLevel = .accurate request.usesLanguageCorrection = false request.recognitionLanguages = ["en-US"] let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) DispatchQueue.global(qos: .userInitiated).async { try? handler.perform([request]) } } } struct PencilCanvas: UIViewRepresentable { @Binding var canvasView: PKCanvasView @Binding var tool: PKTool func makeUIView(context: Context) -> PKCanvasView { canvasView.drawingPolicy = .anyInput canvasView.tool = tool return canvasView } func updateUIView(_ uiView: PKCanvasView, context: Context) { uiView.tool = tool } }
解决建议
修复UI更新线程问题
Vision请求在后台队列执行,回调中更新@State变量recognizedText必须回到主线程,否则无法正确刷新UI,甚至导致识别结果赋值失败。取消注释原代码中的主线程包裹:DispatchQueue.main.async { recognizedText = text.isEmpty ? "No text recognized." : text }优化图像生成逻辑
当前图像生成的边界可能裁剪了手写内容,且背景对比度不足,影响Vision识别效果。修改图像生成代码:// 使用canvasView的完整边界,设置白色背景增强对比度 let image = canvasView.drawing.image(from: canvasView.bounds, scale: UIScreen.main.scale, backgroundColor: .white)避免使用
drawing.bounds.insetBy,确保所有手写内容都被包含在生成的图像中。调整Vision识别参数
针对手写场景优化请求配置,提升识别成功率:request.recognitionLevel = .fast // 手写识别优先选择快速模式,准确率足够 request.usesLanguageCorrection = true // 开启语言修正,适配手写的不规则性 request.recognitionLanguages = ["en-US"] // 根据实际需求添加目标语言完善PKCanvasView配置
在PencilCanvas的makeUIView方法中添加背景设置,确保画布背景与手写颜色对比度足够:canvasView.backgroundColor = .white canvasView.isOpaque = true调试图像生成结果
可以临时添加代码将生成的图像保存到相册,验证图像是否正确包含手写内容:UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)注意需要在
Info.plist中添加NSPhotoLibraryAddUsageDescription权限描述。
内容的提问来源于stack exchange,提问作者Phantom59
相关产品推荐
相关产品推荐

