안드로이드 문자인식
저번에 Tesseract와 OpenALPR을 이용하여 C# 프로그램을 만들었는데 이번에는 안드로이드에서 만들어보겠습니다!!
참고 ☞ C# 문자인식 프로그래밍
안드로이드에서 문자인식을 하기위해서는 기본적으로 OpenCV 라이브러리가 필요합니다.
참고 ☞ 안드로이드에서 OpenCV 사용하기
안드로이드에서는 API를 사용하지 않고 조금 원시적인(?) 방법으로 문자인식으로 해보려고 합니다.
※ 문자인식을 하기 위한 절차
1. 안드로이드와 카메라를 연동합니다.(CameraPreview)
2. 사진을 촬영하고 내부저장소에 저장합니다.(PNG)
3. 저장소에 저장된 이미지파일을 불러옵니다.(Bitmap)
4. 불러온 이미지 파일에 전처리 작업을 수행합니다.(GrayScale, ThresHold, 등)
5. 전체 이미지에서 번호판 영역을 관심영역으로 설정하고 따로 분류합니다.(ROI, contours)
6. 분류된 번호판 영역 이미지 파일에서 번호판 숫자 및 문자를 라벨링 처리합니다.
7. 라벨링 처리 된 숫자 및 문자들을 미리 준비한 템플릿과 비교합니다.
8. 비교한 결과 중 가장 매칭률이 높은 숫자 및 문자를 선별합니다.
9. 모든 숫자와 문자를 순서대로 조합하면 문자인식 결과입니다.
안드로이드에서도 물론 Tesseract API(tess-two)를 사용할 수 있습니다. (30줄 이내에...)
하지만 이런 원시적인 방법을 통해 실제로 문자 및 패턴인식을 하는 원리를 파악할 수 있으며 가장 중요한것은 인식률이 상당히 높다는 것입니다!!! (Tesseract OCR이 한글 문자 인식률이 매우 낮은걸로 유명하죠... 하지만 워낙 라이브러리 자체가 유연해서 거의 모든 프로그래밍 언어를 지원하며 문자 인식 훈련을 통해 인식률을 높일수 있답니다.)
자 그럼 절차대로 하나하나씩 따라해봅시다.
1, 2. 안드로이드 카메라 연동 및 사진 저장 : 이미 블로그에 설명한 내용이 있으므로 링크로 대체합니다.
3. 저장된 이미지 파일 불러오기 : 내부 저장소에 저장된 이미지 파일을 불러오는 방법은 다음과 같이 간단합니다. PNG파일을 File 객체를 통해 지정하고 BitmapFactory.decodeFile을 통해 이미지를 비트맵 객체로 불러올 수 있습니다.
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/OpenCVTest/sample.png");
if(file.exists()){
Bitmap myBitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
4. 이미지 전처리 작업 : 기본적으로 GrayScale(흑백) 및 ThresHold(이진화) 처리를 수행합니다.
Bitmap image1;
OpenCVLoader.initDebug();
Mat img1=new Mat();
Utils.bitmapToMat(myBitmap ,img1);
Mat imageGray1 = new Mat();
Mat imageCny1 = new Mat();
Imgproc.cvtColor(img1, imageGray1, Imgproc.COLOR_BGR2GRAY);
Imgproc.threshold(imageGray1, imageCny1, 160, 255, Imgproc.THRESH_BINARY);
5. 이미지 관심영역 추출 : 링크
6, 7, 8, 9. 번호판 숫자 인식 :
코드가 약간 복잡합니다. 간단히 설명드리면 다음 절차와 같이 수행합니다.
1. 전체사진 불러오기 -> 전처리 -> 번호판만 추출
2. 번호판사진 불러오기 -> 흑백 반전(검은바탕에 흰색 숫자가 되도록) -> 숫자 추출
3. 추출된 숫자와 템플릿 비교
4. 결과 출력
* 신형 번호판의 숫자와 문자는 00가 0000 이런식으로 숫자6개 문자1개 총 7개의 라벨이 생깁니다. 하지만 'ㄱ ㅏ' 라는 문자의 경우 'ㄱ'과 'ㅏ'를 따로 라벨링 처리하기 때문에 총 8개의 문자가 생길때도 있습니다. 이를 처리하기위해 라벨이 7개, 8개인 경우를 각각 조건문으로 처리했습니다.
int[][] listarr = new int[8][4];
List<MatOfPoint> contoursROI = new ArrayList<>();
Mat hierarchyROI = new Mat();
Mat matROI = new Mat();
Mat ResultROI = new Mat();
Utils.bitmapToMat(roi, matROI);
Imgproc.cvtColor(matROI, ResultROI, Imgproc.COLOR_BGR2GRAY, 1);
Imgproc.findContours(ResultROI, contoursROI, hierarchyROI, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
int count = 0;
for(int idx = 0; idx >= 0; idx = (int) hierarchyROI.get(0, idx)[0]) {
if(count>7) break;
MatOfPoint matOfPoint = contoursROI.get(idx);
Rect rect = Imgproc.boundingRect(matOfPoint);
// 해상도별로 조절하기.
if(rect.x < roi.getWidth()/20 || rect.x > roi.getWidth()-(roi.getWidth()/10) ||
rect.y < roi.getHeight()/10 || rect.y > roi.getHeight()-(roi.getHeight()/10) ||
rect.width < roi.getWidth()/50 || rect.width > roi.getWidth()/8 ||
rect.height <= roi.getHeight()/10 ) continue;
Log.d("RECT : ", "x : " + rect.x + ", y : " + rect.y + ", w :" + rect.width + ", h : " + rect.height);
Imgproc.rectangle(matROI, rect.tl(), rect.br(), new Scalar(255, 0, 0, 255), 1);
listarr[count][0] = rect.x;
listarr[count][1] = rect.y;
listarr[count][2] = rect.width;
listarr[count][3] = rect.height;
count++;
}
if(count == 7) {
// 오름차순 정렬
for(int i = 0; i < 7; i++) {
for(int j = i; j < 7; j++) {
if(listarr[i][0] > listarr[j][0]) {
// 스왑
int[] temp = new int[4];
temp[0] = listarr[i][0];
temp[1] = listarr[i][1];
temp[2] = listarr[i][2];
temp[3] = listarr[i][3];
listarr[i][0] = listarr[j][0];
listarr[i][1] = listarr[j][1];
listarr[i][2] = listarr[j][2];
listarr[i][3] = listarr[j][3];
listarr[j][0] = temp[0];
listarr[j][1] = temp[1];
listarr[j][2] = temp[2];
listarr[j][3] = temp[3];
}
}
}
for(int i = 0; i < 7; i++) {
Bitmap tempBitmap = Bitmap.createBitmap(roi, listarr[i][0], listarr[i][1], listarr[i][2], listarr[i][3]);
tempBitmap = Bitmap.createScaledBitmap(tempBitmap, 10, 15, true);
if(i == 0)
imageViewROI1.setImageBitmap(tempBitmap);
else if(i == 1)
imageViewROI2.setImageBitmap(tempBitmap);
else if(i == 2)
imageViewROI3.setImageBitmap(tempBitmap);
else if(i == 3)
imageViewROI4.setImageBitmap(tempBitmap);
else if(i == 4)
imageViewROI5.setImageBitmap(tempBitmap);
else if(i == 5)
imageViewROI6.setImageBitmap(tempBitmap);
else if(i == 6)
imageViewROI7.setImageBitmap(tempBitmap);
int num_count = 0;
double max = 0.0;
int num = 0;
if(i==2) { // 문자
for(int n = 0; n < 10; n++) {
for(int j = 0; j < 15; j++) {
for(int k = 0; k < 10; k++) {
if(ones[n][j][k] == tempBitmap.getPixel(k, j))
num_count++;
}
}
double result = (double)num_count/proones[n]*100;
if(result > 100) result = 100;
if(result > max) {
max = result;
num = n;
}
num_count=0;
}
}
else { // 숫자
for(int n = 0; n < 10; n++) {
for(int j = 0; j < 15; j++) {
for(int k = 0; k < 10; k++) {
if(nums[n][j][k] == tempBitmap.getPixel(k, j))
num_count++;
}
}
double result = (double)num_count/pronums[n]*100;
if(result > 100) result = 100;
if(result > max) {
max = result;
num = n;
}
num_count=0;
}
}
avg+=max;
String floatnum = String.format("%.2f", max);
if(i == 2) { // 한글 처리
// 중략
}
int a = 0, b = 0, c = 0;
for(int x=0; x<tempBitmap.getHeight(); x++) {
for (int y = 0; y < tempBitmap.getWidth(); y++) {
if (tempBitmap.getPixel(y, x) == -1) {
Log.d("arr", "ones[5][" + a + "][" + b + "] = " + tempBitmap.getPixel(y, x) + ";");
c++;
}
b++;
}
b = 0;
a++;
}
Log.d("count" , ""+c);
}
else { // 숫자 처리
textViewResult.append(i + "번째 분석 결과 : " + num + " / 정확도 : " + floatnum +"%\n");
result += Integer.toString(num);
}
}
}
else if(count == 8) {
// 오름차순 정렬
for(int i = 0; i < 8; i++) {
for(int j = i; j < 8; j++) {
if(listarr[i][0] > listarr[j][0]) {
// 스왑
int[] temp = new int[4];
temp[0] = listarr[i][0];
temp[1] = listarr[i][1];
temp[2] = listarr[i][2];
temp[3] = listarr[i][3];
listarr[i][0] = listarr[j][0];
listarr[i][1] = listarr[j][1];
listarr[i][2] = listarr[j][2];
listarr[i][3] = listarr[j][3];
listarr[j][0] = temp[0];
listarr[j][1] = temp[1];
listarr[j][2] = temp[2];
listarr[j][3] = temp[3];
}
}
}
// 한글인 경우
if(abs(listarr[2][0]-listarr[3][0]) < 20) {
if(listarr[2][1] > listarr[3][1]) {
// 스왑
int[] temp = new int[4];
temp[0] = listarr[2][0];
temp[1] = listarr[2][1];
temp[2] = listarr[2][2];
temp[3] = listarr[2][3];
listarr[2][0] = listarr[3][0];
listarr[2][1] = listarr[3][1];
listarr[2][2] = listarr[3][2];
listarr[2][3] = listarr[3][3];
listarr[3][0] = temp[0];
listarr[3][1] = temp[1];
listarr[3][2] = temp[2];
listarr[3][3] = temp[3];
}
}
for(int i = 0; i < 8; i++) {
Bitmap tempBitmap = Bitmap.createBitmap(roi, listarr[i][0], listarr[i][1], listarr[i][2], listarr[i][3]);
tempBitmap = Bitmap.createScaledBitmap(tempBitmap, 10, 15, true);
if(i == 0)
imageViewROI1.setImageBitmap(tempBitmap);
else if(i == 1)
imageViewROI2.setImageBitmap(tempBitmap);
else if(i == 2)
imageViewROI3.setImageBitmap(tempBitmap);
else if(i == 3)
imageViewROI4.setImageBitmap(tempBitmap);
else if(i == 4)
imageViewROI5.setImageBitmap(tempBitmap);
else if(i == 5)
imageViewROI6.setImageBitmap(tempBitmap);
else if(i == 6)
imageViewROI7.setImageBitmap(tempBitmap);
else if(i == 7)
imageViewROI8.setImageBitmap(tempBitmap);
int num_count = 0;
double max = 0.0;
int num = 0;
// 자음
if(i==2) {
for(int n = 0; n < 10; n++) {
for(int j = 0; j < 15; j++) {
for(int k = 0; k < 10; k++) {
if(cons[n][j][k] == tempBitmap.getPixel(k, j))
num_count++;
}
}
double result = (double)num_count/procons[n]*100;
if(result > 100) result = 100;
if(result > max) {
max = result;
num = n;
}
num_count=0;
}
}
// 모음
else if(i==3) {
for(int n = 0; n < 4; n++) {
for(int j = 0; j < 15; j++) {
for(int k = 0; k < 10; k++) {
if(vocs[n][j][k] == tempBitmap.getPixel(k, j))
num_count++;
}
}
double result = (double)num_count/provocs[n]*100;
if(result > 100) result = 100;
if(result > max) {
max = result;
num = n;
}
num_count=0;
}
}
// 숫자
else {
for(int n = 0; n < 10; n++) {
for(int j = 0; j < 15; j++) {
for(int k = 0; k < 10; k++) {
if(nums[n][j][k] == tempBitmap.getPixel(k, j))
num_count++;
}
}
double result = (double)num_count/pronums[n]*100;
if(result > 100) result = 100;
if(result > max) {
max = result;
num = n;
}
num_count=0;
}
}
avg+=max;
String floatnum = String.format("%.2f", max);
// 자음
if(i==2) {
// 중략
}
// 모음
else if(i==3) {
// 중략
}
// 숫자
else {
textViewResult.append(i + "번째 분석 결과 : " + num + " / 정확도 : " + floatnum +"%\n");
result += Integer.toString(num);
}
}
}
else {
Toast.makeText(context, "숫자 생성 실패", Toast.LENGTH_SHORT).show();
}
Utils.matToBitmap(matROI, roi2);
imageViewROI = (ImageView)findViewById(R.id.image_result_ROI);
imageViewROI.setImageBitmap(roi2);
String resultnum = String.format("%.2f", avg/count);
textViewResult.append("\n\n분석 결과 : " + result + " / 정확도 : " + resultnum + "%");
}
중간에 문자 비교 코드는 너무 길어서 중략 처리했습니다.
다음은 미리 저장해둔 문자 템플릿입니다.
nums = new int[10][15][10];
pronums = new int[10];
cons = new int[10][15][10];
procons = new int[10];
vocs = new int[4][15][10];
provocs = new int[4];
ones = new int[10][15][10];
proones = new int[10];
// 픽셀 개수
pronums[0] = 50;
pronums[1] = 40;
pronums[2] = 40;
pronums[3] = 45;
pronums[4] = 50;
pronums[5] = 55;
pronums[6] = 50;
pronums[7] = 37;
pronums[8] = 50;
pronums[9] = 40;
// 0
nums[0][0][3] = -1; nums[0][0][4] = -1; nums[0][0][5] = -1; nums[0][0][6] = -1;
nums[0][1][2] = -1; nums[0][1][3] = -1; nums[0][1][6] = -1; nums[0][1][7] = -1;
nums[0][2][0] = -1; nums[0][2][1] = -1; nums[0][2][8] = -1; nums[0][2][9] = -1;
nums[0][3][0] = -1; nums[0][3][1] = -1; nums[0][3][8] = -1; nums[0][3][9] = -1;
nums[0][4][0] = -1; nums[0][4][1] = -1; nums[0][4][8] = -1; nums[0][4][9] = -1;
nums[0][5][0] = -1; nums[0][5][1] = -1; nums[0][5][8] = -1; nums[0][5][9] = -1;
nums[0][6][0] = -1; nums[0][6][1] = -1; nums[0][6][8] = -1; nums[0][6][9] = -1;
nums[0][7][0] = -1; nums[0][7][1] = -1; nums[0][7][8] = -1; nums[0][7][9] = -1;
nums[0][8][0] = -1; nums[0][8][1] = -1; nums[0][8][8] = -1; nums[0][8][9] = -1;
nums[0][9][0] = -1; nums[0][9][1] = -1; nums[0][9][8] = -1; nums[0][9][9] = -1;
nums[0][10][0] = -1; nums[0][10][1] = -1; nums[0][10][8] = -1; nums[0][10][9] = -1;
nums[0][11][0] = -1; nums[0][11][1] = -1; nums[0][11][8] = -1; nums[0][11][9] = -1;
nums[0][12][0] = -1; nums[0][12][1] = -1; nums[0][12][8] = -1; nums[0][12][9] = -1;
nums[0][13][2] = -1; nums[0][13][3] = -1; nums[0][13][6] = -1; nums[0][13][7] = -1;
nums[0][14][3] = -1; nums[0][14][4] = -1; nums[0][14][5] = -1; nums[0][14][6] = -1;
// 1
nums[1][0][7] = -1; nums[1][0][8] = -1;
nums[1][1][6] = -1; nums[1][1][7] = -1; nums[1][1][8] = -1;
nums[1][2][1] = -1; nums[1][2][2] = -1; nums[1][2][3] = -1; nums[1][2][4] = -1; nums[1][2][5] = -1; nums[1][2][6] = -1; nums[1][2][7] = -1; nums[1][2][8] = -1;
nums[1][3][0] = -1; nums[1][3][1] = -1; nums[1][3][2] = -1; nums[1][3][3] = -1; nums[1][3][4] = -1; nums[1][3][5] = -1; nums[1][3][6] = -1; nums[1][3][7] = -1; nums[1][3][8] = -1;
nums[1][4][6] = -1; nums[1][4][7] = -1; nums[1][4][8] = -1;
nums[1][5][7] = -1; nums[1][5][8] = -1;
nums[1][6][7] = -1; nums[1][6][8] = -1;
nums[1][7][7] = -1; nums[1][7][8] = -1;
nums[1][8][7] = -1; nums[1][8][8] = -1;
nums[1][9][7] = -1; nums[1][9][8] = -1;
nums[1][10][7] = -1; nums[1][10][8] = -1;
nums[1][11][7] = -1; nums[1][11][8] = -1;
nums[1][12][7] = -1; nums[1][12][8] = -1;
nums[1][13][7] = -1; nums[1][13][8] = -1;
nums[1][14][7] = -1; nums[1][14][8] = -1;
// 2
nums[2][0][3] = -1; nums[2][0][4] = -1;
nums[2][1][1] = -1; nums[2][1][2] = -1; nums[2][1][5] = -1; nums[2][1][6] = -1;
nums[2][2][0] = -1; nums[2][2][1] = -1; nums[2][2][7] = -1;
nums[2][3][0] = -1; nums[2][3][1] = -1; nums[2][3][7] = -1; nums[2][3][8] = -1;
nums[2][4][7] = -1; nums[2][4][8] = -1;
nums[2][5][7] = -1; nums[2][5][8] = -1;
nums[2][6][6] = -1; nums[2][6][7] = -1;
nums[2][7][6] = -1; nums[2][7][7] = -1;
nums[2][8][5] = -1; nums[2][8][6] = -1;
nums[2][9][4] = -1; nums[2][9][5] = -1;
nums[2][10][3] = -1; nums[2][10][4] = -1;
nums[2][11][3] = -1; nums[2][11][4] = -1;
nums[2][12][2] = -1; nums[2][12][3] = -1;
nums[2][13][1] = -1; nums[2][13][2] = -1; nums[2][13][3] = -1;
nums[2][14][1] = -1; nums[2][14][2] = -1; nums[2][14][3] = -1; nums[2][14][4] = -1; nums[2][14][5] = -1; nums[2][14][6] = -1; nums[2][14][7] = -1; nums[2][14][8] = -1; nums[2][14][9] = -1;
// 3
nums[3][0][2] = -1; nums[3][0][3] = -1; nums[3][0][4] = -1; nums[3][0][5] = -1; nums[3][0][6] = -1; nums[3][0][7] = -1; nums[3][0][8] = -1; nums[3][0][9] = -1;
nums[3][1][3] = -1; nums[3][1][4] = -1; nums[3][1][5] = -1; nums[3][1][6] = -1; nums[3][1][7] = -1; nums[3][1][8] = -1; nums[3][1][9] = -1;
nums[3][2][7] = -1; nums[3][2][8] = -1;
nums[3][3][6] = -1; nums[3][3][7] = -1;
nums[3][4][5] = -1; nums[3][4][6] = -1;
nums[3][5][4] = -1; nums[3][5][5] = -1; nums[3][5][6] = -1;
nums[3][6][5] = -1; nums[3][6][6] = -1; nums[3][6][7] = -1;
nums[3][7][7] = -1;
nums[3][8][7] = -1; nums[3][8][8] = -1;
nums[3][9][7] = -1; nums[3][9][8] = -1;
nums[3][10][0] = -1; nums[3][10][1] = -1; nums[3][10][7] = -1;
nums[3][11][0] = -1; nums[3][11][1] = -1; nums[3][11][7] = -1;
nums[3][12][0] = -1; nums[3][12][1] = -1; nums[3][12][6] = -1;
nums[3][13][1] = -1; nums[3][13][2] = -1; nums[3][13][3] = -1; nums[3][13][4] = -1; nums[3][13][5] = -1; nums[3][13][6] = -1;
nums[3][14][2] = -1; nums[3][14][3] = -1; nums[3][14][4] = -1;
// 4
nums[4][0][6] = -1; nums[4][0][7] = -1;
nums[4][1][6] = -1; nums[4][1][7] = -1;
nums[4][2][5] = -1; nums[4][2][6] = -1; nums[4][2][7] = -1;
nums[4][3][4] = -1; nums[4][3][5] = -1; nums[4][3][6] = -1; nums[4][3][7] = -1;
nums[4][4][3] = -1; nums[4][4][4] = -1; nums[4][4][6] = -1; nums[4][4][7] = -1;
nums[4][5][3] = -1; nums[4][5][6] = -1; nums[4][5][7] = -1;
nums[4][6][2] = -1; nums[4][6][3] = -1; nums[4][6][6] = -1; nums[4][6][7] = -1;
nums[4][7][2] = -1; nums[4][7][6] = -1; nums[4][7][7] = -1;
nums[4][8][1] = -1; nums[4][8][2] = -1; nums[4][8][6] = -1; nums[4][8][7] = -1;
nums[4][9][1] = -1; nums[4][9][6] = -1; nums[4][9][7] = -1;
nums[4][10][0] = -1; nums[4][10][1] = -1; nums[4][10][2] = -1; nums[4][10][3] = -1; nums[4][10][4] = -1; nums[4][10][5] = -1; nums[4][10][6] = -1; nums[4][10][7] = -1; nums[4][10][8] = -1; nums[4][10][9] = -1;
nums[4][11][0] = -1; nums[4][11][1] = -1; nums[4][11][2] = -1; nums[4][11][3] = -1; nums[4][11][4] = -1; nums[4][11][5] = -1; nums[4][11][6] = -1; nums[4][11][7] = -1; nums[4][11][8] = -1; nums[4][11][9] = -1;
nums[4][12][6] = -1; nums[4][12][7] = -1;
nums[4][13][6] = -1; nums[4][13][7] = -1;
nums[4][14][6] = -1; nums[4][14][7] = -1;
// 5
nums[5][0][2] = -1; nums[5][0][3] = -1; nums[5][0][4] = -1; nums[5][0][5] = -1; nums[5][0][6] = -1; nums[5][0][7] = -1; nums[5][0][8] = -1;
nums[5][1][1] = -1; nums[5][1][2] = -1; nums[5][1][3] = -1; nums[5][1][4] = -1; nums[5][1][5] = -1; nums[5][1][6] = -1; nums[5][1][7] = -1;
nums[5][2][1] = -1; nums[5][2][2] = -1;
nums[5][3][1] = -1; nums[5][3][2] = -1;
nums[5][4][1] = -1; nums[5][4][2] = -1;
nums[5][5][1] = -1; nums[5][5][2] = -1;
nums[5][6][1] = -1; nums[5][6][2] = -1; nums[5][6][3] = -1; nums[5][6][4] = -1; nums[5][6][5] = -1; nums[5][6][6] = -1; nums[5][6][7] = -1;
nums[5][7][1] = -1; nums[5][7][2] = -1; nums[5][7][3] = -1; nums[5][7][4] = -1; nums[5][7][5] = -1; nums[5][7][6] = -1; nums[5][7][7] = -1; nums[5][7][8] = -1;
nums[5][8][8] = -1; nums[5][8][9] = -1;
nums[5][9][8] = -1; nums[5][9][9] = -1;
nums[5][10][8] = -1; nums[5][10][9] = -1;
nums[5][11][0] = -1; nums[5][11][1] = -1; nums[5][11][8] = -1; nums[5][11][9] = -1;
nums[5][12][0] = -1; nums[5][12][1] = -1; nums[5][12][7] = -1; nums[5][12][8] = -1;
nums[5][13][1] = -1; nums[5][13][2] = -1; nums[5][13][3] = -1; nums[5][13][4] = -1; nums[5][13][5] = -1; nums[5][13][6] = -1; nums[5][13][7] = -1;
nums[5][14][2] = -1; nums[5][14][3] = -1; nums[5][14][4] = -1; nums[5][14][5] = -1; nums[5][14][6] = -1;
// 6
nums[6][0][6] = -1; nums[6][0][7] = -1;
nums[6][1][6] = -1;
nums[6][2][5] = -1; nums[6][2][6] = -1;
nums[6][3][4] = -1; nums[6][3][5] = -1;
nums[6][4][4] = -1;
nums[6][5][3] = -1; nums[6][5][4] = -1;
nums[6][6][2] = -1; nums[6][6][3] = -1; nums[6][6][4] = -1; nums[6][6][5] = -1; nums[6][6][6] = -1;
nums[6][7][2] = -1; nums[6][7][3] = -1; nums[6][7][4] = -1; nums[6][7][5] = -1; nums[6][7][6] = -1; nums[6][7][7] = -1; nums[6][7][8] = -1;
nums[6][8][1] = -1; nums[6][8][2] = -1; nums[6][8][7] = -1; nums[6][8][8] = -1;
nums[6][9][0] = -1; nums[6][9][1] = -1; nums[6][9][8] = -1; nums[6][9][9] = -1;
nums[6][10][0] = -1; nums[6][10][1] = -1; nums[6][10][8] = -1; nums[6][10][9] = -1;
nums[6][11][0] = -1; nums[6][11][1] = -1; nums[6][11][8] = -1; nums[6][11][9] = -1;
nums[6][12][0] = -1; nums[6][12][1] = -1; nums[6][12][2] = -1; nums[6][12][7] = -1; nums[6][12][8] = -1;
nums[6][13][1] = -1; nums[6][13][2] = -1; nums[6][13][3] = -1; nums[6][13][4] = -1; nums[6][13][5] = -1; nums[6][13][6] = -1; nums[6][13][7] = -1;
nums[6][14][3] = -1; nums[6][14][4] = -1; nums[6][14][5] = -1;
// 7
nums[7][0][0] = -1; nums[7][0][1] = -1; nums[7][0][2] = -1; nums[7][0][3] = -1; nums[7][0][4] = -1; nums[7][0][5] = -1; nums[7][0][6] = -1; nums[7][0][7] = -1; nums[7][0][8] = -1; nums[7][0][9] = -1;
nums[7][1][0] = -1; nums[7][1][1] = -1; nums[7][1][2] = -1; nums[7][1][6] = -1; nums[7][1][7] = -1; nums[7][1][8] = -1; nums[7][1][9] = -1;
nums[7][2][0] = -1; nums[7][2][1] = -1; nums[7][2][7] = -1; nums[7][2][8] = -1;
nums[7][3][7] = -1;
nums[7][4][7] = -1;
nums[7][5][6] = -1;
nums[7][6][5] = -1; nums[7][6][6] = -1;
nums[7][7][5] = -1;
nums[7][8][5] = -1;
nums[7][9][4] = -1; nums[7][9][5] = -1;
nums[7][10][4] = -1;
nums[7][11][3] = -1; nums[7][11][4] = -1;
nums[7][12][3] = -1;
nums[7][13][2] = -1; nums[7][13][3] = -1;
nums[7][14][2] = -1;
// 8
nums[8][0][4] = -1; nums[8][0][5] = -1;
nums[8][1][2] = -1; nums[8][1][3] = -1; nums[8][1][4] = -1; nums[8][1][5] = -1; nums[8][1][6] = -1; nums[8][1][7] = -1;
nums[8][2][1] = -1; nums[8][2][2] = -1; nums[8][2][7] = -1; nums[8][2][8] = -1;
nums[8][3][1] = -1; nums[8][3][8] = -1;
nums[8][4][0] = -1; nums[8][4][1] = -1; nums[8][4][8] = -1;
nums[8][5][1] = -1; nums[8][5][8] = -1;
nums[8][6][2] = -1; nums[8][6][3] = -1; nums[8][6][4] = -1; nums[8][6][5] = -1; nums[8][6][6] = -1; nums[8][6][7] = -1;
nums[8][7][2] = -1; nums[8][7][3] = -1; nums[8][7][4] = -1; nums[8][7][5] = -1; nums[8][7][6] = -1; nums[8][7][7] = -1;
nums[8][8][1] = -1; nums[8][8][2] = -1; nums[8][8][7] = -1; nums[8][8][8] = -1;
nums[8][9][0] = -1; nums[8][9][1] = -1; nums[8][9][8] = -1; nums[8][9][9] = -1;
nums[8][10][0] = -1; nums[8][10][1] = -1; nums[8][10][8] = -1; nums[8][10][9] = -1;
nums[8][11][0] = -1; nums[8][11][1] = -1; nums[8][11][8] = -1; nums[8][11][9] = -1;
nums[8][12][1] = -1; nums[8][12][2] = -1; nums[8][12][7] = -1; nums[8][12][8] = -1;
nums[8][13][1] = -1; nums[8][13][2] = -1; nums[8][13][3] = -1; nums[8][13][6] = -1; nums[8][13][7] = -1;
nums[8][14][3] = -1; nums[8][14][4] = -1; nums[8][14][5] = -1; nums[8][14][6] = -1;
// 9
nums[9][0][3] = -1; nums[9][0][4] = -1; nums[9][0][5] = -1;
nums[9][1][1] = -1; nums[9][1][2] = -1; nums[9][1][3] = -1; nums[9][1][4] = -1; nums[9][1][5] = -1; nums[9][1][6] = -1; nums[9][1][7] = -1;
nums[9][2][0] = -1; nums[9][2][1] = -1; nums[9][2][7] = -1; nums[9][2][8] = -1;
nums[9][3][0] = -1; nums[9][3][1] = -1; nums[9][3][7] = -1; nums[9][3][8] = -1;
nums[9][4][0] = -1; nums[9][4][1] = -1; nums[9][4][7] = -1; nums[9][4][8] = -1;
nums[9][5][1] = -1; nums[9][5][2] = -1; nums[9][5][8] = -1; nums[9][5][9] = -1;
nums[9][6][1] = -1; nums[9][6][2] = -1; nums[9][6][3] = -1; nums[9][6][8] = -1; nums[9][6][9] = -1;
nums[9][7][3] = -1; nums[9][7][4] = -1; nums[9][7][5] = -1; nums[9][7][6] = -1; nums[9][7][7] = -1; nums[9][7][8] = -1;
nums[9][8][5] = -1; nums[9][8][6] = -1; nums[9][8][7] = -1;
nums[9][9][6] = -1; nums[9][9][7] = -1;
nums[9][10][6] = -1;
nums[9][11][6] = -1; nums[9][11][7] = -1;
nums[9][12][5] = -1;
nums[9][13][4] = -1; nums[9][13][5] = -1;
// 자음 및 모음 중략...
이런식으로 3차원 배열에 이미지 템플릿(자음, 모음, 숫자)에 해당하는 픽셀값을 미리 설정해 두고 추출된 이미지와 1:1 비교해서 일치하는 값만큼 숫자를 증가시켜 그 숫자의 비율을 정확도로 칭하고 그 정확도가 가장 높은 숫자를 인식된 숫자라고 판별합니다.
다음은 실행 결과입니다.
프로그램 코드가 너무 긴 관계로 일부 코드를 생략했습니다. 무조건 복사 붙여넣기 한다고 실행 되지 않을것입니다. 프로그램 원리나 소스코드에 대해 궁금하신분은 댓글 또는 방명록에 남겨주시면 상세하게 답변해드리겠습니다.
공감♡ 버튼을 눌러주시면 더욱 유용하고 좋은 포스팅으로 찾아뵙겠습니다.
[관련 게시글]
2018/09/05 - [Language/Android] - 안드로이드 findContours 오류 해결
2018/09/03 - [Language/Android] - 안드로이드 OpenCV 관심영역(ROI) 추출
2018/09/03 - [Language/Android] - 안드로이드 OpenCV 설치
2018/08/29 - [Language/Android] - 안드로이드 핀치 줌 - 멀티 터치로 구현하기
2018/08/28 - [Language/Android] - 안드로이드 이미지 뷰 여백 없애기
2018/08/27 - [Language/Android] - 안드로이드 카메라 줌 제어
2018/08/25 - [Language/Android] - [안드로이드] 비트맵 이진화 처리
2018/08/24 - [Language/Android] - [안드로이드] 실시간 SurfaceView 화면 캡쳐하기
2018/08/21 - [Language/Android] - [Android] 안드로이드 내부 저장소 텍스트 파일 읽기 및 쓰기
2018/08/20 - [Language/Android] - [Android] 안드로이드 SurfaceView 카메라 연동하기
'Android' 카테고리의 다른 글
안드로이드 Activity class does not exist. 오류 해결법 (1) | 2018.09.18 |
---|---|
안드로이드 notification 간단한 사용법 (9) | 2018.09.17 |
안드로이드 FCM 푸시알림 예제 (8) | 2018.09.17 |
안드로이드 블루투스 연동 예제 소스 (71) | 2018.09.12 |
안드로이드 텍스트뷰 사용법 (0) | 2018.09.06 |
안드로이드 findContours 오류 해결 (0) | 2018.09.05 |
안드로이드 OpenCV 관심영역(ROI) 추출 (3) | 2018.09.03 |
안드로이드 OpenCV 설치 (2) | 2018.09.03 |