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

OCRを使ってゲームのアイテムをデータ化する

 OCRを使ってゲームのアイテムをデータ化する

プロトタイプを製品にする技術
OCRを使ってゲームのアイテムをデータ化する

Avatar for Kishikawa Katsumi

Kishikawa Katsumi

May 22, 2026

More Decks by Kishikawa Katsumi

Other Decks in Programming

Transcript

  1. 4UFQ3BX0$3 actor OCRRunner { private var busy = false func

    process(_ cgImage: CGImage) async -> [RecognizedTextObservation]? { guard !busy else { return nil } busy = true defer { busy = false } var request = RecognizeTextRequest() request.recognitionLanguages = [ Locale.Language(identifier: "ja-JP"), Locale.Language(identifier: "en-US"), ] request.recognitionLevel = .accurate request.usesLanguageCorrection = false return try? await request.perform(on: cgImage) } }
  2. let windowSize: Int = 5 let minHits: Int = 3

    func updateStability(with results: [RecognizedTextObservation]) { let textsThisFrame = Set( results.compactMap { (observation) -> String? in let raw = observation.topCandidates(1).first?.string ?? "" let t = raw.trimmingCharacters(in: .whitespacesAndNewlines) return t.isEmpty ? nil : t } ) recentTextSets.append(textsThisFrame) if recentTextSets.count > windowSize { recentTextSets.removeFirst(recentTextSets.count - windowSize) } var counts: [String: Int] = [:] for set in recentTextSets { for t in set { counts[t, default: 0] += 1 } } let stable = counts.filter { $0.value >= minHits } stableTexts = Set(stable.keys) stableLines = stable .map { StableLine(text: $0.key, hits: $0.value) } .sorted { $0.hits == $1.hits ? $0.text < $1.text : $0.hits > $1.hits } } ϑϨʔϜ಺ͰճҎ্ग़ݱͨ͠ ςΩετΛ࠾༻͢Δɻ
  3. Ԍ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ ग़ܸ࣌ͷ෢ثʹ ੟߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ੟߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ

    ཕ߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ཕ߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ཕ߈ܸྗΛ෇Ճ ϦϯάόοϑΝʹΑΔ҆ఆੑͷ޲্ /ϑϨʔϜத.ճҎ্ग़ͨςΩετΛ࠾༻͢Δ
  4. Ԍ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ ग़ܸ࣌ͷ෢ثʹ ੟߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ੟߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ

    ཕ߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ཕ߈ܸྗΛ෇Ճ ग़ܸ࣌ͷ෢ثʹ ཕ߈ܸྗΛ෇Ճ ϦϯάόοϑΝʹΑΔ҆ఆੑͷ޲্ /ϑϨʔϜத.ճҎ্ग़ͨςΩετΛ࠾༻͢Δ
  5. static let roiOnScreen = CGRect(x: 0.08, y: 0.30, width: 0.84,

    height: 0.32) static let visionROI: NormalizedRect = { let r = roiOnScreen return NormalizedRect(x: r.minX, y: 1 - r.maxY, width: r.width, height: r.height) }() func process( _ cgImage: CGImage, roi: NormalizedRect ) async -> [RecognizedTextObservation]? { ... request.regionOfInterest = roi ... } 6*ͷ࠲ඪͷ7JTJPOGSBNFXPSLͷ ࠲ඪʹม׵ͯ͠ηοτ ΨΠυ࿮ͷൣғ͚ͩಡΈऔΔ ؔ܎ͳ͍ςΩετΛಡ·ͳ͍ɾ଎౓޲্
  6. func bestMatch(for input: String) -> (master: Master, distance: Int)? {

    let n = normalize(input) var best: (Master, Int)? for (key, master) in normalizedKeys { if abs(key.count - n.count) > 5 { continue } let d = levenshtein(n, key) if best == nil || d < best!.1 { best = (master, d) } } return best } // डཧ: ڑ཭ ≤ max(1, |master| × 0.3) ≒ score ≥ 0.70 let threshold = max(1, Int(Double(master.textJa.count) * 0.3)) guard match.distance <= threshold else { return nil } ฤूڑ཭ -FWFOTIUFJO%JTUBODF ͰҰக౓Λ൑ఆ Ϛελʔσʔλͱর߹
  7. ΞϧΰϦζϜ )BNNJOHڑ཭ ܭࢉྔ଎౓ͱ࢓૊Έ ࠷଎ 903 QPQDPVOU ɻಉ͡௕͞ͷจࣈྻͰʮҟͳΔҐஔͷ਺ʯΛ਺͑Δ ࠾༻͠ͳ͔ͬͨཧ༝ 0$3ͷจࣈ௕͸GSBNF͝ͱʹ༳ΕΔͨΊద༻ෆՄɻจࣈͰ΋௕͕͞ҧ͏ͱ࢖͑ͳ͍ ΞϧΰϦζϜ

    OHSBN+BDDBSEྨࣅ౓ ܭࢉྔ଎౓ͱ࢓૊Έ ଎͍ ू߹ԋࢉ ɻจࣈ/HSBNू߹Λ࡞Γc"ˬ#cc"˫#cΛܭࢉ ࠾༻͠ͳ͔ͬͨཧ༝ จࣈॱংΛࣺͯΔͨΊʮ߈ܸྗ্ঢʯͱʮ্ঢ߈ܸྗʯΛ۠ผͰ͖ͳ͍ ΞϧΰϦζϜ %BNFSBV-FWFOTIUFJO ܭࢉྔ଎౓ͱ࢓૊Έ -FWFOTIUFJOͱ΄΅ಉ౳ Θ͔ͣʹ஗͍ ɻ-FWFOTIUFJO ྡ઀จࣈͷೖΕସ͑ΛίετͰڐ༰ ࠾༻͠ͳ͔ͬͨཧ༝ 0$3Ͱ͸USBOTQPTJUJPOΑΓ७ਮͳஔ׵ޡΓ͕େ൒ͰɺԸܙ͕ബ͍ ΞϧΰϦζϜ +BSP8JOLMFS ܭࢉྔ଎౓ͱ࢓૊Έ -FWFOTIUFJOΑΓఆ਺͕খ͍͞ɻҰகจࣈ਺ USBOTQPTJUJPO ڞ௨QSF fi YՃ఺Ͱྨࣅ౓Λग़͢ ࠾༻͠ͳ͔ͬͨཧ༝ ୹͍ਓ໊ɾॅॴ޲͚ʹ࠷దԽ͞Εͨؔ਺ͰɺʙจࣈͷFGGFDUจͰ͸-FWFOTIUFJOͱͷ͕ࠩग़ʹ͍͘ ͦͷଞͷর߹ΞϧΰϦζϜ
  8. ͦͷଞͷর߹ΞϧΰϦζϜ ΞϧΰϦζϜ 4ZN4QFMM ܭࢉྔ଎౓ͱ࢓૊Έ ࣄલܭࢉͰ࣮࣭0  MPPLVQɻNBTUFSΛʮFEJU≤Lͷશมܗʯʹల։ͨࣙ͠ॻΛQSFCVJME͠ɺೖྗ΋ల։ͯ͠IBTIিಥΛݕग़ ࠾༻͠ͳ͔ͬͨཧ༝ ڑ཭≤·Ͱ͔͠Ҿ͚ͣ௕͞มಈʹऑ͍ɻࣙॻల։Ͱ0 -

    ͷϝϞϦ๲ு͕͋Γɺ݅ن໛Ͱ͸Ըܙ͕๡͍͠ ΞϧΰϦζϜ #,USFF ܭࢉྔ଎౓ͱ࢓૊Έ ฏۉ0 MPH/ ఔ౓ͷۙ๣୳ࡧɻจࣈྻۭؒʹNFUSJDUSFFΛߏங͠ɺڑ཭EҎ಺ͷ΋ͷΛ໦ͰߜΔ ࠾༻͠ͳ͔ͬͨཧ༝ ಺෦Ͱ݁ہ-FWFOTIUFJOΛݺͿɻ݅ن໛Ͱ͸ΠϯσοΫεߏஙίετ͕ԸܙΛ্ճΔ ΞϧΰϦζϜ 4PVOEFY.FUBQIPOF ԻӆIBTI ܭࢉྔ଎౓ͱ࢓૊Έ ଎͍ ఆ਺࣌ؒ ɻൃԻྨࣅੑͰಉ஋ΫϥεΛ࡞ΓɺϋογϡҰகͰൺֱ ࠾༻͠ͳ͔ͬͨཧ༝ ӳޠԻӆ޲͚ͷࢉ๏Ͱ͋Γɺ೔ຊޠ$+,ʹ͸ద༻Ͱ͖ͳ͍ ΞϧΰϦζϜ จ຺ϞσϧຒΊࠐΈڑ཭ #&35౳ ܭࢉྔ଎౓ͱ࢓૊Έ େ෯ʹ஗͍ ਺ेNTΫΤϦ ɻจࣈྻΛߴ࣍ݩϕΫτϧʹຒΊࠐΈɺDPTJOFڑ཭Ͱྨࣅ౓Λܭࢉ ࠾༻͠ͳ͔ͬͨཧ༝ ϦΞϧλΠϜಈըʹ͸ॏ͗͢ΔɻϞσϧ͕NBTUFSͷEPNBJOޠኮɺಛʹήʔϜ଄ޠΛ஌Βͳ͍
  9. ·ͱΊ r Ϛελʔσʔλʢਖ਼ղͷఆٛʣΛ੔͑Δ r ϑϨʔϜ୯ҐͰޡೝࣝΛϑΟϧλʔ͢Δ ‣ .VMUJGSBNF$POTFOTVT r ࣄલʹೖྗΛΫϦʔϯʹ͢Δ ‣

    ςΩετͷਖ਼نԽ ‣ Α͋͘ΔޡೝࣝΛஔ׵ r ڍಈΛܾఆ࿦తɾ؍ଌՄೳʹ͢Δ ߴ͍඼࣭Ͱ࠶ݱੑͷ͋Δ݁ՌΛग़ྗ͢ΔͨΊͷ޻෉