컴퓨터 비전

OCR

인공지능파이썬 2025. 3. 6. 16:24

#### OCR 파트 ###
8. OCR
* OCR(Optical Character Recognition, 광학 문자 인식) 는 이미지나 문서에서 문자를 식별하고 디지털 텍스트로 변환하는 기술입니다. 
* OCR은 주로 스캔된 문서, 사진 속 글자, 번호판, 손글씨 등의 텍스트를 자동으로 인식하는 데 사용됩니다. 
* 기본적인 OCR 방식은 이미지 전처리(그레이스케일 변환, 이진화, 노이즈 제거) 후 문자 영역을 감지하고, 문자 패턴을 데이터베이스와 비교하여 최적의 텍스트를 추출하는 과정으로 이루어집니다. 
* OpenCV와 Tesseract OCR을 사용하면 Python에서 쉽게 구현할 수 있으며, 딥러닝 기반의 EasyOCR, PaddleOCR, Google Vision OCR 등을 활용하면 한글과 다양한 언어의 인식률을 더욱 높일 수 있습니다. 
* OCR은 문서 자동화, 차량 번호판 인식(LPR), CAPTCHA 해독, 서류 디지털화 등 다양한 분야에서 활용됩니다.

9. Tesseract OCR
* Tesseract OCR 는 Google이 개발한 오픈소스 광학 문자 인식(Optical Character Recognition, OCR) 엔진으로, 다양한 언어를 지원하며 높은 정확도의 문자 인식을 제공합니다. 
* Tesseract는 기본적으로 LSTM(Long Short-Term Memory) 기반의 딥러닝 OCR 모델을 포함하고 있으며, tesseract-ocr 엔진과 함께 pytesseract 라이브러리를 사용하면 Python에서도 쉽게 적용할 수 있습니다. 
* Tesseract는 문서 디지털화, 자동차 번호판 인식, CAPTCHA 해독, 자동화 문서 처리 등 다양한 분야에서 활용됩니다.
 참고 링크 주소 : https://github.com/UB-Mannheim/tesseract/wiki

Home

Tesseract Open Source OCR Engine (main repository) - UB-Mannheim/tesseract

github.com

테러렉트 ocr 설치방법 참고 링크: https://naver.me/5Ghq8roY

😃테서렉트 OCR 설치 후 환경변수도 등록합니다😃
 ※윈도우는 테서렉트 OCR 환경변수 등록 후 터미널을 반드시 재실행해야함

10. EasyOCR
* EasyOCR는 딥러닝 기반의 광학 문자 인식(OCR) 라이브러리로, 여러 언어를 지원하며 이미지에서 텍스트를 빠르고 정확하게 추출할 수 있습니다. 
* PyTorch를 기반으로 하여 동작하며, 사전 학습된 모델을 활용해 다양한 글꼴과 크기의 문자를 인식할 수 있습니다. 
* 특히 번호판, 문서 스캔, 표지판 등의 텍스트를 감지하는 데 유용하며, OpenCV와 함께 사용하여 전처리 과정을 최적화하면 인식 정확도를 더욱 향상시킬 수 있습니다. 
* EasyOCR의 핵심 기능은 readtext() 함수를 사용하여 이미지에서 텍스트를 감지하고, 바운딩 박스와 신뢰도를 함께 제공하는 것입니다.
 
※팁!! EasyOCR를 사용할 때 OpenCV 에러(imshow) 발생시
pip uninstall opencv-python-headless
pip install opencv-python

만약 opencv가 다시 설치되지 않는 경우
pip install --upgrade --force-reinstall opencv-python
 

images (2).zip
0.48MB

 
압축을 풀어서 사용하시면 됩니다~~^^
 
예시 1)

import cv2
import numpy as np

# 이미지를 흑백(Grayscale)으로 불러옴
img = cv2.imread('./images/morph.jpg', cv2.IMREAD_GRAYSCALE)

# 구조화 요소(Structuring Element) 생성
# MORPH_RECT: 사각형 모양의 커널을 생성 (5x5 크기)
gse = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

# 팽창 연산 (Dilation) 적용
# 흰색 영역(밝은 영역)이 확대되며, 작은 구멍이나 노이즈를 채우는 효과가 있음
dst1 = cv2.dilate(img, gse)

# 침식 연산 (Erosion) 적용
# 검은색 영역(어두운 영역)이 확대되며, 작은 흰색 노이즈가 제거되는 효과가 있음
dst2 = cv2.erode(img, gse)

# 원본 이미지 출력
cv2.imshow('img', img)

# 팽창된 이미지 출력
cv2.imshow('dst1', dst1)

# 침식된 이미지 출력
cv2.imshow('dst2', dst2)

cv2.waitKey()

--->

 
예시 2)

import cv2
import random

# 이미지를 흑백(Grayscale)으로 불러옴
img = cv2.imread('./images/contours.bmp', cv2.IMREAD_GRAYSCALE)

# findContours : 외곽선 검출
# findContours(이미지, 검색 모드, 근사화 방법)
# RETR_CCOMP : 외곽선 계층을 두 개의 레벨(연속 외곽선과 내부 구멍)으로 구분하여 찾음
# CHAIN_APPROX_NONE : 모든 좌표를 생략하지 않음 (외곽선을 구성하는 모든 점을 반환)
contours, hierachy = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)

# 검출된 외곽선 정보 출력 (리스트 형태)
print(contours)

# 외곽선 계층 정보 출력 (각 외곽선의 부모-자식 관계를 포함한 계층 구조)
print(hierachy)

# 흑백 이미지를 BGR 컬러 이미지로 변환 (외곽선을 색상으로 표시하기 위함)
dst = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)

# 랜덤한 색상 생성 (BGR 형식, 각각 0~255 사이의 값을 가짐)
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
print(color)

# drawContours : 외곽선 그리기
# drawContours(이미지, 외곽선 리스트, 인덱스, 색상, 선 두께)
# 인덱스 : -1일 경우 모든 외곽선을 그림 (개별 외곽선을 선택하려면 특정 인덱스를 사용)
cv2.drawContours(dst, contours, -1, color, 3)

# 원본 이미지 출력
cv2.imshow('img', img)

# 외곽선이 그려진 이미지 출력
cv2.imshow('dst', dst)

# 키 입력 대기
cv2.waitKey()

--->

 
예시 3)

import cv2
import pytesseract

# 이미지를 BGR 형식으로 불러옴 (OpenCV는 기본적으로 BGR 형식 사용)
img = cv2.imread('./images/hello.png')

# OpenCV의 기본 색상 순서는 BGR이므로, Tesseract에서 인식할 수 있도록 RGB로 변환
dst = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 이미지 파일을 텍스트로 변환하여 출력
# lang='kor+eng' : 한글과 영어를 동시에 인식 (한글만 원하면 'kor', 영어만 원하면 'eng' 설정 가능)
text = pytesseract.image_to_string(dst, lang='kor+eng')

# 추출된 텍스트 출력
print(text)
--->
안녕하세요 OCR
Hello OCR

 
예시 4)

import cv2
import easyocr

# EasyOCR 객체 생성 (한글 인식 가능하도록 설정)
ocr_reader = easyocr.Reader(['ko'])

# OCR을 수행할 이미지 파일 리스트
image_file_paths = ['./images/test1.jpg', './images/test2.jpg', './images/test3.jpg',
                    './images/test4.jpg', './images/test5.jpg']

