Warning: session_start(): open(/var/lib/php/sessions/sess_53mp5ia8emlkp25ph6ne3tkdk7, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
sclass SimpleRecognizer {
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 glyphInfos;
// optional for full similarity search - character image to MD5
Map 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 md5s = splitAtSpace($1);
L characters = eachCharAsString(dropSpaces($2));
saveMeanings(md5s, characters);
} else if (find3("the images * are the grouped characters *", s, m)) {
L md5s = splitAtSpace($1);
L 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 md5s, L 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 recognizeCheat(BWImage img) {
lock lock;
Scored 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 recognizeScored(BWImage img) {
Scored> s = recognizeGrouped(img, null);
ret scored(ocr_joinGroups(s!), s);
}
L recognizeGrouped(BWImage img) {
ret getVar(recognizeGrouped(img, null));
}
// md5 -> recognition result
Map> recognizeGrouped_cache = synchroMap();
Scored> recognizeGrouped(BWImage img, L clips_out) {
S md5 = null;
if (clips_out == null) {
md5 = md5OfBWImage(img);
Scored> result = recognizeGrouped_cache.get(md5);
if (result != null) ret result;
}
Scored> result = recognizeGrouped_uncached(img, clips_out);
if (md5 != null) recognizeGrouped_cache.put(md5, result);
ret result;
}
Scored> recognizeGrouped_uncached(BWImage img, L clips_out) {
lock lock;
// TODO: auto-crop here?
Scored 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 buf;
L rects = horizontalAutoSplit2ThenAutoCrop(img);
if (empty(rects)) ret scored(ll(unknownCharacter), 0.5);
new L 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 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 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));
}
Scored recognizeGlyph(BWImage img, bool fullSearch) {
S md5 = md5OfBWImage(img);
GlyphInfo info = glyphInfos.get(md5);
if (info != null || !fullSearch || fullSearchMap == null) ret fullScored(info);
new Best best;
for (BWImage cImg : keys(fullSearchMap)) {
float sim = bwImageSimilarityResized(img, cImg, (float) best.bestScore());
best.put(fullSearchMap.get(cImg), sim);
}
ret !best.has() ? null : scored(glyphInfos.get(best!), best.score());
}
}