Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
OCRを使ってゲームのアイテムをデータ化する
Search
Kishikawa Katsumi
May 22, 2026
Programming
200
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
OCRを使ってゲームのアイテムをデータ化する
プロトタイプを製品にする技術
OCRを使ってゲームのアイテムをデータ化する
Kishikawa Katsumi
May 22, 2026
More Decks by Kishikawa Katsumi
See All by Kishikawa Katsumi
Accessibility APIでテキストの内容、位置、サイズを取得する実装パターン
kishikawakatsumi
0
89
ゲームコントローラやキーボードのファームウェアをSwiftで書く
kishikawakatsumi
1
280
Running Swift without an OS
kishikawakatsumi
0
1.2k
浮動小数の比較について
kishikawakatsumi
0
640
Automatic Grammar Agreementと Markdown Extended Attributes について
kishikawakatsumi
0
280
愛される翻訳の秘訣
kishikawakatsumi
3
510
Private APIの呼び出し方
kishikawakatsumi
3
1.1k
iOSでSVG画像を扱う
kishikawakatsumi
0
270
Build your own WebP codec in Swift
kishikawakatsumi
2
2.9k
Other Decks in Programming
See All in Programming
なぜCTOを降りてFDEを選んだのか?〜なぜプロダクト企業がFDEで顧客の現場に踏み込むのか〜
gonta
1
170
When benchmarks go bad - what I learned from measuring performance wrong
hollycummins
0
190
re:Inventに行く前に知っておきたい現地参加のノウハウ
nokomoro3
0
380
Jetpack Compose Mechanisms
skydoves
2
570
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.9k
Embedded Swiftで作る自作USBデバイス によるiOSデバイスの自動テスト / iOSDC Japan 2026 glassfiber
glassfiber
0
310
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
2k
JRuby: Past, Present, and Future
headius
0
220
dotNET_vulnclicker_intro.pdf
deka_morita
0
130
Agents on Rails - Rails at Scale 2026
irinanazarova
0
350
気持ちぃ〜角丸 Squircle
ryu1013
0
130
The Rails Doctrine Decade
koic
2
530
Featured
See All Featured
Rails Girls Zürich Keynote
gr2m
96
14k
Typedesign – Prime Four
hannesfritz
42
3.2k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.7k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
58k
Deep Space Network (abreviated)
tonyrice
0
360
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.6k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.5k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
35
2.9k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
1.1k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
3k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
480
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Transcript
ϓϩτλΠϓΛʹ͢Δٕज़ LJTIJLBXBLBUTVNJ !LJTIJLBXBLBUTVNJ!IBDIZEFSNJP LJTIJLBXBLBUTVNJ 0$3ΛͬͯήʔϜͷΞΠςϜΛσʔλԽ͢Δ
None
ϓϩτλΠϓΛʹ͢Δٕज़ r ݸͷΞΠςϜΛਖ਼֬ʹσʔλԽ͢Δ r ̍ͭʹ͖ͭඵҎʹಡΈऔΕΔ r ήʔϜͷݴޠ͕ຊޠͱӳޠͷͲͪΒͰಡΈऔΕΔ
ϓϩτλΠϓΛʹ͢Δٕज़ r ݸͷΞΠςϜΛਖ਼֬ʹσʔλԽ͢Δ r ̍ͭʹ͖ͭඵҎʹಡΈऔΕΔ r ήʔϜͷݴޠ͕ຊޠͱӳޠͷͲͪΒͰಡΈऔΕΔ ਫ਼
ϓϩτλΠϓΛʹ͢Δٕज़ r ݸͷΞΠςϜΛਖ਼֬ʹσʔλԽ͢Δ r ̍ͭʹ͖ͭඵҎʹಡΈऔΕΔ r ήʔϜͷݴޠ͕ຊޠͱӳޠͷͲͪΒͰಡΈऔΕΔ ਫ਼
ϓϩτλΠϓΛʹ͢Δٕज़ r ݸͷΞΠςϜΛਖ਼֬ʹσʔλԽ͢Δ r ̍ͭʹ͖ͭඵҎʹಡΈऔΕΔ r ήʔϜͷݴޠ͕ຊޠͱӳޠͷͲͪΒͰಡΈऔΕΔ ਫ਼ ॊೈੑ
4BNQMF$PEF HJUIVCDPNLJTIJLBXBLBUTVNJ$BNFSB0$3
None
None
େ͖͞ ৭ छྨ ޮՌςΩετ
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) } }
None
4UFQ4UBCJMJUZ'JMUFS
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 } } ϑϨʔϜͰճҎ্ग़ݱͨ͠ ςΩετΛ࠾༻͢Δɻ
None
Ԍ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ ग़ܸ࣌ͷثʹ ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ
ཕ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ཕ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ཕ߈ܸྗΛՃ ϦϯάόοϑΝʹΑΔ҆ఆੑͷ্ /ϑϨʔϜத.ճҎ্ग़ͨςΩετΛ࠾༻͢Δ
Ԍ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ Ԍ߈ܸྗ্ঢ ཕ߈ܸྗ্ঢ ग़ܸ࣌ͷثʹ ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ
ཕ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ཕ߈ܸྗΛՃ ग़ܸ࣌ͷثʹ ཕ߈ܸྗΛՃ ϦϯάόοϑΝʹΑΔ҆ఆੑͷ্ /ϑϨʔϜத.ճҎ্ग़ͨςΩετΛ࠾༻͢Δ
4UFQ30* 3FHJPOPG*OUFSFTU
ΨΠυͷൣғ͚ͩಡΈऔΔ ؔͳ͍ςΩετΛಡ·ͳ͍ɾ্
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ͷ ࠲ඪʹมͯ͠ηοτ ΨΠυͷൣғ͚ͩಡΈऔΔ ؔͳ͍ςΩετΛಡ·ͳ͍ɾ্
None
4UFQ.BTUFS.BUDIJOH
Ϛελʔσʔλͱর߹
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 ͰҰகΛఆ Ϛελʔσʔλͱর߹
None
ΞϧΰϦζϜ )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ͱͷ͕ࠩग़ʹ͍͘ ͦͷଞͷর߹ΞϧΰϦζϜ
ͦͷଞͷর߹ΞϧΰϦζϜ ΞϧΰϦζϜ 4ZN4QFMM ܭࢉྔͱΈ ࣄલܭࢉͰ࣮࣭0 MPPLVQɻNBTUFSΛʮFEJU≤Lͷશมܗʯʹల։ͨࣙ͠ॻΛQSFCVJME͠ɺೖྗల։ͯ͠IBTIিಥΛݕग़ ࠾༻͠ͳ͔ͬͨཧ༝ ڑ≤·Ͱ͔͠Ҿ͚ͣ͞มಈʹऑ͍ɻࣙॻల։Ͱ0 -
ͷϝϞϦு͕͋Γɺ݅نͰԸܙ͕͍͠ ΞϧΰϦζϜ #,USFF ܭࢉྔͱΈ ฏۉ0 MPH/ ఔͷۙ୳ࡧɻจࣈྻۭؒʹNFUSJDUSFFΛߏங͠ɺڑEҎͷͷΛͰߜΔ ࠾༻͠ͳ͔ͬͨཧ༝ ෦Ͱ݁ہ-FWFOTIUFJOΛݺͿɻ݅نͰΠϯσοΫεߏஙίετ͕ԸܙΛ্ճΔ ΞϧΰϦζϜ 4PVOEFY.FUBQIPOF ԻӆIBTI ܭࢉྔͱΈ ͍ ఆ࣌ؒ ɻൃԻྨࣅੑͰಉΫϥεΛ࡞ΓɺϋογϡҰகͰൺֱ ࠾༻͠ͳ͔ͬͨཧ༝ ӳޠԻӆ͚ͷࢉ๏Ͱ͋Γɺຊޠ$+,ʹద༻Ͱ͖ͳ͍ ΞϧΰϦζϜ จ຺ϞσϧຒΊࠐΈڑ #&35 ܭࢉྔͱΈ େ෯ʹ͍ ेNTΫΤϦ ɻจࣈྻΛߴ࣍ݩϕΫτϧʹຒΊࠐΈɺDPTJOFڑͰྨࣅΛܭࢉ ࠾༻͠ͳ͔ͬͨཧ༝ ϦΞϧλΠϜಈըʹॏ͗͢ΔɻϞσϧ͕NBTUFSͷEPNBJOޠኮɺಛʹήʔϜޠΛΒͳ͍
ೖྗσʔλΛΩϨΠʹ͢Δࡉ͔͍ r Χˠྗ̍ͭΧλΧφͷΧΛࣈͷྗ ͔ͪΒ ʹஔ͖͑Δ ‣ ߈ܸʮྗʯͳͲܾ·ͬͨύλʔϯʹ͍ͭͯ r શ֯ɾ֯Λଗ͑Δ r
ۭനΛআڈ͢Δ Ϛονϯάͷલʹਖ਼نԽͯ͠ϊΠζΛআڈ͢Δ
ೝࣝΛ্ͤ͞Δࡉ͔͍ 0xD5D5EBF7EAD5D5EB ݩը૾ 9×8 grayscale 8×8 bit pattern 64-bit hash
E)BTIΛϋϛϯάڑͰൺֱͯ͠ྨࣅͷϑϨʔϜΛແࢹ͢Δ
None
·ͱΊ r Ϛελʔσʔλʢਖ਼ղͷఆٛʣΛ͑Δ r ϑϨʔϜ୯ҐͰޡೝࣝΛϑΟϧλʔ͢Δ ‣ .VMUJGSBNF$POTFOTVT r ࣄલʹೖྗΛΫϦʔϯʹ͢Δ ‣
ςΩετͷਖ਼نԽ ‣ Α͋͘ΔޡೝࣝΛஔ r ڍಈΛܾఆతɾ؍ଌՄೳʹ͢Δ ߴ͍࣭Ͱ࠶ݱੑͷ͋Δ݁ՌΛग़ྗ͢ΔͨΊͷ
3FTPVSDFT r IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJ$BNFSB0$3 r IUUQTHJUIVCDPNLJTIJLBXBLBUTVNJ3FMJD'PSHF r IUUQTBQQTBQQMFDPNVTBQQSFMJDGPSHFJE r IUUQTSFMJDGPSHFQBHFTEFW