📄 recognize.c
字号:
/* Create a new stroke by applying the transformation to the source */{ Stroke *stroke; int k, j; stroke = stroke_new(0); for (k = 0, j = 0; k < STROKES_MAX && j < src->len; k++) for (j = 0; j < src->len; j++) if (tfm->order[j] - 1 == i && tfm->glue[j] == k) { glue_stroke(&stroke, src->strokes[j], tfm->reverse[j]); break; } process_stroke(stroke); return stroke;}/* Recognition and training*/Sample *input = NULL;int strength_sum = 0;static GTimer *timer;void recognize_init(void){#ifndef DISABLE_WORDFREQ load_wordfreq();#endif timer = g_timer_new();}void recognize_sample(Sample *sample, Sample **alts, int num_alts){ gulong microsec; int i, range, strength, msec; g_timer_start(timer); input = sample; process_sample(input); /* Clear ratings */ sampleiter_reset(); while ((sample = sampleiter_next())) { memset(sample->ratings, 0, sizeof (sample->ratings)); sample->rating = 0; } /* Run engines */ for (i = 0, range = 0; i < ENGINES; i++) { int rated = 0; if (engines[i].func) engines[i].func(); /* Compute average and maximum value */ engines[i].max = 0; engines[i].average = 0; sampleiter_reset(); while ((sample = sampleiter_next())) { int value = 0; if (!sample->ch) continue; if (sample->ratings[i] > value) value = sample->ratings[i]; if (!value && engines[i].ignore_zeros) continue; if (value > engines[i].max) engines[i].max = value; engines[i].average += value; rated++; } if (!rated) continue; engines[i].average /= rated; if (engines[i].max > 0) range += engines[i].range; if (engines[i].max == engines[i].average) { engines[i].average = 0; continue; } engines[i].max -= engines[i].average; } if (!range) { g_timer_elapsed(timer, µsec); msec = microsec / 100; g_message("Recognized -- No ratings, %dms", msec); input->ch = 0; return; } /* Rank the top samples */ alts[0] = NULL; sampleiter_reset(); while ((sample = sampleiter_next())) { int j; sample_rating(sample); if (sample->rating < 1) continue; /* Bubble-sort the new rating in */ for (j = 0; j < num_alts; j++) if (!alts[j]) { if (j < num_alts - 1) alts[j + 1] = NULL; break; } else if (alts[j]->ch == sample->ch) { if (alts[j]->rating >= sample->rating) j = num_alts; break; } else if (alts[j]->rating < sample->rating) { int k; if (j == num_alts - 1) break; /* See if the character is in the list */ for (k = j + 1; k < num_alts - 1 && alts[k] && alts[k]->ch != sample->ch; k++); /* Do not swallow zeroes */ if (!alts[k] && k < num_alts - 1) alts[k + 1] = NULL; memmove(alts + j + 1, alts + j, sizeof (*alts) * (k - j)); break; } if (j >= num_alts) continue; alts[j] = sample; } /* Normalize the alternates' accuracies to 100 */ if (range) for (i = 0; i < num_alts && alts[i]; i++) alts[i]->rating = alts[i]->rating * 100 / range; /* Keep track of strength stat */ strength = 0; if (alts[0]) { strength = alts[1] ? alts[0]->rating - alts[1]->rating : 100; strength_sum += strength; } g_timer_elapsed(timer, µsec); msec = microsec / 100; g_message("Recognized -- %d/%d (%d%%) disqualified, " "%dms (%dms/symbol), %d%% strong", num_disqualified, prep_examined, num_disqualified * 100 / prep_examined, msec, prep_examined - num_disqualified ? msec / (prep_examined - num_disqualified) : -1, strength); /* Print out the top candidate scores in detail */ if (log_level >= G_LOG_LEVEL_DEBUG) for (i = 0; i < num_alts && alts[i]; i++) { int j, len; len = input->len >= alts[i]->len ? input->len : alts[i]->len; log_print("| '%C' (", alts[i]->ch); for (j = 0; j < ENGINES; j++) log_print("%4d [%5d]%s", engine_rating(alts[i], j), alts[i]->ratings[j], j < ENGINES - 1 ? "," : ""); log_print(") %3d%% [", alts[i]->rating); for (j = 0; j < len; j++) log_print("%d", alts[i]->transform.order[j] - 1); for (j = 0; j < len; j++) log_print("%c", alts[i]->transform.reverse[j] ? 'R' : '-'); for (j = 0; j < len; j++) log_print("%d", alts[i]->transform.glue[j]); log_print("]\n"); } /* Select the top result */ input->ch = alts[0] ? alts[0]->ch : 0;}static void insert_sample(const Sample *new_sample, int force_overwrite)/* Insert a sample into the sample chain, possibly overwriting an older sample */{ int last_used, count = 0; Sample *sample, *overwrite = NULL, *create = NULL; last_used = force_overwrite ? current + 1 : new_sample->used; sampleiter_reset(); while ((sample = sampleiter_next())) { if (!sample->used) { create = sample; continue; } if (sample->ch != new_sample->ch) continue; if (sample->used < last_used) { overwrite = sample; last_used = sample->used; } count++; } if (overwrite && count >= samples_max) { sample = overwrite; clear_sample(sample); } else if (create) sample = create; else sample = sample_new(); *sample = *new_sample; process_sample(sample);}void train_sample(const Sample *sample, int trusted)/* Overwrite a blank or least-recently-used slot in the samples set */{ Sample new_sample; /* Do not allow zero-length samples */ if (sample->len < 1) { g_warning("Attempted to train zero length sample for '%C'", sample->ch); return; } copy_sample(&new_sample, sample); new_sample.used = trusted ? current++ : 1; new_sample.enabled = TRUE; insert_sample(&new_sample, TRUE);}int char_trained(int ch)/* Count the number of samples for this character */{ Sample *sample; int count = 0; sampleiter_reset(); while ((sample = sampleiter_next())) { if (sample->ch != ch) continue; count++; } return count;}void untrain_char(int ch)/* Delete all samples for a character */{ Sample *sample; sampleiter_reset(); while ((sample = sampleiter_next())) if (sample->ch == ch) clear_sample(sample);}/* Profile*/void recognize_sync(void)/* Sync params with the profile */{ int i; profile_write("recognize"); profile_sync_int(¤t); profile_sync_int(&samples_max); if (samples_max < 1) samples_max = 1; profile_sync_int(&no_latin_alpha); for (i = 0; i < ENGINES; i++) profile_sync_int(&engines[i].range); profile_write("\n");}void sample_read(void)/* Read a sample from the profile */{ Sample sample; Stroke *stroke; memset(&sample, 0, sizeof (sample)); sample.ch = atoi(profile_read()); if (!sample.ch) { g_warning("Sample on line %d has NULL symbol", profile_line); return; } sample.used = atoi(profile_read()); stroke = sample.strokes[0]; for (;;) { const char *str; int x, y; str = profile_read(); if (!str[0]) { if (!sample.strokes[0]) { g_warning("Sample on line %d ('%C') with no " "point data", profile_line, sample.ch); break; } insert_sample(&sample, FALSE); break; } if (str[0] == ';') { stroke = sample.strokes[sample.len]; continue; } if (sample.len >= STROKES_MAX) { g_warning("Sample on line %d ('%C') is oversize", profile_line, sample.ch); clear_sample(&sample); break; } if (!stroke) { stroke = stroke_new(0); sample.strokes[sample.len++] = stroke; } if (stroke->len >= POINTS_MAX) { g_warning("Symbol '%C' stroke %d is oversize", sample.ch, sample.len); clear_sample(&sample); break; } x = atoi(str); y = atoi(profile_read()); draw_stroke(&stroke, x, y); }}static void sample_write(Sample *sample)/* Write a sample link to the profile */{ int k, l; profile_write(va("sample %5d %5d", sample->ch, sample->used)); for (k = 0; k < sample->len; k++) { for (l = 0; l < sample->strokes[k]->len; l++) profile_write(va(" %4d %4d", sample->strokes[k]->points[l].x, sample->strokes[k]->points[l].y)); profile_write(" ;"); } profile_write("\n");}void samples_write(void)/* Write all of the samples to the profile */{ Sample *sample; sampleiter_reset(); while ((sample = sampleiter_next())) if (sample->ch && sample->used) sample_write(sample);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -