Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ディープラーニングAI と SwiftUI で作る文字認識読み上げアプリその1

ディープラーニングAI と SwiftUI で作る文字認識読み上げアプリその1

「完璧なコード」じゃなくて「改善できるコード」から始める
プログラミングを知るには、理想的なサンプルコードを見ても「なぜそうなのか」が腑に落ちず、実践的な応用力が身につきにくいものです。本記事では、あえて「完璧でない」コードから始め、生成AIをパートナーとしながら改善していく新しい学習アプローチを紹介します。
https://note.com/ipadtocode/n/n3140bb00781f

Avatar for ikejun360

ikejun360

May 15, 2025
Tweet

More Decks by ikejun360

Other Decks in Programming

Transcript

  1. ͜ͷ͜ͷϖʔδΛ೔ຊޠͰݟΔ iOS ύε΢ΣΠ ༏ΕͨΞϓϦ΍ήʔϜΛߏங͢ΔͨΊͷɺ͜ͷφϏήʔτ͠΍͍͢ ϏσΦɺυΩϡϝϯτɺπʔϧͷίϨΫγϣϯ͔Β࢝Ί·͠ΐ͏ɻ T ͷ iOSʹ͍ͭͯ஌Δ iOSͱiOS SDK͸ɺiPhoneͷΞϓϦ΍ήʔϜʹ؆୯ʹػೳΛఏڙ͢Δڧྗͳػೳͷแׅతͳηο

    τΛఏڙ͠·͢ɻ·ͨɺۀքΛϦʔυ͢ΔηΩϡϦςΟͱϓϥΠόγʔอޢػೳ͕૊Έࠐ·Εͯ ͍ΔͨΊɺΞΠσΞʹࣗ༝ʹूதͰ͖·͢ɻ iOSʹ͍ͭͯ஌Δ πʔϧϘοΫεΛ૊ΈཱͯΔ σβΠϯʹμΠϒ ϕετϓϥΫςΟεΛ࠾༻͢ Δ ෳ਺ͷAppleϓϥοτϑΥʔ Ϝ޲͚ʹߏங ΞϓϦΛ഑෍͢Δ ͞ΒʹਐΉ   ʢӳޠʣ Λμ΢ϯϩʔυ iOS iOS 18 ࢝ΊΔ ΞϓϦΛఏग़͢Δ χϡʔε ൃݟ͢Δ σβΠϯ ։ൃ͢Δ ഑෍͢Δ αϙʔτ ΞΧ΢ϯτ
  2. import SwiftUI import PhotosUI import Vision import AVFoundation struct ContentView:

    View { @State private var selectedPickerItem: PhotosPickerItem? = nil @State private var selectedImage: UIImage? = nil @State private var recognizedText = "" var body: some View { VStack { if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 400) } PhotosPicker("จࣈೝࣝ͢ΔࣸਅΛબΜͰ͍ͩ͘͞", selection: $selectedPickerItem, matching: .images) .onChange(of: selectedPickerItem) { newItem in if let newItem { Task { if let data = try? await newItem.loadTransferable(type: Data.self), let uiImage = UIImage(data: data) { selectedImage = uiImage recognizeText(from: selectedImage!) } } } } if !recognizedText.isEmpty{ ScrollView{ Text(recognizedText) .padding() .frame(maxWidth: .infinity, alignment: .leading) } } } } func recognizeText(from image: UIImage) { guard let cgImage = image.cgImage else { return } let request = VNRecognizeTextRequest { request, error in guard let observations = request.results as? [VNRecognizedTextObservation] else { return } let text = observations.compactMap { $0.topCandidates(1).first?.string }.joined(separator: "\n") DispatchQueue.main.async { recognizedText = text speakText(text: text) } } request.recognitionLanguages = ["ja-JP"] request.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) try? handler.perform([request]) } func speakText(text: String){ let synthesizer = AVSpeechSynthesizer() let utt = AVSpeechUtterance(string: text) utt.voice = AVSpeechSynthesisVoice(language: "ja-JP") utt.rate = 0.5 synthesizer.speak(utt) } }
  3. import SwiftUI import PhotosUI import Vision import AVFoundation struct ContentView:

    View { @State private var selectedPickerItem: PhotosPickerItem? = nil @State private var selectedImage: UIImage? = nil @State private var recognizedText = "" var body: some View { VStack { if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 400) } PhotosPicker("จࣈೝࣝ͢ΔࣸਅΛબΜͰ͍ͩ͘͞", selection: $selectedPickerItem, matching: .images) .onChange(of: selectedPickerItem) { newItem in if let newItem { Task { if let data = try? await newItem.loadTransferable(type: Data.self), let uiImage = UIImage(data: data) { selectedImage = uiImage recognizeText(from: selectedImage!) } } } } if !recognizedText.isEmpty{ ScrollView{ Text(recognizedText) .padding() .frame(maxWidth: .infinity, alignment: .leading) } } } } func recognizeText(from image: UIImage) { guard let cgImage = image.cgImage else { return } let request = VNRecognizeTextRequest { request, error in guard let observations = request.results as? [VNRecognizedTextObservation] else { return } let text = observations.compactMap { $0.topCandidates(1).first?.string }.joined(separator: "\n") DispatchQueue.main.async { recognizedText = text speakText(text: text) } } request.recognitionLanguages = ["ja-JP"] request.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) try? handler.perform([request]) } func speakText(text: String){ let synthesizer = AVSpeechSynthesizer() let utt = AVSpeechUtterance(string: text) utt.voice = AVSpeechSynthesisVoice(language: "ja-JP") utt.rate = 0.5 synthesizer.speak(utt) } } ໰୊͸͋Δ͕ ػೳ͢Δ͸ͣͷίʔυʢߦʣ ίϯύΠϥͰΤϥʔ͸Ͱͳ͍
  4. 発生した不具合 音声が出ない・出ないことがある func speakText(text: String){ let synthesizer = AVSpeechSynthesizer() let

    utt = AVSpeechUtterance(string: text) utt.voice = AVSpeechSynthesisVoice(language: "ja-JP") utt.rate = 0.5 synthesizer.speak(utt) }