10-구글 색상 추출 API

jje·2026년 2월 21일

개인 프로젝트

목록 보기
10/18

색상 추출 API 후보군

  1. Google Cloud Vision API
    구글의 머신러닝 기술을 활용함
    화면 구성을 지배하는 색상을 찾아냄
    분석이 정교함 (픽셀 밀도까지 추출)
    RGB 값 제공
    객체 탐지, 문자 인식 기능 탑재
  2. Imagga API
    사람이 이해하기 쉬운 색상 이름을 매칭 (Red, Green, Blue)
    배경색상과 피사체 색상 구분
    추출도나 색상으로 비슷한 색감 이미지 분류 가능
  3. Cloudinary
    이미지 업로드 시 부가적인 색상 정보 추가
    클라우드에 올리면서 동시에 색상 정보 추출 가능
    이미지에서 가장 두드러지는 색상을 모아 대표팔레트 자동 생성
    API 호출 한번으로 이미지 URL 관리 및 색상분석 가능
  4. Color Thief
    자바 스크립트에서 실행 (API 보다는 도구)
    서버통신 없이 웹 브라우저에서 바로 색상 팔레트 계산
    지배적인 색 + 보조색 추출에 특화
    오픈소스

네가지의 서비스가 각각 특색이 있어서 어떤걸 선택해야할지 고민이다
사용한다면 1번, 아니면 2번이 아닐까 싶은데

피사체 색상 구분은 할 필요가 없을 것 같다
그림의 전체적인 색감, 즉 지배적인 색으로 크게크게 분류를 할 예정이기 때문에

그리고 Imagga API 에서 제공해주는 이름들이 굉장히 다채로운데
나는 Red, Orange, Yellow 이런 포괄적인 이름만 사용할 예정이다
스카이블루, 레몬그린 뭐 이런 세세한 이름까지는 필요하지 않다는 뜻이다

Google Cloud Vision API 쓰기로 함


그럼 이미지를 RGB 값으로 분류하려면?
DB에서 컬러 아카이브 테이블을 만들고
각 컬럼을 색상 이름으로 만들어서 RGB 값 범위를 정해주고
추출된 이미지의 RGB 값을 확인한 후
범위에 들어가는 색상 DB에 넣어주면 되지 않을까?


1. Google Cloud 설정하기 (준비 단계)

코드를 짜기 전에 먼저 구글 클라우드 콘솔에서 API를 활성화

  • 프로젝트 생성: Google Cloud Console에 접속해서 새 프로젝트 생성

  • API 활성화: 'API 및 서비스' 메뉴에서 Cloud Vision API를 찾아 '사용' 버튼 클릭
    라이브러리 목록 눌러서 머신러닝 탭 쪽에 가면 있다

  • 사용자 인증 정보: '사용자 인증 정보' 메뉴에서 서비스 계정(Service Account)을 생성하고, JSON 키를 다운로드(이 파일이 있어야 서버에서 구글 서버로 접근할 수 있음)

JSON 키 파일 다운로드 방법 (Step-by-Step) 

서비스 계정 목록 확인:

현재 화면(서비스 계정 만들기)에서 하단의 [완료] 버튼을 눌러 목록으로 나갑니다.

방금 만든 서비스 계정(예: docentnote@...)의 이메일 주소를 클릭하여 상세 페이지로 들어갑니다.

키 메뉴 이동:

상단에 있는 탭 메뉴 중에서 [키 (Keys)] 탭을 클릭합니다. 🖱️

키 추가 실행:

[키 추가] 버튼을 누르고, **[새 키 만들기]**를 선택합니다.

파일 형식 선택:

키 유형 중에서 JSON이 선택되어 있는지 확인하고 **[만들기]**를 누릅니다. 

자동 다운로드:

클릭과 동시에 브라우저를 통해 .json 확장자로 된 파일이 내 컴퓨터에 저장됩니다. 

주의: 이 파일은 한 번만 다운로드할 수 있으니 안전한 곳에 잘 보관하세요.

구글 api 쓴다고 하니까 제미나이가 정말 친절하게 알려주고 있다..
  • 환경 변수 설정: 다운로드한 JSON 파일 경로를 시스템 환경 변수에 등록
    구글은 보안이 중요하기 때문에 코드나 설정 파일에 직접 키를 입력하는 방식이 아닌 시스템 환경변수로 등록시킨다
    GOOGLE_APPLICATION_CREDENTIALS="C:\경로\내-키-파일.json"

1. JSON 키 파일 경로 확인

먼저, 다운로드받은 .json 파일이 어디에 있는지 확인

  • 예: C:\jje_works\google-key.json
  • : 파일 경로에 한글이 없는 곳에 두는 것이 가장 안전하다

