-
-
Save selvypen/787fe7d13e8fd14b08ec1234e8e9bdb7 to your computer and use it in GitHub Desktop.
Simple example source of handwriting recognition for Android using Java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* @brief example source of handwriting recognition | |
* @date 2019/12/10 | |
* @file HandwritingExampleActivity.java | |
* @author SELVAS AI | |
* | |
* Copyright 2019. SELVAS AI Inc. All Rights Reserved. | |
*/ | |
package com.selvasai.handwriting; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.util.Log; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.Locale; | |
import com.diotek.dhwr.DHWR; | |
public class HandwritingExampleActivity extends Activity { | |
public final static String TAG = "HWR"; | |
final int MAX_CANDIDATES = 10; | |
private DHWR.Ink mInk; | |
private DHWR.Setting mSetting; | |
private DHWR.Result mResult; | |
// points of 'a' | |
// -1, 0 : end of stroke | |
// -1, -1 : end of ink | |
// (x0, y0), (x1, y1), ... (-1, 0) ... (xn, yn) .... (-1, 0), (-1, -1) | |
final int[] ink_a = {271, 97, 270, 95, 266, 94, 262, 94, 256, 94, 249, 94, 243, 96, 234, 100, 226, | |
107, 216, 118, 208, 127, 203, 137, 195, 147, 191, 156, 188, 163, 188, 169, 188, 172, 191, 175, | |
195, 176, 202, 176, 210, 176, 218, 176, 227, 173, 237, 170, 246, 166, 253, 161, 258, 156, 261, | |
153, 264, 148, 265, 144, 267, 139, 267, 135, 268, 131, 268, 128, 268, 123, 268, 122, 268, 120, | |
268, 117, 268, 116, 268, 119, 273, 126, 278, 133, 284, 140, 291, 145, 294, 150, 299, 153, 301, | |
156, 303, 159, 306, 160, 307, 163, 308, 163, -1, 0, -1, -1 | |
}; | |
// points of 'good morning' | |
final int[] ink_good_morning = {242, 382, 233, 372, 209, 385, 176, 425, 174, 438, 195, 447, 216, | |
427, 223, 411, 231, 379, 233, 382, 233, 405, 234, 456, 232, 512, 227, 534, 200, 569, 167, 569, 154, | |
543, 161, 513, 173, 500, 220, 476, 266, 464, 278, 458, 282, 458, -1, 0, 303, 398, 292, 403, 285, | |
426, 307, 437, 319, 430, 330, 397, 311, 385, 291, 391, 297, 401, -1, 0, 369, 383, 363, 386, 358, | |
415, 385, 421, 411, 402, 418, 388, 406, 370, 372, 380, 362, 402, 368, 406, -1, 0, 496, 385, 497, | |
384, 495, 377, 471, 383, 457, 391, 438, 418, 463, 424, 482, 416, 510, 386, 516, 343, 511, 315, | |
508, 302, 510, 306, 513, 336, 518, 384, 528, 419, 534, 425, 533, 419, -1, 0, 626, 365, 629, 370, | |
633, 392, 635, 405, 634, 421, 630, 420, 638, 389, 644, 378, 658, 371, 671, 393, 673, 412, 673, 416, | |
673, 409, 678, 389, 684, 378, 704, 366, 715, 377, 720, 397, 723, 409, 723, 411, 725, 409, 730, 402, | |
-1, 0, 756, 374, 750, 375, 749, 401, 776, 400, 788, 391, 797, 373, 766, 366, 750, 373, 763, 375, | |
-1, 0, 814, 350, 814, 347, 823, 358, 836, 390, 838, 406, 835, 409, 833, 397, 837, 389, 855, 368, | |
875, 356, 894, 354, 900, 355, 899, 365, -1, 0, 911, 342, 917, 357, 916, 370, 918, 398, 917, 401, | |
917, 384, 929, 351, 946, 341, 955, 354, 958, 366, 961, 389, 964, 401, 959, 380, -1, 0, 983, 327, | |
991, 326, 1005, 330, 1005, 338, -1, 0, 991, 362, 992, 366, 999, 393, 1001, 400, -1, 0, 1032, 344, | |
1039, 350, 1045, 376, 1046, 396, 1049, 388, 1053, 378, 1067, 355, 1079, 352, 1086, 374, 1092, 398, | |
1095, 404, 1097, 403, 1099, 398, -1, 0, 1146, 345, 1149, 350, 1140, 356, 1127, 375, 1142, 384, | |
1160, 359, 1155, 342, 1151, 343, 1164, 366, 1180, 403, 1181, 439, 1176, 457, 1153, 486, 1113, 488, | |
1089, 463, 1101, 443, 1116, 434, 1162, 417, 1219, 409, 1229, 416, 1228, 417, -1, 0, -1, -1 | |
}; | |
// points of '4' | |
final int[] ink_4 = {273, 69, 270, 72, 267, 78, 261, 88, 253, 103, 245, 115, 236, 127, 231, 137, 227, | |
144, 226, 146, 230, 146, 238, 146, 252, 146, 271, 145, 291, 143, 313, 141, 329, 139, 341, 137, | |
352, 137, 358, 137, 362, 137, 364, 136, -1, 0, 300, 105, 300, 106, 300, 112, 298, 121, 298, 132, | |
296, 143, 296, 154, 296, 163, 296, 169, 296, 177, 296, 181, 295, 186, 295, 189, 295, 190, -1, 0, | |
-1, -1 | |
}; | |
// points of '안녕하세요' | |
final int[] ink_annyeonghaseyo = {182, 315, 185, 316, 183, 316, 182, 318, 180, 320, 173, 330, 159, | |
356, 149, 384, 149, 406, 157, 426, 175, 440, 200, 451, 230, 446, 250, 431, 259, 411, 268, 384, | |
266, 357, 258, 341, 244, 330, 229, 327, 215, 326, 204, 328, 195, 332, 192, 339, -1, 0, 357, | |
269, 355, 268, 355, 271, 354, 281, 355, 317, 359, 360, 363, 403, 365, 430, 364, 443, 362, 443, | |
-1, 0, 363, 377, 368, 370, 371, 370, 381, 370, 400, 371, 424, 376, 431, 377, -1, 0, 275, 502, | |
270, 504, 268, 508, 267, 515, 268, 527, 272, 541, 281, 556, 299, 571, 324, 575, 357, 569, 387, | |
555, 408, 533, -1, 0, 506, 301, 498, 296, 497, 302, 492, 327, 484, 364, 479, 401, 478, 432, | |
482, 453, 489, 467, 502, 470, 518, 471, 551, 468, 571, 454, 574, 450, -1, 0, 552, 334, 554, | |
319, 559, 323, 574, 320, 604, 317, 635, 315, 650, 316, 659, 320, 656, 322, -1, 0, 591, 377, | |
589, 377, 598, 375, 622, 371, 650, 363, 678, 353, 683, 348, -1, 0, 701, 300, 698, 300, 697, | |
301, 696, 307, 694, 318, 692, 347, 688, 378, 682, 412, 678, 442, 678, 449, -1, 0, 621, 515, | |
606, 520, 603, 526, 600, 536, 602, 546, 616, 558, 649, 562, 674, 556, 682, 546, 679, 538, 666, | |
531, 621, 518, 594, 526, -1, 0, 790, 282, 789, 278, 789, 279, 790, 282, 799, 288, 829, 304, | |
854, 318, 871, 330, 872, 331, -1, 0, 793, 386, 787, 383, 786, 383, 785, 384, 792, 384, 827, | |
385, 861, 385, 878, 387, -1, 0, 828, 436, 807, 448, 796, 457, 783, 471, 777, 487, 778, 501, | |
790, 506, 825, 507, 847, 496, 851, 487, 850, 477, 844, 471, 830, 465, 804, 460, 792, 459, -1, | |
0, 937, 294, 936, 290, 935, 292, 933, 298, 931, 315, 930, 359, 931, 407, 935, 453, 939, 488, | |
942, 518, 942, 536, 939, 550, 936, 554, -1, 0, 939, 408, 946, 399, 947, 402, 967, 401, 997, | |
402, 1013, 405, -1, 0, 1145, 319, 1134, 315, 1135, 318, 1129, 326, 1105, 362, 1080, 403, 1058, | |
446, 1041, 476, 1030, 496, 1030, 494, -1, 0, 1069, 430, 1071, 425, 1073, 427, 1079, 433, 1092, | |
449, 1106, 471, 1114, 486, -1, 0, 1106, 416, 1104, 404, 1116, 407, 1146, 403, 1179, 399, 1206, | |
391, 1209, 389, -1, 0, 1228, 352, 1225, 357, 1224, 361, 1222, 374, 1222, 404, 1223, 431, 1226, | |
452, 1226, 466, 1225, 463, -1, 0, 1269, 345, 1268, 343, 1267, 347, 1265, 360, 1265, 398, 1267, | |
434, 1269, 466, 1272, 484, 1276, 490, -1, 0, 1373, 342, 1369, 342, 1368, 345, 1368, 354, 1372, | |
366, 1382, 376, 1404, 385, 1431, 377, 1445, 360, 1451, 334, 1446, 321, 1432, 321, 1400, 326, | |
1369, 341, 1358, 359, 1353, 380, 1357, 402, 1363, 421, 1370, 440, 1376, 459, 1377, 479, 1374, | |
497, 1369, 509, 1363, 516, 1361, 514, -1, 0, 1426, 413, 1432, 407, 1432, 408, 1434, 416, 1429, | |
442, 1413, 476, 1388, 503, 1358, 526, 1334, 534, 1319, 536, 1318, 533, 1342, 523, 1417, 503, | |
1477, 495, 1525, 497, -1, 0, -1, -1 | |
}; | |
// points of '中囯' | |
final int[] ink_zhongguo = {54, 72, 53, 72, 52, 73, 52, 75, 52, 80, 52, 83, 52, 87, 52, 89, 52, | |
95, 52, 98, 52, 101, 51, 104, 51, 106, 51, 109, 51, 111, 51, 114, 51, 116, 51, 118, 51, | |
121, 51, 122, 51, 123, 51, 120, 51, 117, 50, 114, -1, 0, 51, 81, 52, 81, 53, 81, 54, 81, | |
55, 81, 56, 81, 59, 81, 60, 81, 64, 80, 68, 79, 71, 78, 76, 78, 81, 76, 86, 75, 96, 74, | |
99, 74, 104, 73, 110, 72, 113, 72, 117, 71, 119, 71, 123, 70, 125, 70, 127, 70, 127, 69, | |
128, 69, 129, 69, 129, 70, 129, 71, 129, 73, 129, 75, 129, 78, 129, 81, 129, 84, 129, 87, | |
129, 90, 129, 94, 129, 95, 129, 97, 129, 98, 129, 101, 129, 102, 129, 103, 129, 104, 129, | |
105, 128, 106, 127, 106, 124, 106, -1, 0, 47, 114, 48, 114, 49, 114, 50, 114, 53, 114, 55, | |
114, 56, 114, 58, 114, 61, 114, 66, 114, 70, 113, 75, 112, 82, 112, 87, 111, 96, 108, 104, | |
108, 111, 107, 119, 106, 123, 106, 126, 105, 130, 105, 131, 104, 132, 104, 133, 104, 133, | |
103, 132, 101, -1, 0, 82, 30, 82, 31, 82, 32, 82, 34, 82, 38, 82, 39, 82, 41, 82, 46, 82, | |
48, 82, 52, 82, 54, 82, 58, 82, 63, 82, 67, 82, 69, 82, 75, 82, 78, 82, 83, 82, 87, 82, | |
91, 82, 95, 82, 98, 82, 102, 82, 105, 82, 110, 82, 113, 82, 116, 82, 120, 82, 124, 82, | |
128, 82, 131, 82, 134, 82, 137, 82, 139, 82, 141, 82, 146, 82, 147, 82, 148, 82, 149, 82, | |
150, 82, 151, 82, 152, 82, 153, 82, 154, 82, 155, 82, 156, 82, 157, 81, 157, 81, 155, 81, | |
152, 81, 149, -1, 0, 165, 51, 166, 54, 166, 59, 167, 64, 167, 71, 167, 76, 167, 83, 167, | |
90, 167, 96, 167, 105, 167, 110, 167, 114, 167, 118, 167, 122, 167, 125, 167, 130, 167, | |
133, 167, 135, 167, 137, 167, 138, 167, 140, 167, 138, 167, 132, 167, 129, -1, 0, 168, | |
60, 169, 60, 170, 60, 171, 60, 174, 60, 175, 60, 176, 60, 177, 60, 178, 60, 180, 60, 181, | |
60, 185, 59, 189, 59, 193, 59, 199, 58, 205, 55, 209, 54, 211, 53, 217, 52, 220, 51, 222, | |
51, 224, 51, 225, 51, 226, 51, 227, 51, 228, 50, 229, 50, 231, 50, 232, 50, 233, 50, 234, | |
50, 235, 51, 235, 53, 235, 55, 235, 56, 237, 57, 237, 60, 237, 63, 237, 64, 238, 67, 238, | |
69, 238, 73, 238, 75, 238, 80, 238, 82, 238, 86, 238, 88, 238, 94, 238, 96, 238, 99, 238, | |
103, 238, 106, 238, 110, 238, 112, 238, 116, 238, 117, 238, 119, 238, 123, 238, 125, 238, | |
126, 238, 129, 238, 130, 238, 132, 238, 134, 238, 135, 238, 136, 238, 137, 237, 135, 234, | |
131, 231, 129, 225, 124, -1, 0, 176, 90, 177, 90, 178, 90, 179, 90, 180, 90, 181, 90, 182, | |
89, 183, 89, 185, 87, 188, 87, 190, 86, 192, 85, 194, 84, 196, 84, 197, 83, 198, 83, 199, | |
83, 200, 83, 201, 83, 202, 83, 204, 83, 205, 83, 206, 83, 206, 82, -1, 0, 180, 109, 181, | |
109, 182, 109, 183, 109, 184, 109, 186, 109, 188, 109, 190, 109, 192, 109, 197, 107, 199, | |
107, 200, 107, 202, 107, 203, 106, 205, 106, 205, 105, -1, 0, 191, 86, 192, 86, 192, 89, | |
192, 90, 193, 92, 193, 93, 193, 96, 193, 98, 193, 100, 194, 103, 194, 105, 194, 106, 194, | |
108, 194, 110, 194, 111, 194, 114, 194, 115, 194, 116, 194, 118, 194, 120, 194, 122, 194, | |
123, 194, 124, 194, 125, -1, 0, 183, 129, 184, 129, 185, 129, 186, 129, 187, 129, 188, | |
129, 190, 128, 193, 127, 195, 127, 198, 126, 201, 125, 202, 124, 206, 123, 207, 123, 209, | |
123, 210, 123, 211, 123, 212, 123, 213, 123, 213, 122, -1, 0, 218, 93, 218, 94, 219, 94, | |
220, 96, 221, 96, 221, 98, 221, 99, 223, 99, 223, 101, 224, 102, 225, 103, 225, 105, 226, | |
106, 227, 107, 227, 108, 227, 109, -1, 0, 169, 146, 170, 146, 171, 146, 172, 146, 176, 146, | |
181, 145, 187, 145, 192, 143, 197, 143, 203, 142, 206, 142, 208, 141, 210, 141, 211, 141, | |
212, 141, 213, 141, 213, 140, 214, 140, 215, 140, 216, 140, 217, 140, 218, 140, 219, 140, | |
221, 140, 223, 140, 224, 140, 225, 140, 226, 140, -1, 0, -1, -1 | |
}; | |
// points of 'ありがとう' | |
final int[] ink_arigatou = {272, 331, 265, 338, 311, 340, 400, 328, 455, 306, 470, 282, -1, 0, 354, | |
236, 342, 243, 342, 305, 357, 394, 374, 462, 386, 499, 384, 479, -1, 0, 444, 350, 435, 388, 416, | |
412, 349, 454, 299, 459, 278, 439, 325, 391, 411, 373, 457, 392, 456, 452, 451, 463, 455, 454, -1, | |
0, 569, 310, 570, 327, 571, 365, 570, 380, 569, 370, -1, 0, 619, 280, 620, 280, 632, 309, 639, 357, | |
638, 386, 620, 447, 591, 505, 585, 516, 596, 489, -1, 0, 706, 315, 705, 310, 735, 308, 794, 308, | |
827, 327, 826, 388, 808, 437, 790, 459, 785, 441, -1, 0, 816, 251, 803, 248, 772, 302, 739, 364, | |
723, 426, 723, 468, 740, 450, 747, 441, -1, 0, 839, 294, 851, 303, 859, 330, 861, 344, 858, 338, | |
-1, 0, 869, 235, 874, 240, 876, 249, 878, 263, 872, 259, -1, 0, 887, 223, 892, 227, 902, 249, 906, | |
264, -1, 0, 970, 266, 979, 288, 994, 314, 1015, 320, -1, 0, 1075, 272, 1078, 276, 1021, 338, 962, | |
391, 940, 432, 946, 458, 971, 482, 1029, 487, 1069, 475, 1090, 463, -1, 0, 1181, 234, 1223, 256, | |
1237, 262, 1249, 270, -1, 0, 1151, 336, 1146, 340, 1193, 320, 1246, 320, 1285, 337, 1290, 387, | |
1246, 448, 1203, 494, 1204, 486, -1, 0, -1, -1 | |
}; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
copyResourceToStorage(); | |
initEngine(); | |
testKorean(); | |
testEnglish(); | |
testChinese(); | |
testJapanese(); | |
destroyEngine(); | |
} | |
private void copyResourceToStorage() { | |
String path = "hdb"; | |
String[] fileList = null; | |
try { | |
fileList = getAssets().list(path); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
if (fileList == null) { | |
return; | |
} | |
for (String file : fileList) { | |
try { | |
String filePath = (path + "/" + file); | |
try { | |
FileInputStream fis = openFileInput(file); | |
fis.close(); | |
} catch (FileNotFoundException e) { | |
InputStream is = getAssets().open(filePath); | |
final int bufferSize = is.available(); | |
byte[] buffer = new byte[bufferSize]; | |
int readSize = is.read(buffer); | |
is.close(); | |
if (readSize > 0) { | |
FileOutputStream fos = openFileOutput(file, Activity.MODE_PRIVATE); | |
fos.write(buffer); | |
fos.close(); | |
} | |
} | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
private void makeInputEvent(DHWR.Ink ink, int[] inputs) { | |
DHWR.InkClear(ink.GetHandle()); | |
int i = 0; | |
while (true) { | |
if (inputs[i] == -1 && inputs[i + 1] == -1) { // if end of inks | |
break; | |
} else if (inputs[i] == -1 && inputs[i + 1] == 0) { // if end of stroke | |
DHWR.EndStroke(ink.GetHandle()); | |
} else { | |
DHWR.AddPoint(ink.GetHandle(), inputs[i], inputs[i + 1]); | |
} | |
i += 2; | |
} | |
} | |
private String getCandidates(DHWR.Result result) { | |
StringBuilder candidates = new StringBuilder(); | |
boolean exit = false; | |
int resultSize = result.size(); | |
if (resultSize < 1) { | |
return "result empty"; | |
} | |
for (int i = 0; i < MAX_CANDIDATES; i++) { | |
for (int j = 0; j < resultSize; j++) { | |
DHWR.Line line = result.get(j); | |
for (int k = 0; k < line.size(); k++) { | |
DHWR.Block block = line.get(k); | |
if (block.candidates.size() <= i) { | |
exit = true; | |
break; | |
} | |
candidates.append(String.format(Locale.US, " [%d] ", i + 1)); | |
candidates.append(block.candidates.get(i)); | |
if (k + 1 < line.size()) { | |
candidates.append(" "); | |
} | |
} | |
if (exit) { | |
break; | |
} | |
if (j + 1 < result.size()) { | |
candidates.append("\n"); | |
} | |
} | |
if (exit) { | |
break; | |
} | |
candidates.append("\n"); | |
} | |
return candidates.toString(); | |
} | |
private void printResult(String title, int status) { | |
if (status == DHWR.ERR_SUCCESS) { | |
Log.d(TAG, title + " ...Success"); | |
Log.d(TAG, "Recognized Text:\n" + getCandidates(mResult)); | |
} else { | |
Log.d(TAG, title + " ...Failed" + " (" + status + ")"); | |
} | |
} | |
private int initEngine() { | |
final int MAX_VERSION_LENGTH = 64; | |
char[] version = new char[MAX_VERSION_LENGTH]; | |
DHWR.GetRevision(version); | |
final String filesPath = getFilesDir().getAbsolutePath(); | |
int status = DHWR.Create(filesPath + "/" + "license.key"); | |
DHWR.SetExternalResourcePath(filesPath.toCharArray()); | |
DHWR.SetExternalLibraryPath(getApplicationInfo().nativeLibraryDir.toCharArray()); | |
mInk = new DHWR.Ink(); | |
mSetting = new DHWR.Setting(); | |
mResult = new DHWR.Result(); | |
DHWR.SetRecognitionMode(mSetting.GetHandle(), DHWR.MULTICHAR); | |
DHWR.SetCandidateSize(mSetting.GetHandle(), MAX_CANDIDATES); | |
Log.d(TAG, "SDK Version: " + String.valueOf(version).trim()); | |
Log.d(TAG, "Initialize Engine ..." + (status == DHWR.ERR_SUCCESS ? "Success" : "Failed")); | |
return status; | |
} | |
private int destroyEngine() { | |
int status = DHWR.Close(); | |
Log.d(TAG, "Destroy Engine ..." + (status == DHWR.ERR_SUCCESS ? "Success" : "Failed")); | |
return status; | |
} | |
private int testKorean() { | |
DHWR.ClearLanguage(mSetting.GetHandle()); | |
DHWR.AddLanguage(mSetting.GetHandle(), DHWR.DLANG_KOREAN, DHWR.DTYPE_KOREAN); | |
DHWR.SetAttribute(mSetting.GetHandle()); | |
makeInputEvent(mInk, ink_annyeonghaseyo); | |
int status = DHWR.Recognize(mInk, mResult); | |
printResult("Korean Test", status); | |
return status; | |
} | |
private int testEnglish() { | |
DHWR.ClearLanguage(mSetting.GetHandle()); | |
DHWR.AddLanguage(mSetting.GetHandle(), DHWR.DLANG_ENGLISH, DHWR.DTYPE_UPPERCASE | DHWR.DTYPE_LOWERCASE); | |
DHWR.SetAttribute(mSetting.GetHandle()); | |
makeInputEvent(mInk, ink_good_morning); | |
int status = DHWR.Recognize(mInk, mResult); | |
printResult("English Test", status); | |
return status; | |
} | |
private int testChinese() { | |
DHWR.ClearLanguage(mSetting.GetHandle()); | |
DHWR.AddLanguage(mSetting.GetHandle(), DHWR.DLANG_CHINA, DHWR.DTYPE_SIMP); | |
DHWR.SetAttribute(mSetting.GetHandle()); | |
makeInputEvent(mInk, ink_zhongguo); | |
int status = DHWR.Recognize(mInk, mResult); | |
printResult("Chinese Test", status); | |
return status; | |
} | |
private int testJapanese() { | |
DHWR.ClearLanguage(mSetting.GetHandle()); | |
DHWR.AddLanguage(mSetting.GetHandle(), DHWR.DLANG_JAPANESE, DHWR.DTYPE_HIRAGANA); | |
DHWR.SetAttribute(mSetting.GetHandle()); | |
makeInputEvent(mInk, ink_arigatou); | |
int status = DHWR.Recognize(mInk, mResult); | |
printResult("Japanese Test", status); | |
return status; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment