티스토리 뷰

이미지에서 글자를 추출해야 할 때, Tesseract OCR은 가장 많이 사용되는 오픈소스 라이브러리 중 하나입니다. 이번 포스팅에서는 Spring Boot와 Tesseract를 활용해 이미지에서 글자를 추출하는 방법을 알아보겠습니다. 전체소스는 github 를 참고해 주세요.


1. 특징

Tesseract는 강력한 오픈소스 OCR(Optical Character Recognition) 엔진으로 다양한 특징을 가지고 있습니다. 다음은 Tesseract의 주요 특징입니다.

  • 다국어 지원 : Tesseract는 약 100여 개의 언어를 기본으로 지원하며, 한국어, 영어, 일본어 등 다국어 OCR이 가능합니다.
  • 높은 정확도 : LSTM(Long Short-Term Memory) 신경망을 활용해 텍스트 인식 정확도를 크게 개선했습니다.
  • 오픈소스 : Apache License 2.0 하에 배포되어 상업적 용도로도 무료로 사용 가능합니다.
  • 플랫폼 독립적 : Windows, macOS, Linux 등에서 사용할 수 있으며, Java, Python 등 여러 프로그래밍 언어와도 연동 가능합니다.
  • 사용자 정의 훈련 가능 : 기존에 제공되는 traineddata 파일 외에, 사용자가 특정 언어 또는 글꼴에 맞게 학습 데이터를 만들어 추가할 수 있습니다.
  • 다양한 입력 파일 포맷 : JPG, PNG, WEBP, BMP, TIFF 등 대부분의 이미지 포맷을 지원합니다.
  • 커뮤니티 및 확장성 : 많은 개발자와 연구자들이 사용하고 있어, 문제 해결이나 확장 기능을 찾기 쉽습니다.
  • 제한점 : 배경이 복잡하거나 해상도가 낮은 이미지는 추가 전처리가 필요합니다.

2. 예제

2.1. lib 추가

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'net.sourceforge.tess4j:tess4j:5.13.0'

	annotationProcessor 'org.projectlombok:lombok'
	compileOnly 'org.projectlombok:lombok'

	testImplementation 'org.springframework.boot:spring-boot-starter-test'
	testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
  • tess4j 를 추가합니다. 가급적 최신 버전을 추천드립니다.

 

2.2. Controller

@RestController
@RequiredArgsConstructor
public class ApiController {

  private final OcrService ocrService;

  @PostMapping("/upload")
  public ResponseEntity<Map<String, String>> uploadFile(@RequestParam("image") MultipartFile image){
    try{
      return ResponseEntity.status(HttpStatus.OK).body(Map.of("text", ocrService.extractText(image)));
    }catch (Exception e){
      return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", "Failed to process image."));
    }
  }

}
  • 이미지 파일을 입력받아, Service 를 호출 후 그 결과를 문자열로 반환합니다.

 

2.3. Service

@Service
public class OcrService {

  // 글자 추출
  public String extractText(MultipartFile file) throws Exception {
    Tesseract tesseract = new Tesseract();
    tesseract.setDatapath("D:\\OCR\\tessdata"); // tessdata 경로 설정
    tesseract.setLanguage("kor+eng"); // 한글+영어[숫자는 자동]
    tesseract.setPageSegMode(6); // 6: 단락분석, 3: 완전한 페이지 분석, 1: 자동 레이아웃 감지

    File convFile = new File("D:\\OCR\\temp\\" + file.getOriginalFilename());
    file.transferTo(convFile);

    try {
      return tesseract.doOCR(convFile);
    } catch (TesseractException e) {
      throw new Exception("OCR Processing Failed", e);
    } finally {
      if (convFile.exists()) {
        convFile.delete();
      }
    }
  }
}
  • tessdata 경로를 지정하고 해당 경로에 아래 3개의 파일을 준비합니다.
chi_tra.traineddata
eng.traineddata
kor.traineddata

 

2.4. 화면

- index.html

<!DOCTYPE html>
<html lagn="ko" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image to Text Converter</title>
  <link th:href="@{/css/styles.css}" rel="stylesheet"/>
</head>
<body>
<div class="container">
  <h1>Image to Text Converter</h1>
  <input type="file" id="imageUpload" accept="image/*" />
  <button id="processImage">Extract Text</button>
  <div id="preview"></div>
  <textarea id="output" placeholder="Extracted text will appear here..." readonly></textarea>
</div>
<script th:src="@{/js/script.js}"></script>
</body>
</html>

- styles.css

.container {
  text-align: center;
  margin: 50px auto;
  max-width: 600px;
}

textarea {
  width: 100%;
  height: 150px;
  margin-top: 20px;
}

- script.js

document.getElementById('processImage').addEventListener('click', () => {
  const fileInput = document.getElementById('imageUpload');
  const file = fileInput.files[0];

  if (!file) {
    alert("Please select an image file.");
    return;
  }

  const formData = new FormData();
  formData.append('image', file);

  fetch('/upload', {
    method: 'POST',
    body: formData,
  })
    .then((response) => response.json())
    .then((data) => {
      document.getElementById('output').value = data.text || 'No text found!';
    })
    .catch((error) => console.error('Error:', error));
});

3. 실행

캡처 사진

  • 문자가 쓰여진 이미지를 준비하여 저장합니다.

  • 페이지를 열고 파일을 선택 후 "Extract Text" 버튼을 누릅니다.

  • 문자가 추출되는 모습을 확인할 수 있습니다.

 

감사합니다.

최근에 올라온 글
Total
Today
Yesterday