# 이미지 리스트를 하나씩 처리
for image_path in image_file_paths:
    print(f"Processing {image_path}")  # 현재 처리 중인 이미지 경로 출력
    
    # 이미지 읽기
    input_image = cv2.imread(image_path)
    
    # 이미지가 정상적으로 불러와졌는지 확인 (없으면 다음 이미지로 넘어감)
    if input_image is None:
        print(f"이미지를 불러올 수 없습니다: {image_path}")
        continue

    # 그레이스케일 변환 (컬러 이미지를 흑백으로 변환, OCR 성능 향상을 위해)
    gray_image = cv2.cvtColor(input_image, cv2.COLOR_BGR2GRAY)
    
    # Bilateral 필터 적용 (노이즈 제거하면서도 가장자리를 유지하는 필터)
    denoised_image = cv2.bilateralFilter(gray_image, 9, 75, 75)
    
    # Otsu 이진화 적용 (자동으로 최적의 임계값을 찾아 흑백 이미지로 변환)
    _, binary_image = cv2.threshold(denoised_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # Canny 엣지 검출 적용 (번호판과 같은 강한 윤곽선을 찾아냄)
    edges = cv2.Canny(binary_image, 50, 150)
    
    # OCR을 원본 이미지와 전처리된 이미지에서 수행하여 비교
    ocr_images = [input_image, binary_image, edges]  # 원본, 이진화 이미지, 엣지 이미지
    detected_license_plates = {}  # OCR 결과를 저장할 딕셔너리
    
    # OCR을 각각의 이미지에서 수행
    for ocr_img in ocr_images:
        detected_texts = ocr_reader.readtext(ocr_img)  # OCR 실행
        
        for (bbox, text, prob) in detected_texts:  # OCR 결과에서 바운딩 박스, 텍스트, 신뢰도 가져오기
            # 번호판일 가능성이 높은 텍스트만 필터링 (7자 이상이고 숫자를 포함하는 경우)
            if len(text) >= 7 and any(char.isdigit() for char in text):  
                
                # OCR이 반환한 바운딩 박스 좌표 (왼쪽 위, 오른쪽 위, 오른쪽 아래, 왼쪽 아래)
                (tl, tr, br, bl) = bbox
                tl, tr, br, bl = tuple(map(tuple, [tl, tr, br, bl]))  # 리스트를 튜플로 변환
                
                # 바운딩 박스 크기 계산
                width = br[0] - tl[0]
                height = br[1] - tl[1]
                
                # 가로세로 비율 계산 (일반적인 차량 번호판은 가로가 세로보다 2~5배 정도 길다)
                aspect_ratio = width / height if height > 0 else 0
                
                # 가로/세로 비율이 너무 크거나 작으면 번호판이 아닐 가능성이 높으므로 제외
                if 2.0 <= aspect_ratio <= 5.0:
                    # 동일한 텍스트가 여러 번 감지된 경우, 신뢰도가 더 높은 것을 선택
                    if text not in detected_license_plates or detected_license_plates[text][1] < prob:
                        detected_license_plates[text] = (bbox, prob)
    
    # 감지된 번호판 중 신뢰도가 가장 높은 것 선택하여 시각화
    if detected_license_plates:
        best_text = max(detected_license_plates, key=lambda x: detected_license_plates[x][1])
        best_bbox, best_prob = detected_license_plates[best_text]
        
        # OCR이 반환한 바운딩 박스를 정수형으로 변환
        (tl, tr, br, bl) = best_bbox
        tl = tuple(map(int, tl))
        br = tuple(map(int, br))

        # 번호판 위치에 초록색 사각형 그리기
        cv2.rectangle(input_image, tl, br, (0, 255, 0), 2)

        # 감지된 번호판 텍스트를 이미지 위에 표시
        cv2.putText(input_image, best_text, (tl[0], tl[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)

        print(f"감지된 번호판: {best_text} (신뢰도: {best_prob:.2f})")
    else:
        print("감지된 번호판이 없습니다.")
    
    # 최종 결과 이미지 출력
    cv2.imshow('Detected License Plates', input_image)
    cv2.waitKey() 
    print()

-->
Processing ./images/test1.jpg
감지된 번호판: 99845006 (신뢰도: 0.99)

Processing ./images/test2.jpg
감지된 번호판: 154러 7070 (신뢰도: 0.90)

Processing ./images/test3.jpg
감지된 번호판: 157고4895 (신뢰도: 0.75)

Processing ./images/test5.jpg
감지된 번호판: 403수 7975' (신뢰도: 0.29)

 
--->

1.jpg
2.jpg
3.jpg

 
 

728x90
LIST

'컴퓨터 비전' 카테고리의 다른 글

이안류 CCTV 데이터셋  (0) 2025.03.11
Object Detection  (2) 2025.03.07
4-(2). OpenCV  (0) 2025.03.05
4. OpenCV  (0) 2025.03.05
3. 포켓몬 분류 데이터셋  (8) 2025.03.04