OpenCV

Visual Studio에서 OpenCV, Tesseract-OCR 사용해서 번호판 인식하고 출력하기

BigmacGood 2022. 3. 11. 17:01

사용 환경

Visual Studio 2022

OpenCV 4.5.4

Tesseract-OCR 5.0.1

 

OpenCV와 Tesseract를 사용해서 자동차 번호판을 인식하는 방법입니다.

 

OpenCV 설치 방법

2022.03.11 - [OpenCV] - Visual Studio에서 OpenCV 설치하기

Tesseract 설치 방법

2022.03.11 - [OpenCV] - Visual Studio에서 Tesseract-OCR 사용해보기

 

자세한 코드는 https://github.com/kangsunghyun111/Car-license-plate-recognition-using-tesseract-OCR 에 있습니다.

 

이미지 처리부터 출력까지의 과정을 크게 세 단계로 나눠 볼 수 있습니다.

 

1. 자동차 번호판의 위치 찾기

원본 이미지

 

이미지를 회색으로 바꿉니다.

    cvtColor(image2, image2, COLOR_BGR2GRAY);

 

이미지를 가우시안 블러 처리해줍니다. 이미지를 흐리게 만들어서 노이즈를 줄여줍니다.

    GaussianBlur(image2, image2, Size(5,5), 0);

 

이미지를 canny 처리해서 윤곽선만 남깁니다.

    Canny(image2, image2, 100, 300, 3);

 

윤곽선을 찾고 직사각형을 씌웁니다.

