sclass SimpleRecognizer { bool useCache1 = true, useCache2 = true; S initial = [[ The images "9176714c9a935fc91e14595dbb3adddf 35731666e72dd0c9448f616ff3a7464a da9bc5a24bd503e898f69ad43bb9b92e" are the characters "yet". The images "412f9e0f8e177817a4fa285415c5a13f 386b289407599f31e3a7c57c3adb2587 6cd2a2284a5a6fda3a7cad3e3a048671 b0c47c014d665ec5b658f510c258dc47 b273ff598fe6afa04cfed9f9e8fb4109" are the grouped characters "[Ob]ject". The images "175116b749670b7b65707c10c935b42c ddaf2b9c198818c49628387ecc2910ed 3777597e39eb0de16c022293c8c91cc0 fad86bda3f716ef4e7fa9d199f6c4383 35731666e72dd0c9448f616ff3a7464a 03b96c30adaaed5b60cea4ab9bc37263" are the characters "images". ]]; Lock lock = lock(); class GlyphInfo { S meaning; bool multi; // multiple meanings seen } // key = md5 new Map<S, GlyphInfo> glyphInfos; // optional for full similarity search - character image to MD5 Map<BWImage, S> fullSearchMap; S unknownCharacter = diamond(); // "\u2666" - diamond suit symbol; used for unknown characters *() { load(initial); } void load(S info) { lock lock; recognizeGrouped_cache.clear(); new Matches m; for (S s : toLinesFullTrim(info)) { if (find3("the images * are the characters *", s, m)) { L<S> md5s = splitAtSpace($1); L<S> characters = eachCharAsString(dropSpaces($2)); saveMeanings(md5s, characters); } else if (find3("the images * are the grouped characters *", s, m)) { L<S> md5s = splitAtSpace($1); L<S> characters = ocr_parseGlyphs(dropSpaces($2)); saveMeanings(md5s, characters); } else if (nempty(javaTokC(s))) { print("huh? " + s); } } //print("Have " + n(l(glyphInfos), "glyph info")); //psl(glyphInfos); } void saveMeaning(S md5, S meaning) { GlyphInfo info = getGlyphInfo(md5); if (info.multi) ret; if (hasDifferent(info.meaning, meaning)) { //info.meaning = null; info.meaning = meaning; info.multi = true; //print("multi"); } else info.meaning = meaning; } // gets or creates GlyphInfo GlyphInfo getGlyphInfo(S md5) { GlyphInfo info = glyphInfos.get(md5); if (info == null) glyphInfos.put(md5, info = new GlyphInfo); ret info; } void saveMeanings(L<S> md5s, L<S> characters) { if (l(md5s) != l(characters)) { print("huh?"); ret; } for i over md5s: saveMeaning(md5s.get(i), characters.get(i)); } // lookup stored recognition of whole image Scored<S> recognizeCheat(BWImage img) { lock lock; Scored<GlyphInfo> scored = recognizeGlyph(img, false); GlyphInfo info = getVar(scored); if (info != null && info.meaning != null) ret scored(info.meaning, scored); null; } S recognize(BWImage img) { ret ocr_joinGroups(recognizeGrouped(img)); } Scored<S> recognizeScored(BWImage img) { Scored<L<S>> s = recognizeGrouped(img, null); ret scored(ocr_joinGroups(s!), s); } L<S> recognizeGrouped(BWImage img) { ret getVar(recognizeGrouped(img, null)); } // md5 -> recognition result Map<S, Scored<L<S>>> recognizeGrouped_cache = synchroMap(); int cantCache, cacheHits, cacheMisses; Scored<L<S>> recognizeGrouped(BWImage img, L<Rect> clips_out) { S md5 = null; if (clips_out != null || !useCache1) ++cantCache; else { md5 = md5OfBWImage(img); Scored<L<S>> result = recognizeGrouped_cache.get(md5); if (result != null) { ++cacheHits; ret result; } else ++cacheMisses; } Scored<L<S>> result = recognizeGrouped_uncached(img, clips_out); if (md5 != null) recognizeGrouped_cache.put(md5, result); ret result; } Scored<L<S>> recognizeGrouped_uncached(BWImage img, L<Rect> clips_out) { lock lock; // TODO: auto-crop here? Scored<S> s = recognizeCheat(img); if (s != null) { if (clips_out != null) clips_out.add(new Rect(0, 0, img.w(), img.h())); ret scored(ll(ocr_escapeMeaning(s!)), s); // hmm... how to group? does it matter? } new L<S> buf; L<Rect> rects = horizontalAutoSplit2ThenAutoCrop(img); if (empty(rects)) ret scored(ll(unknownCharacter), 0.5); new L<Scored> scores; iLoop: for (int i = 0; i < l(rects); i++) { Rect r = null; for (int j = i; j < l(rects); j++) { r = rectUnion(r, rects.get(j)); BWImage cImg = img.clip(r); Scored<GlyphInfo> scored = recognizeGlyph(cImg, false); GlyphInfo info = getVar(scored); if (info != null && info.meaning != null) { buf.add(info.meaning); buf.addAll(rep("_", j-i)); if (clips_out != null) clips_out.addAll(rep(r, j-i+1)); scores.add(scored); i = j; continue iLoop; } } r = rects.get(i); Scored<GlyphInfo> scored = recognizeGlyph(img.clip(r), true); GlyphInfo info = getVar(scored); if (info != null && info.meaning != null) buf.add(info.meaning); else buf.add(unknownCharacter); if (clips_out != null) clips_out.add(r); scores.add(scored); } ret scored(buf, averageScore(scores)); } // md5 -> recognition result Map<S, Scored<GlyphInfo>> recognizeGlyph_cache = synchroMap(); static int cacheHits2, cacheMisses2; Scored<GlyphInfo> recognizeGlyph(BWImage img, bool fullSearch) { S md5 = md5OfBWImage(img); GlyphInfo info = glyphInfos.get(md5); if (info != null || !fullSearch || fullSearchMap == null) ret fullScored(info); if (useCache2) { Scored<GlyphInfo> result = recognizeGlyph_cache.get(md5); if (result != null) { ++cacheHits2; ret result; } cacheMisses2++; } new Best<S> best; for (BWImage cImg : keys(fullSearchMap)) { float sim = bwImageSimilarityResized(img, cImg, (float) best.bestScore()); best.put(fullSearchMap.get(cImg), sim); } Scored<GlyphInfo> result = !best.has() ? null : scored(glyphInfos.get(best!), best.score()); if (useCache2) recognizeGlyph_cache.put(md5, result); ret result; } S cacheStats() { //ret "Cache size: " + l(recognizeGrouped_cache) + ", hits: " + cacheHits + ", misses: " + cacheMisses + ", uncachable: " + cantCache; ret "Cache size: " + l(recognizeGlyph_cache) + ", hits: " + cacheHits2 + ", misses: " + cacheMisses2 + ", full search map: " + l(fullSearchMap); } }
Began life as a copy of #1006108
download show line numbers debug dex old transpilations
Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1015444 |
Snippet name: | class SimpleRecognizer v1 - recognizes a line of text - works, but slowly |
Eternal ID of this version: | #1015444/1 |
Text MD5: | 643bb1d800a7b79993812b9da91ef543 |
Author: | stefan |
Category: | javax / ocr |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2018-05-14 01:04:14 |
Source code size: | 6653 bytes / 190 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 353 / 393 |
Referenced in: | [show references] |