2. 환경 변수 설정 창 열기

  1. 키보드에서 Win + S (검색)를 누르고 "시스템 환경 변수 편집"이라고 입력한 뒤 엔터
  2. 작은 창이 뜨면 하단에 있는 [환경 변수(N)...] 버튼을 클릭해서 확인

3. 변수 추가하기

이제 구글이 정해준 규칙대로 이름을 적는다

  1. 위쪽의 '사용자 변수' 또는 아래쪽의 '시스템 변수' 영역에서 [새로 만들기(W)...] 클릭
  2. 아래 내용을 그대로 입력해서 설정
  • 변수 이름: GOOGLE_APPLICATION_CREDENTIALS (모두 대문자)
  • 변수 값: 아까 확인한 JSON 키 파일의 전체 경로를 입력
  • : [파일 찾아보기...] 버튼을 눌러서 파일을 직접 선택하면 오타 없이 가져올 수 있음
  1. 확인 버튼을 계속 눌러서 모든 창을 저장하고 닫기

4. 적용 확인하기

  1. Win + R을 누르고 cmd라고 입력해서 명령 프롬프트를 열기
  2. 창에 echo %GOOGLE_APPLICATION_CREDENTIALS% 라고 입력하고 엔터
  3. 방금 입력한 파일 경로가 화면에 나타나면 성공

요약 및 주의사항

  • 변수 이름: 반드시 GOOGLE_APPLICATION_CREDENTIALS설정해야 구글 라이브러리가 자동으로 인식
  • 재시작: 환경 변수를 바꾼 후에는 인텔리제이(IntelliJ)나 이클립스를 껐다가 다시 켜야 바뀐 설정이 적용
  • 파일 관리: JSON 키 파일은 절대 지우거나 위치를 옮기지 않도록 주의해서 저장

여기까지 문제없이 성공이 됐다
파일 경로도 제대로 나오고


2. 의존성(Dependency) 추가

스프링 부트의 pom.xml 파일에 Google Cloud Vision 라이브러리를 추가

<dependency>
    <<groupId>com.google.cloud</groupId>
    <artifactId>google-cloud-vision</artifactId>
    <version>3.22.0</version> </dependency>

이 사이에 DB에 미술사조 데이터 전부, 아르누보 화가 목록, 아르누보 폴더에 있는 화가의 그림, 색상 관련 데이터를 넣었다

api가 추출해주는 데이터에 맞게 각 색상마다 가지는 RGB 값 수치를 설정

로직의 흐름은

리액트: 사용자가 '초록(Green)' 카테고리를 클릭했으니까
/api/archive/color/Green으로 데이터를 달라

스프링 (Controller): colorName이 'Green' 인 요청이 왔네네?

스프링 (Service/Mapper): 서비스에서 색상분석 로직을 수행함
archiveColor 테이블에서 'Green'의 RGB 범위를 가져옴
painting_color_map 테이블에서 그 범위 안에 들어가는 paintingId를 찾음
그 ID에 해당하는 그림 정보(Painting)를 모두 모아서 리턴

리액트: 받은 JSON 데이터를 화면에 보여줌


다음엔 아카이브 관련 테이블이랑
아카이브 관련 컨트롤러-매퍼 라인을 쭉 만들어줬다
여기부터는 jsp 말고 리액트로 보낼거라 jsp 는 만들지 않았다


전체 목록만 구현하는 과정 정리

1. 데이터 분석 및 서버 로직 구축 (Back-end)

  • 구글 비전 API 연동: ColorAnalysisService를 생성해 이미지의 주요 RGB 값을 추출하는 로직 설계
  • 색상 분류 로직: 추출된 RGB 값을 11가지 표준 색상 범위(archiveColor 테이블)와 대조해 가장 적절한 색상 ID를 매칭하는 findMatchColorId 기능을 구현
  • 일괄 분석 컨트롤러: /api/archive/analyze-start 주소를 호출하면 DB의 모든 그림을 순회하며 분석 결과를 painting_color_map 테이블에 저장하도록 설계

오류 해결

API 호출을 시작하자마자 콘솔창이 붉은색 에러 메시지로 도배되며 서버가 계속 돌아감

제미나이한테 분석시켜본 결과 PERMISSION_DENIEDUnknown column 'regDate' 에러

그리고... 구글에서 API를 이용하려면 기본적으로 결제 정보가 필요하다는 양아치같은 조건이 있었다

