주거지 번호 인식을 위한 SVM 기반 이미지 분류 모델 구현

SVM을 활용한 주소판 숫자 인식 시스템 개발

서포트 벡터 머신(SVM)은 지도 학습 방식의 대표적인 분류 알고리즘으로, 고차원 공간에서 데이터를 효과적으로 분리할 수 있는 결정 경계(하이퍼플레인)를 찾는 데 중점을 둔다. 특히 소규모에서 중간 규모의 복잡한 데이터셋에 강한 성능을 보이며, 과적합을 억제하는 능력 덕분에 이미지 인식 작업에 자주 사용된다.

SVM은 입력 데이터를 고차원 특징 공간으로 매핑한 후, 클래스 간 마진을 최대화하는 평면을 도출한다. 비선형 문제의 경우 커널 함수(kernel function)를 통해 암시적으로 차원을 확장하여 선형 분리를 가능하게 한다. 본 사례에서는 RBF(Radial Basis Function) 커널을 채택하여 다양한 밝기와 배경 조건의 숫자 이미지를 효과적으로 처리한다.

데이터셋 소개: mchar

mchar 데이터셋은 알리바바 클라우드 티안치(Tianchi) 플랫폼에서 제공하는 문자 인식용 오픈 데이터로, Google Street View House Numbers(SVHN)에서 파생되었다. 각 샘플은 아파트 현관문 또는 복도에 설치된 번호판 이미지와 그 안에 포함된 숫자들의 위치 및 레이블 정보(JSON 형식)로 구성된다.

JSON 메타데이터에는 다음 필드가 포함된다:

  • label: 인식 대상 숫자 (0~9)
  • left: ROI(Region of Interest) 왼쪽 가장자리 X 좌표
  • top: 상단 가장자리 Y 좌표
  • width: 영역 너비
  • height: 영역 높이

전처리 파이프라인 설계

정확한 분류를 위해서는 원본 이미지에서 노이즈를 제거하고 일관된 형식의 입력 데이터를 생성해야 한다. 아래는 전처리 단계별 절차이다.

1. ROI 기반 숫자 추출

Pillow 라이브러리를 사용해 JSON에 기록된 좌표를 기반으로 각 숫자 영역을 독립적으로 잘라낸다.

cropped_image = source_image.crop((left, top, left + width, top + height))

2. 정규화를 위한 리사이징

추출된 각 이미지를 16×16 픽셀 크기로 통일하여 모든 샘플이 동일한 특징 차원을 가지도록 변환한다. 이는 모델 입력의 일관성을 보장하며 계산 효율을 높인다.

NORMALIZED_SIZE = (16, 16)
resized_image = cropped_image.resize(NORMALIZED_SIZE, Image.NEAREST)

3. 적응형 이진화 처리

조명 조건이나 배경 색상의 다양성으로 인해 흑백 반전 문제가 발생할 수 있다. 이를 해결하기 위해 OTSU 알고리즘 기반의 자동 임계값 설정과 함께, 이미지 모서리 4점의 픽셀 값을 분석하여 필요 시 흑백 반전을 수행한다.

def apply_binary(pixel_matrix):
    _, binary = cv2.threshold(pixel_matrix, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    corner_sum = int(binary[0,0]) + int(binary[15,0]) + int(binary[0,15]) + int(binary[15,15])
    if corner_sum < 765:  # 대부분 검은색일 경우
        binary = 255 - binary
    return binary.astype(np.uint8).flatten()

차원 축소: PCA 기반 특징 최적화

각 이미지는 16×16=256개의 픽셀 값을 특징으로 가지며, 이는 다소 높은 차원이다. 주성분 분석(PCA)을 적용해 전체 분산의 95% 이상을 유지하면서 차원을 압축함으로써 학습 속도를 향상시키고 일반화 성능을 개선한다.

from sklearn.decomposition import PCA

def reduce_dimension(train_data, test_data):
    pca_model = PCA(n_components=0.95, random_state=42)
    train_reduced = pca_model.fit_transform(train_data)
    test_reduced = pca_model.transform(test_data)
    return train_reduced, test_reduced

모델 학습 및 하이퍼파라미터 튜닝

최적의 분류 성능을 달성하기 위해 정규화 계수 C를 탐색하고, 최종 모델을 학습하는 절차를 구현한다.

초기 파라미터 탐색

소규모 데이터셋을 기반으로 그리드 서치를 통해 최적의 C 값을 탐색한다. 이 값은 모델의 복잡도와 오분류 허용 정도를 조절한다.

from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

def find_optimal_c(features, labels):
    model = SVC(kernel='rbf')
    param_space = {'C': np.linspace(5, 20, 100), 'kernel': ['rbf']}
    searcher = GridSearchCV(model, param_space, cv=5, scoring='accuracy', n_jobs=-1)
    searcher.fit(features, labels)
    
    print(f"최적 C: {searcher.best_params_['C']:.3f}")
    print(f"검증 정확도: {searcher.best_score_:.4f}")
    
    return searcher.best_estimator_

최종 모델 훈련

탐색된 최적 파라미터를 바탕으로 전체 훈련 데이터에 대해 최종 모델을 학습시킨다.

# 예: C = 5.3으로 고정하여 재학습
final_classifier = SVC(C=5.3, kernel='rbf', gamma='scale')
final_classifier.fit(X_train_pca, y_train)
accuracy = final_classifier.score(X_test_pca, y_test)
print(f"테스트 정확도: {accuracy:.4f}")

실행 결과 요약

  • 훈련 데이터: 30,000개 샘플
  • 테스트 데이터: 7,500개 샘플
  • 전처리: 그레이스케일 → ROI 추출 → 16×16 리사이징 → 이진화 → PCA(95% variance 유지)
  • 모델: RBF 커널 SVM
  • 성능: 약 94% 이상의 정확도 기록

이 접근법은 비교적 간단한 구조임에도 불구하고 실세계 환경의 다양한 번호판 이미지에 대해 높은 인식률을 달성할 수 있음을 보여준다.

태그: SVM image-classification PCA python computer-vision

6월 18일 20:14에 게시됨