springboot

Google Cloud API [OCR] 구현

shinminkyoung 2025. 3. 18. 22:22

 

구글 공식 문서를 이용해 구현

https://cloud.google.com/vision/docs/ocr?hl=ko

 

이미지의 텍스트 감지  |  Cloud Vision API  |  Google Cloud

의견 보내기 이미지의 텍스트 감지 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 스캔된 문서에서 텍스트를 감지하는 경우 광학 문자 인식, 구조화된 양식

cloud.google.com

 

로컬 이미지 분석 vs. 원격 이미지 분석

사용자가 사진을 찍으면, 사진 안에 있는 텍스트를 읽어들여 다음 화면에서 보여주면 되는 거라, 로컬 이미지 텍스트 감지 방법을 선택

 

를 하려다가, 문서화된 글씨가 아닌 손글씨를 분석해야할 때 더 적합한 API를 사용하기로 했다.

 

https://cloud.google.com/vision/docs/handwriting?hl=ko

 

이미지의 필기 입력 감지  |  Cloud Vision API  |  Google Cloud

의견 보내기 이미지의 필기 입력 감지 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 참고: 이 API를 휴대기기 앱에서 사용하는 경우 Firebase 머신러닝 및 ML Ki

cloud.google.com

 

1. Google Cloud Vision API 신청 & 설정

https://cloud.google.com/gcp?hl=ko

 

https://cloud.google.com/gcp?hl=ko

 

cloud.google.com

여기서 신청

(이전에 사용한 경험이 있어, 이미 가입된 상태라 과정 생략)

 

 

2. VISION API 설정 (OCR)

https://console.cloud.google.com/projectselector2/home/dashboard?hl=ko&inv=1&invt=AbsVNg

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

API 관련 설정 

 

서비스 계정까지 설정 완료

 

 

 

json 값으로 키 발급

 

여기서 결제 정보 등록까지 마쳐야 한다.

이걸 안 해서 500에러 2시간 동안 봤다..

 

3. resources/~ . json 파일 추가

 

이는 .gitignore로 빼서 관리 (그렇지 않으면 git push 조차 안 됨)

 

4. yml 설정 추가

ocr:
  api:
    provider: google
    key-file: src/main/resources/ocr/service-key.json

 

배포 시 환경 변수 설정 추가 필요

 

5.  Controller 및 Service 코드

package com.weve.controller;

import com.weve.common.api.payload.BasicResponse;
import com.weve.domain.User;
import com.weve.service.ImageService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.support.CustomSQLErrorCodesTranslation;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;


@RestController
@RequestMapping("/api/image")
@RequiredArgsConstructor
@Tag(name = "OCR", description = "OCR 관련 API입니다.")
public class ImageController {

    private final ImageService imageService;

    @PostMapping
    public BasicResponse<String> postOcrText(@AuthenticationPrincipal UserDetails userDetails, @RequestParam("imageFile") MultipartFile imageFile) throws IOException {

        String username = userDetails.getUsername();
        return imageService.postOcrTextByFile(username, imageFile);
    }
}
package com.weve.service;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.vision.v1.*;
import com.google.protobuf.ByteString;
import com.weve.common.api.payload.BasicResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

@Slf4j
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ImageService {

    private final ResourceLoader resourceLoader;

    @Value("${ocr.api.key-file}")
    private String ocrKeyFilePath;

    public BasicResponse<String> postOcrTextByFile(String username, MultipartFile imageFile) throws IOException {

        // 예외처리 추가
        try (ImageAnnotatorClient vision = createVisionClient()) {
            ByteString imgBytes = ByteString.readFrom(imageFile.getInputStream());
            Image image = Image.newBuilder().setContent(imgBytes).build();
            return analyzeImage(vision, image);
        }
    }

    // OCR 분석 로직
    private BasicResponse<String> analyzeImage(ImageAnnotatorClient vision, Image image) {
        AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
                .addFeatures(Feature.newBuilder().setType(Feature.Type.TEXT_DETECTION))
                .setImage(image)
                .build();

        BatchAnnotateImagesResponse response = vision.batchAnnotateImages(List.of(request));
        String extractedText = response.getResponses(0).getTextAnnotations(0).getDescription();

        return BasicResponse.onSuccess(extractedText);
    }

    // API 클라이언트
    private ImageAnnotatorClient createVisionClient() throws IOException {
        Resource resource = resourceLoader.getResource("file:" + ocrKeyFilePath);
        FileInputStream credentialsStream = new FileInputStream(resource.getFile());
        GoogleCredentials credentials = GoogleCredentials.fromStream(credentialsStream);
        return ImageAnnotatorClient.create(ImageAnnotatorSettings.newBuilder()
                .setCredentialsProvider(() -> credentials)
                .build());
    }
}

 

 

결과

분석한 이미지

 

분석 결과

 

 

정확도 엄청 높다.. 재밌다 8ㅇ8 !!