먼저 무한 루프를 막기 위해 try-catch 블록 내부에 에러 발생 시 즉시 중단되는 break;를 추가했다.
그다음 DB 에러를 해결하기 위해 HeidiSQL로 들어가 ALTER TABLE 명령어로 누락된 regDate 컬럼을 생성

마지막으로 구글 클라우드에서 프로젝트와 결제 계정이 연결되어 있지 않음을 확인하고 이를 바로잡으니 드디어 데이터가 DB에 쌓이기 시작했다


2. 리액트 아카이브 페이지 UI 및 라우팅 (Front-end)

jsp 가 아니라 리액트 쪽으로 설계를 할 예정이었다
이 레이아웃 설계 부분은 솔직히 제미나이를 죽을정도로 갈궜다

  • 레이아웃 설계: Tailwind CSS를 활용해 상단 카테고리 탭(전체, 이름, 사조, 색상)과 검색창이 ui 를 피그마에서 추출해서 다듬었다

  • 메이슨리(Masonry) 그리드:react-masonry-css 라이브러리를 설치해 격자 구조를 구현

  • 라우팅 설정: App.js에 주소를 등록해 사용자가 아카이브 페이지에 접근할 수 있도록 경로를 만들었다

오류 해결

페이지는 떴는데 데이터가 하나도 안 나오고 Cannot GET /api/archive/main이라는 HTML 에러 페이지가 생김

리액트 라우터(App.js) 경로를 /api/archive/main으로 설정하고 axios 주소도 똑같이 맞췄는데
브라우저는 내가 보여주고 싶은 화면 대신 백엔드의 데이터 통로를 화면 자체로 인식

화면 주소와 데이터 주소를 철저히 분리하는 방향으로 갔다
리액트 화면용 주소는 사용자가 보기 편한 /usr/archive/main
데이터 요청용 주소만 서버 경로인 /api/archive/main

package.json에 프록시(proxy) 설정을 했음에도 반영이 안돼서 결국 모든 주소를 또 axios 에 때려박는 방법을 쓸 수 밖에 없었다


3. 백엔드 데이터 연동

이제 리액트 화면에서 서버의 데이터를 불러와야 한다

  • Axios 연동: useEffect를 사용해 컴포넌트 마운트 시점에 서버에 데이터를 요청하고 setPaintings로 상태를 업데이트

  • 이미지 경로: DB의 절대 경로(C:\...)를 리액트가 읽을 수 있는 상대 경로로 변환하는 .replace() 로직을 적용

오류 해결

요청을 보내면 스프링 서버 콘솔에 BindingException: Invalid bound statement (not found)라는 에러가 찍힘

ArchiveRepository 인터페이스에도 오타가 없었고 컨트롤러나 서비스에도 오류는 없었는데 문제는 xml 매퍼 파일이었다

ArchiveRepository.xmlnamespace 경로 끝에 마침표가 하나 찍혀 있었고
결정적으로 XML의 idgetPaintings인데
자바 인터페이스는 getPainting으로 끝에 's'가 빠져 있었다
사소한 오타를 고치고 나니 드디어 데이터가 보였다


4. 디자인 통합과 최종 다듬기

마지막으로 디자인에 실제 데이터를 입히고 메이슨리 정렬을 완성하는 단계까지 왔다

  • 컴포넌트 구조화: paintings.map을 사용해 카드를 동적으로 생성하고, 이미지와 텍스트를 배치

오류 해결 (대소문자 오타)

Module not found: Can't resolve './ArchivePage.css' 에러가 나며 빌드가 멈췄다
분명히 파일이 있는데 없다고 해서
파일 경로가 틀린 줄 알고 파일 이동도 해보고 ../../ 경로도 고쳐봤는데 여전히 문제가 사라지지 않았다

그래서 에러 메시지를 다시 정독해보니
파일 이름은 Archivepage.css인데
호출은 ArchivePage.css로 하고 있었다

파일명과 import 문을 대문자 'P'로 통일하고 서버를 재시작하니 에러가 사라졌다
이거 진행하면서 나는 오류는 90% 이상이 대소문자 오류인 것 같다

또한 메이슨리 그리드가 한 줄로 나오던 현상은 전용 CSS 컨테이너 설정을 display: flex로 잡아서 반응형으로 바꿔줬다


이렇게...그냥...진짜 기초... 전체 아카이브만 추가했다...


반성

연휴 끝인데 고작 이거밖에 못했다

작업 계획을 어떻게 해야할지 갈피를 못잡아서 시간을 낭비했고
연휴 시작되고 집에서 나가있는 시간이 많아서 또 시간을 낭비했다
안그래도 잘 못하는데 시간까지 안들이면 어쩌자는건지...난 대체 뭘 한걸까..

profile
공부기록

0개의 댓글