Add Live-Processing (todo: get previewlayer working)

This commit is contained in:
Simon Rieger 2023-12-15 18:00:26 +01:00
parent 56a8f07a9f
commit a54db5d11e
2 changed files with 104 additions and 88 deletions

View file

@ -6,121 +6,137 @@
// //
import SwiftUI import SwiftUI
import AVFoundation
import Vision import Vision
struct ContentView: View { struct LiveTextRecognitionView: View {
@State private var recognizedText = "" @State private var recognizedText = ""
@State private var showingImagePicker = false
@State private var showingCamera = false
@State private var selectedImage: UIImage?
var body: some View { var body: some View {
VStack { VStack {
Button("Bild auswählen") { CameraView(recognizedText: $recognizedText)
self.showingImagePicker.toggle() .edgesIgnoringSafeArea(.all)
} .onDisappear {
.sheet(isPresented: $showingImagePicker, onDismiss: recognizeText) { CameraView.stopSession()
ImagePicker(selectedImage: self.$selectedImage, sourceType: .photoLibrary) }
}
Button("Kamera verwenden") { Text("Live erkannter Text:")
self.showingCamera.toggle() .padding()
} Text(recognizedText)
.sheet(isPresented: $showingCamera, onDismiss: recognizeText) { .padding()
ImagePicker(selectedImage: self.$selectedImage, sourceType: .camera) .background(Color.white.opacity(0.7))
}
if let selectedImage = selectedImage {
Image(uiImage: selectedImage)
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
.padding()
Text("Erkannter Text:")
Text(recognizedText)
.padding()
}
}
}
func recognizeText() {
guard let selectedImage = selectedImage, let cgImage = selectedImage.cgImage else {
return
}
let request = VNRecognizeTextRequest(completionHandler: { (request, error) in
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
var recognizedText = ""
for observation in observations {
guard let topCandidate = observation.topCandidates(1).first else { continue }
recognizedText += topCandidate.string + "\n"
}
self.recognizedText = recognizedText
})
let requestHandler = VNImageRequestHandler(cgImage: cgImage, options: [:])
do {
try requestHandler.perform([request])
} catch {
print("Error performing OCR: \(error)")
} }
} }
} }
struct ContentView_Previews: PreviewProvider { struct LiveTextRecognitionView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ContentView() LiveTextRecognitionView()
} }
} }
struct ImagePicker: UIViewControllerRepresentable { struct CameraView: UIViewRepresentable {
@Binding var selectedImage: UIImage? @Binding var recognizedText: String
var sourceType: UIImagePickerController.SourceType
class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { class Coordinator: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate {
let parent: ImagePicker var recognizedText: Binding<String>
var request: VNRecognizeTextRequest?
init(parent: ImagePicker) { init(recognizedText: Binding<String>) {
self.parent = parent self.recognizedText = recognizedText
super.init()
setupVision()
} }
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { func setupVision() {
if let uiImage = info[.originalImage] as? UIImage { request = VNRecognizeTextRequest(completionHandler: { (request, error) in
parent.selectedImage = uiImage guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
var recognizedText = ""
for observation in observations {
guard let topCandidate = observation.topCandidates(1).first else { continue }
recognizedText += topCandidate.string + "\n"
}
self.recognizedText.wrappedValue = recognizedText
})
request?.recognitionLevel = .accurate
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
let handler = VNImageRequestHandler(cvPixelBuffer: imageBuffer, options: [:])
do {
try handler.perform([request!])
} catch {
print("Error performing OCR: \(error)")
} }
parent.presentationMode.wrappedValue.dismiss()
} }
} }
var imagePickerController: UIImagePickerController static var session: AVCaptureSession?
@Environment(\.presentationMode) var presentationMode
init(selectedImage: Binding<UIImage?>, sourceType: UIImagePickerController.SourceType) { static func startSession() {
_selectedImage = selectedImage session?.startRunning()
self.sourceType = sourceType
imagePickerController = UIImagePickerController()
imagePickerController.sourceType = sourceType
imagePickerController.allowsEditing = false
} }
func makeUIViewController(context: Context) -> UIImagePickerController { static func stopSession() {
imagePickerController.delegate = context.coordinator session?.stopRunning()
return imagePickerController
} }
func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {}
func makeCoordinator() -> Coordinator { func makeCoordinator() -> Coordinator {
return Coordinator(parent: self) return Coordinator(recognizedText: $recognizedText)
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
let session = AVCaptureSession()
guard let device = AVCaptureDevice.default(for: .video) else { return view }
let input = try? AVCaptureDeviceInput(device: device)
if session.canAddInput(input!) {
session.addInput(input!)
}
let output = AVCaptureVideoDataOutput()
output.setSampleBufferDelegate(context.coordinator, queue: DispatchQueue(label: "cameraQueue"))
if session.canAddOutput(output) {
session.addOutput(output)
}
// Todo: get PreviewLayer working
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
previewLayer.videoGravity = .resizeAspectFill
previewLayer.frame = view.layer.bounds
view.layer.addSublayer(previewLayer)
CameraView.session = session
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
uiView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
if context.coordinator.request == nil {
context.coordinator.setupVision()
}
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
CameraView.startSession()
} else {
AVCaptureDevice.requestAccess(for: .video) { granted in
if granted {
CameraView.startSession()
}
}
}
} }
} }
#Preview {
ContentView()
}

View file

@ -11,7 +11,7 @@ import SwiftUI
struct intelliScan_analytic_engineApp: App { struct intelliScan_analytic_engineApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() LiveTextRecognitionView()
} }
} }
} }