저번에 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 비교해서 일치하는 값만큼 숫자를 증가시켜 그 숫자의 비율을 정확도로 칭하고 그 정확도가 가장 높은 숫자를 인식된 숫자라고 판별합니다.


다음은 실행 결과입니다.





프로그램 코드가 너무 긴 관계로 일부 코드를 생략했습니다. 무조건 복사 붙여넣기 한다고 실행 되지 않을것입니다. 프로그램 원리나 소스코드에 대해 궁금하신분은 댓글 또는 방명록에 남겨주시면 상세하게 답변해드리겠습니다. 

공감♡ 버튼을 눌러주시면 더욱 유용하고 좋은 포스팅으로 찾아뵙겠습니다.







Comments

  1. KingKane 2018.11.19 21:31 Permalink Modify/Delete Reply

    문자비교는 어떤식으로 하나용?

    • 열코 2018.11.19 22:15 신고 Permalink Modify/Delete

      원글에 설명되어있습니다.
      미리 픽셀별로 배열을 생성하여
      blob 처리된 문자들과 1대1 대응하여
      비교하여 같은 픽셀(0또는 1)인 경우 비율을 계산하여 확률을 구하는것입니다.

  2. 현시창 2018.11.28 09:22 Permalink Modify/Delete Reply

    안녕하세요, 덕분에 OpenCV로 숫자 인식에 성공했습니다. 그런데 숫자 인식 순서가 뒤죽박죽으로 됩니다. (예: 206 -> 062)

    OpenCV에서 인식 영역 검출은 랜덤으로 검출되는 건지 궁금합니다.

    • 열코 2018.11.28 10:25 신고 Permalink Modify/Delete

      순서부분은 오름차순 정렬부분에서 수행합니다
      해당 코드부분을 디버깅해보시기바랍니다

  3. 콩코니 2019.03.18 21:23 Permalink Modify/Delete Reply

    안녕하세요, 덕분에 카메라 연동은 구현하였는데 문자인식부분이 어렵네요 실례지만 전체코드를 보여주실수있나요??
    혹시 괜찮으시면 아래 메일로 부탁드립니다. 정말 간절합니다 ㅠㅠ
    qmdch1@naver.com

  4. 박철우 2019.04.14 17:22 Permalink Modify/Delete Reply

    글 잘봤습니다.
    화폐인식프로그램을 짜고싶은데 참고많이 될거같은데 실례지만 전체소스 보고싶은데 부탁드려도될까요???
    cwp2126@gmail.com 메일로 부탁드립니다.

  5. 박세준 2019.04.16 09:53 Permalink Modify/Delete Reply

    안녕하세요 명함인식 어플리케이션을 만들어보고 싶은 학생입니다.
    실례지만 전체 코드 부탁드려도 괜찮을까요???
    kprc369@naver.com 메일 주소로 부탁드리겠습니다 감사합니다!!!

  6. 이지수 2019.04.21 04:36 Permalink Modify/Delete Reply

    안녕하세요, 글 잘 봤습니다 !
    이번에 한글 OCR 인식 애플리케이션을 만들어보고 싶은 학생입니다.
    Tesseract API를 사용하지 않고 만들어보고자 하는데 코드가 정말 도움이 될 것 같아서
    실례지만 전체 코드 부탁드려도 될까요...?
    honghong0715@naver.com 메일 주소로 부탁드립니다. 감사합니다!!

  7. 2019.05.02 16:45 Permalink Modify/Delete Reply

    죄송한데 프로젝트 때문에 그런데 소스코드좀 보내주시면안될까요 ㅜ
    seenhyeoknow@naver.com

  8. 이민호 2019.05.20 20:41 Permalink Modify/Delete Reply

    최근 안드로이드 화면인식 프로그램에 대해 공부를 시작한 학생입니다.
    관심 영역과 같이 보면서 공부하고 싶어서 전체코드가 너무나도 궁금해
    저도 부탁드리겠습니다.
    cloudhm7@naver.com

  9. 2019.05.25 19:36 Permalink Modify/Delete Reply

    안녕하세요. 이번에 자동차 번호판 인식 프로그램을 구상중인 학생입니다. 죄송한데 전체 소스코드좀 보내주실수있나요?
    jkp1230@naver.com

  10. 저기 2019.06.20 13:40 Permalink Modify/Delete Reply

    안녕하세요.
    공부하고 싶어서 그러는데.. 전체 소스코드좀 보내주실수있나요?
    hohx@naver.com

  11. 이해원 2019.06.24 17:38 Permalink Modify/Delete Reply

    공부하고싶습니다... 전체 소스코드를 보고 싶습니다..
    banner4@naver.com

  12. 나그네 2019.08.06 12:09 Permalink Modify/Delete Reply

    자체 스터디 중입니다. 소스 부탁드려도 될까요?
    도움이 많이 될 것 같습니다.

  13. 열공 2019.09.09 18:22 Permalink Modify/Delete Reply

    잘 봤어요~! 젤 쉽고 설명 잘되어있는것같아요.. 하지만 좀 헷갈리는게 있는데
    전체 소스 받을 수 있을까요?
    a388900@naver.com 로 부탁 드려요.....

  14. 아지 2019.10.02 16:21 Permalink Modify/Delete Reply

    안드로이드 Opencv를 검색하다 보게 되었읍니다.
    전체 source를 받을 수 있을까요?
    czdog@naver.com
    감사합니다.

  15. 팔룻 2019.10.18 10:05 Permalink Modify/Delete Reply

    안드로이드 ocr 공부하다 막혀서 그런데 혹시 소스코드 보내주실수 있나요..?ㅜㅜ
    pil123696@gmail.com 으로 보내주시면 감사하겟습니당

Leave a Comment


to Top