우리가 원하는 건 번호판 모양의 윤곽이므로 적당한 비율과 넓이를 설정해서 걸러냅니다.

    // Finding contours
    findContours(image2, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
    vector<vector<Point> > contours_poly(contours.size());
    vector<Rect> boundRect(contours.size());
    vector<Rect> boundRect2(contours.size());

    // Bind rectangle to every rectangle.
    for (int i = 0; i < contours.size(); i++) {
        approxPolyDP(Mat(contours[i]), contours_poly[i], 1, true);
        boundRect[i] = boundingRect(Mat(contours_poly[i]));
    }

    drawing = Mat::zeros(image2.size(), CV_8UC3);

    for (int i = 0; i < contours.size(); i++) {

        ratio = (double)boundRect[i].height / boundRect[i].width;

        // Filtering rectangles height/width ratio, and size.
        if ((ratio <= 2.5) && (ratio >= 0.5) && (boundRect[i].area() <= 700) && (boundRect[i].area() >= 100)) {

            drawContours(drawing, contours, i, Scalar(0, 255, 255), 1, 8, hierarchy, 0, Point());
            rectangle(drawing, boundRect[i].tl(), boundRect[i].br(), Scalar(255, 0, 0), 1, 8, 0);

            // Include only suitable rectangles.
            boundRect2[refinery_count] = boundRect[i];
            refinery_count += 1;
        }
    }

    boundRect2.resize(refinery_count);  //  Resize refinery rectangle array.

 

표시된 직사각형 중에 번호판만 남기고 나머지는 걸러냅니다.

 

2. 이미지 회전 및 번호판만 남기기

Tesseract-OCR의 인식률을 높이기 위해 번호판을 x축에 평행하도록 회전시킵니다.

    // Image processing is performed to increase the recognition rate of tesseract-OCR
    // The first is to rotate the tilted car plate straight
    Mat cropped_image;
    image.copyTo(cropped_image);
    Point center1 = (carNumber[0].tl() + carNumber[0].br()) * 0.5;  // Center of the first number
    Point center2 = (carNumber[carNumber.size()-1].tl() + carNumber[carNumber.size() - 1].br()) * 0.5;  // Center of the last number
    int plate_center_x = (int)(center1.x + center2.x) * 0.5;    // X-coordinate at the Center of car plate
    int plate_center_y = (int)(center1.y + center2.y) * 0.5;    // Y-coordinate at the Center of car plate

    // To calculate the height
    int sum_height=0;
    for (int i = 0; i < carNumber.size(); i++)
        sum_height += carNumber[i].height;

    plate_width = (-center1.x + center2.x + carNumber[carNumber.size() - 1].width) * 1.05;  // Car plate width with some paddings
    plate_height = (int)(sum_height / carNumber.size()) * 1.2;  // Car plate height with some paddings

    delta_x = center1.x - center2.x;
    delta_y = center1.y - center2.y;

    // Roatate car plate
    double angle_degree = (atan(delta_y / delta_x))*(double)(180/3.141592);
    
    Mat rotation_matrix = getRotationMatrix2D(Point(plate_center_x, plate_center_y), angle_degree, 1.0);
    warpAffine(cropped_image, cropped_image, rotation_matrix, Size(original_width, original_height));

 

그 다음 번호판의 중심 좌표와 폭, 높이를 이용해서 번호판만 추출합니다.

 

3. 결과물 인식하기

Tesseract api를 psm 7, oem 0 으로 설정해줍니다.

psm을 7로 설정하는 이유는 번호판이 한 줄로 이루어져있기 때문입니다.

    // Initialize tesseract-ocr with Korean, oem is 0
    if (api->Init("C:\\Program Files\\tesseract-OCR\\tessdata", "kor3",tesseract::OEM_TESSERACT_ONLY)) {
        fprintf(stderr, "Could not initialize tesseract.\n");
        exit(1);
    }

    // Set page segmentation mode to PSM_SINGLE_LINE(7), it assumes there is only one line
    api->SetPageSegMode(tesseract::PSM_SINGLE_LINE);

 

정규표현식을 사용해서 번호판 형식에 맞는 문자열을 출력합니다.

    // Extract "12가3456" or "123가4567"
    regex re("\\d{2,3}\\W{2}\\s{0,}\\d{4}");
    smatch match;
    if (regex_search(text, match, re)) {
        return match.str();
    }

 

결과

 

 

참고한 사이트

https://mind3002.blogspot.com/2016/01/cc-opencv-license-plates-recognition.html

 

[C/C++] OpenCV 라이브러리로, 윤곽에 기반한 자동차 번호판 영역 추출 (License plates recognition)

Download link : OpenCV_License plates recognition_console project (On Ubuntu linux, Qt)   5번째 게시물은 오픈소스 영상처리 라이브러리인 Op...

mind3002.blogspot.com

https://tesseract-ocr.github.io/tessdoc/ImproveQuality.html

 

Improving the quality of the output

Tesseract documentation

tesseract-ocr.github.io

https://opencv-python.readthedocs.io/en/latest/doc/09.imageThresholding/imageThresholding.html

 

이미지 임계처리 — gramman 0.1 documentation

기본 임계처리 이진화 처리는 간단하지만, 쉽지 않은 문제를 가지고 있다. 이진화란 영상을 흑/백으로 분류하여 처리하는 것을 말합니다. 이때 기준이 되는 임계값을 어떻게 결정할 것인지가 중

opencv-python.readthedocs.io

https://docs.opencv.org/2.4.9/modules/imgproc/doc/imgproc.html

 

imgproc. Image Processing — OpenCV 2.4.9.0 documentation

 

docs.opencv.org

https://maxtime1004.tistory.com/37?category=971805 

 

[Python] tesseract를 이용한 자동차 번호판 인식기 - 1

안녕하세요! 오늘은 tesseract를 이용하여 자동차 번호판을 인식하는 방법입니다. 저는 아래의 영상을 통해 도움을 얻었고 해당 영상에도 링크에 깃허브 주소가 있으니 참고하실 분들은 아래 링크

maxtime1004.tistory.com

https://jay1127.github.io/cpp/5-Use-Tesseract-API/

 

C++ : 5. Tesseract API 설치 및 사용법

Tesseract 설치

jay1127.github.io

 

기록용입니다.