이미지를 grayscale 함수로 보고, 밝기 임계값을 0→255로 올리면서 나타나고(birth) 사라지는(death) 위상적 특징을 추적한다. PH는 형태를, Color는 색상을, OCR은 텍스트를 보기 때문에 세 관점이 상호 보완된다.

H₀ — Connected Components
밝기 임계값을 올리면 밝은 영역들이 나타나고 합쳐짐.
포장의 밝기 분포 구조를 포착.
H₁ — Holes (1-cycles)
밝은 영역들이 고리(구멍)를 형성하는 패턴.
글자, 로고의 기하학적 구조를 반영.
촬영 center_crop (3:4) OCR (원본 해상도) 128×128 PH 54D + Color 96D Z-score → L2
등록모드 (Registration)

목적: 상품 DB 구축 (~8초/장, 정확도 우선)

1. 사진 촬영 → center_crop (3:4)

2. 원본 해상도 OCR (Tesseract eng+kor)

3. 128×128 → PH 54D + Color 96D

4. DB 저장 (150D 벡터 + OCR 텍스트)

스캔모드 (Scan)

목적: 실시간 식별 (~0.7초, 속도 우선)

1. 카메라 프리뷰 캡처

2. center_crop → OCR → 128×128

3. PH 54D + Color 96D 추출

4. Z-score 정규화 (DB 통계 기준)

5. L2 거리 − OCR 보너스 → Top-1

PH 54D (3 filtrations × 18D)

1. Sublevel set (원본 grayscale)
2. Edge / Sobel (경계선 강도)
3. Gradient / Laplacian (변화율)
각 filtration에서 H₀, H₁의 count, sum, max, mean, std + 4-bin 분포

Color 96D (HSV Histogram)

H (Hue) 32 bins — 색상
S (Saturation) 32 bins — 채도
V (Value) 32 bins — 명도
각 채널 독립 히스토그램, L1 정규화

System Architecture — Client, Server, Pipeline
Android/iOS → Spring Boot API → Python (GUDHI + OpenCV + Tesseract) → MySQL

Android 앱의 MediaProjection 화면 녹화. 카메라 프리뷰 위에 상품명, 신뢰도, Top-3이 실시간 표시된다.
좌: 4주차 PH+Color only / 우: 5주차 PH+Color+OCR (이미지 압축 적용 후 응답 속도 개선)

4주차 스캔 — PH+Color only (2026.05.22)
5주차 스캔 — PH+Color+OCR (2026.05.30)

5가지 피처 조합에 대해 201개 등록 이미지를 Leave-One-Out 교차검증으로 평가하였다. 각 이미지를 하나씩 빼고 나머지로 DB를 구성한 뒤, 빠진 이미지의 상품을 맞추는 과정을 201회 반복한다.

Feature Combination Dimension Correct Total Accuracy
PH only54D 15720178.11%
Color only96D 17120185.07%
PH + Color150D 188201 93.53%
OCR onlytext 9820148.76%
PH + Color + OCR150D + text 189201 94.03%
Ablation Study 결과 + 주차별 정확도 추이
왼쪽: 피처 조합별 LOO 정확도 / 오른쪽: 주차별 정확도 추이 (LOO vs 실전 스캔)
PH + Color 상보성

PH 단독 78%, Color 단독 85%이지만 결합 시 93.5%로 도약한다. PH는 형태(topology), Color는 색상 분포(histogram)를 포착하여 한쪽이 틀리는 경우를 다른 쪽이 보완한다.
위상 정보가 독립적 가치를 제공한다는 TDA 연구의 핵심 증거.

OCR의 역할

OCR 단독 48.76%로 주역은 아니지만, PH+Color가 혼동하는 상품 쌍에서 결정적 보너스를 제공한다 (93.53% → 94.03%).
OCR weight 탐색 결과 w=1.0에서 최적이며, w≥1.0에서 포화(saturated)된다.

상품별 정확도 (PH+Color+OCR, LOO)10 products
상품이미지정답정확도
cookie2020100%
orthomol2121100%
tubing band2020100%
Philips JC302212095.24%
kitkat201995.00%
pokemon go++201995.00%
Airpods Pro201890.00%
every time201890.00%
kavalan191789.47%
stanley201785.00%
OCR Weight 탐색sweep

adjusted = L2_distance − (OCR_similarity × weight)

WeightCorrectAccuracy
0.518893.53%
1.018994.03%
1.518994.03%
2.018994.03%
3.018994.03%
5.018994.03%

4주차(PH+Color only)와 5주차(PH+Color+OCR)의 실제 스캔 결과를 비교한다. 동일한 10종 상품을 같은 앱으로 스캔하되, 서버 파이프라인에 OCR이 추가된 것이 유일한 차이다.

94.03%
LOO 검증 (201 images, 10 products)
← 15.6%p →
78.46%
5주차 실전 스캔 — PH+Color+OCR (등록 상품 51/65건)
← +11.8%p →
66.67%
4주차 실전 스캔 — PH+Color only (등록 상품 42/63건)
상품 4주차 (OCR 없음) 5주차 (OCR 적용) 변화
pokemon go ++ 71.4% (10/14) 100% (9/9) +28.6%p
tubing band 0% (0/3) 85.7% (6/7) +85.7%p
Philips JC302 50.0% (4/8) 75.0% (6/8) +25.0%p
Airpods Pro 57.1% (4/7) 77.8% (7/9) +20.7%p
orthomol 100% (3/3) 88.9% (8/9) -11.1%p
every time 100% (8/8) 100% (7/7) 0
cookie 100% (5/5) 100% (8/8) 0
kavalan 0% (0/2) 0% (0/6) 0%

Android 앱에서 실시간 스캔 후 O/X 판정한 화면. PH+Color+OCR 파이프라인이 상품명, 신뢰도, Top-3을 표시한다.

pokemon go ++ 정답
pokemon go ++ O
tubing band 정답
tubing band O
Philips JC302 정답
Philips JC302 O
Airpods Pro 정답
Airpods Pro O
orthomol 정답
orthomol O
cookie 정답
cookie O
kavalan 오답
kavalan X (0/6)
OCR이 해결한 것

텍스트가 뚜렷한 상품(tubing band, pokemon go ++)에서 극적 개선.
4주차 오인식 21건 → 5주차 14건으로 33% 감소.
OCR 유사도 보너스가 PH+Color 거리만으로 구별 어려운 상품을 분리해준다.

잔여 Gap 원인

kavalan 0% — OCR 적용 후에도 6회 연속 실패. 등록 이미지 다양성 부족이 근본 원인.
촬영 조건 변동 — 조명/각도/거리 차이가 피처 벡터를 변형시켜 등록 벡터와의 거리가 벌어진다.
피처 설계가 아닌 데이터 다양성의 문제

연구 방법

상품 이미지에서 Persistent Homology(PH)로 위상적 특징 54D, Color Histogram으로 색상 분포 96D, OCR로 텍스트를 추출하여 총 150D 벡터 + 텍스트 유사도로 상품을 식별하는 시스템을 구축하였다. 11종 상품 211개 등록 이미지에 대해 Leave-One-Out 교차검증으로 각 피처의 기여도를 측정하고, 153건의 실제 스캔(4주차 78건 + 5주차 75건)으로 OCR 기여를 실전 검증하였다. 총 364장의 이미지를 처리하였다.

78.11%
PH 단독 (LOO)
85.07%
Color 단독 (LOO)
94.03%
PH+Color+OCR (LOO)
78.46%
실전 스캔 (OCR 적용)
+11.8%p
OCR 기여 (실전)

PH + Color + OCR 조합이 실전에서 작동한다

LOO 94.03%뿐 아니라 실전 스캔에서도 78.5%를 달성하였다. OCR 없이 66.7%에서 OCR 적용 후 78.5%로 +11.8%p 향상. tubing band 0%→86%, pokemon go++ 71%→100% 등 텍스트가 뚜렷한 상품에서 특히 효과적이다.

Gap은 피처가 아닌 데이터 문제

LOO 94%와 실전 78.5%의 잔여 gap 15.6%p는 kavalan(0/6, 0%)이 대표적 사례로, 등록 이미지의 다양성 부족에서 기인한다. 피처 설계 자체의 한계가 아니며, 다양한 조건의 등록 이미지 확보로 해결 가능하다.

학습 없이 동작한다

딥러닝과 달리 학습 데이터 없이 등록 즉시 식별이 가능하다. CPU만으로 0.7초 내 응답하며, 신규 상품을 재학습 없이 추가할 수 있다. Android + iOS 앱으로 실제 동작하는 시스템을 구현하였다.

현재까지의 결론

Persistent Homology는 상품 이미지 식별에서 유의미한 위상적 특징을 제공하며, Color Histogram, OCR과 결합 시 상보적으로 작용하여 실전 스캔 78.5%를 달성한다. OCR 적용 전후 비교를 통해 +11.8%p의 실전 기여가 검증되었으며, 잔여 gap 15.6%p(LOO 94% vs 실전 78.5%)는 등록 이미지 다양성 확보로 줄일 수 있다. PH 기반 피처는 추가 연구(Wasserstein distance, persistence image, data augmentation)를 통해 더 높은 실전 정확도 도달이 가능하다.

단기

  • Data Augmentation (다양한 각도/조명 등록) — kavalan 0% 해결
  • 바코드 우선 매칭 파이프라인 적용
  • Confidence 컷오프 최적화

중장기

  • 상품 수 확대 (10종 → 50종+)
  • PH landscape / persistence image 탐색
  • Wasserstein 등 거리 메트릭 비교
  • SIFT/HOG/CNN과의 비교 실험
사용 도구 (모두 오픈소스)tools
용도도구버전라이선스
PH 계산GUDHI3.12.0MIT
이미지 처리 + ColorOpenCV4.13.0Apache 2.0
OCR 엔진Tesseract5.5.0Apache 2.0
AndroidCameraX + Retrofit 2Apache 2.0
iOSSwiftUI + AVFoundationMIT
ServerSpring Boot + MySQL3.5 / 8.4Apache / GPL
GUDHI CubicalComplex Python 3.12 Spring Boot 3.5 Android / Java 17 iOS / SwiftUI MySQL 8.4 AWS EC2

이하 주차별 상세 실험 로그는 한국어로 제공됩니다.

5주차 — OCR 실전 검증 66.7% → 78.5% (+11.8%p)
Latest

Feature Ablation Study로 PH/Color/OCR 기여도를 정량 측정(LOO 94.03%)하고,
OCR을 스캔 파이프라인에 통합한 뒤 실제 스캔으로 OCR 기여를 검증하였다.
등록 상품 기준 66.7% → 78.5% (+11.8%p) 향상 확인.

94.03%
LOO (PH+Color+OCR)
78.46%
실전 스캔 (OCR 적용)
66.67%
실전 스캔 (OCR 없음)
+11.8%p
OCR 실전 기여

5가지 피처 조합에 대해 201개 등록 이미지를 Leave-One-Out 교차검증으로 평가하였다.
각 이미지를 하나씩 빼고 나머지로 DB를 구성한 뒤, 빠진 이미지의 상품을 맞추는 과정을 201회 반복한다.

Feature Combination Dimension Correct Total Accuracy
PH only 54D 157 201 78.11%
Color only 96D 171 201 85.07%
PH + Color 150D 188 201 93.53%
OCR only text 98 201 48.76%
PH + Color + OCR 150D + text 189 201 94.03%

PH + Color 상보성 — PH 단독 78.11%, Color 단독 85.07%이지만 결합 시 93.53%로 도약한다. PH는 형태(topology), Color는 색상 분포(histogram)를 포착하여 서로 다른 차원의 정보를 제공하므로, 한쪽이 틀리는 경우를 다른 쪽이 보완한다.

OCR의 역할 — OCR 단독 48.76%로 독립적 판별력은 낮지만, PH+Color가 혼동하는 상품 쌍에서 결정적 보너스를 제공하여 93.53% → 94.03%로 개선한다. OCR weight 탐색 결과 w=1.0에서 최적이며, w≥1.0에서 포화(saturated)된다.

LOO vs 실전 갭 — LOO 94.03% vs 실제 스캔 57.69%로 36.3%p 차이가 존재한다. 촬영 조건(각도, 거리, 조명)의 변동이 주 원인이며, 등록 시 다양한 조건에서 촬영(data augmentation)하면 갭을 줄일 수 있다.

adjusted_distance = L2_distance − (OCR_similarity × weight).
weight를 0.5~5.0까지 탐색한 결과, w=1.0에서 최적 성능을 달성한다.

OCR WeightCorrectTotalAccuracy
0.518820193.53%
1.018920194.03%
1.518920194.03%
2.018920194.03%
3.018920194.03%
5.018920194.03%
상품등록 이미지정답정확도
cookie2020100%
orthomol2121100%
tubing band2020100%
Philips JC302212095.24%
kitkat201995.00%
pokemon go++201995.00%
Airpods Pro201890.00%
every time201890.00%
kavalan191789.47%
stanley201785.00%

128×128 리사이즈 후 OCR을 적용하면 글자가 뭉개지는 문제가 있었다. 해결: 원본 해상도 center_crop에서 OCR을 먼저 추출하고, 이후 128×128로 리사이즈하여 PH/Color를 계산한다.

# Scan pipeline (identify_ph_color.py)
img = Image.open(path).convert("RGB")
cropped = center_crop(img)            # 3:4 ratio

ocr_text = extract_ocr_text(cropped)  # OCR on original resolution

gray_128 = cv2.resize(gray, (128,128))
color_128 = cv2.resize(rgb, (128,128))
ph = ph_features_54d(gray_128)        # PH 54D (3 filtrations)
color = color_features_96d(color_128) # Color 96D (H32+S32+V32)

OCR 텍스트 유사도는 단어 Jaccard문자 트라이그램 Jaccard 중 큰 값을 취한다. 트라이그램은 OCR 노이즈(오타, 깨진 문자)에 강건하다. 0°/180° 회전 중 더 많은 문자를 인식하는 방향을 선택한다.

주차별 정확도 비교
1~3주차 자가 테스트(LOO) / 4주차 실제 스캔 / 5주차 LOO (201개 이미지, 10종)
  • PH+Color 상보성 확인 — PH 78% + Color 85% → PH+Color 93.5%. 위상 정보와 색상 분포가 상호 보완적이라는 TDA 연구의 핵심 발견.
  • OCR은 보조 피처 — 단독 49%로 주역은 아니지만, PH+Color 혼동 케이스에서 결정적 1표를 추가 (93.5% → 94.0%).
  • LOO vs 실전 갭 36%p — 촬영 조건 변동이 주 원인. data augmentation + 바코드 우선 매칭으로 75~80% 도달 목표.
  • 바코드 2단계 전략 — 바코드 인식 시 100% 확정, 미인식 시 PH+Color+OCR 폴백.
5주차 시행착오log
  • OCR 해상도 순서 — 128×128 리사이즈 후 OCR은 무의미한 결과. 원본 해상도에서 OCR을 먼저 추출 후 리사이즈로 해결.
  • OCR 회전 4방향 → 2방향 — 90°/270°는 실전에서 거의 없음. 0°/180°만 유지하여 속도 절반으로 단축, 정확도 손실 없음.
  • OCR Weight 포화 — w=1.0 이후 정확도 불변. OCR이 기여하는 케이스가 201개 중 1개(188→189)뿐이므로 가중치를 높여도 효과 없음.
  • Data Freeze Race Condition — X 판정 후 바코드 스캔 중 백그라운드에서 스캔 결과가 변경되는 문제. 판정 시점 스냅샷 동결로 해결.
  • Data Augmentation — 등록 시 다양한 조건에서 촬영하면 실전 환경에 가까운 피처 분포가 형성되어 LOO-실전 갭이 줄어들 것으로 기대.
  • 바코드 우선 매칭 실전 적용 — 스캔 파이프라인에 "바코드 먼저 → 없으면 피처 비교"를 적용.
  • Confidence 컷오프 최적화 — 확신이 낮은 판정을 "미확인"으로 분류하여 오답률을 줄임.
사용 도구 (모두 오픈소스)tools
용도도구버전라이선스
PH 계산GUDHI3.12.0MIT
이미지 처리 + Color HistogramOpenCV4.13.0Apache 2.0
OCR 엔진Tesseract5.5.0Apache 2.0
Android 앱CameraX + Retrofit 2Apache 2.0
iOS 앱SwiftUI + AVFoundationMIT
서버Spring Boot + MySQL3.5 / 8.4Apache / GPL
4주차 — 등록모드/스캔모드 분리 + 실제 스캔 실험 (69.0%)

3주차에서 자가 테스트(DB 이미지 ↔ DB 이미지) 100%를 달성하였으나, 이는 등록된 이미지로 등록된 이미지를 찾는 것이다.
4주차에서는 등록모드(PH+Color+OCR로 상품 정보 저장)와 스캔모드(카메라로 실물을 촬영하여 판정)를 분리하고,
SAM을 제거하고 center_crop으로 통일한 뒤, 실제 스마트폰으로 10종 상품을 스캔하여 정확도를 측정하였다.

69.0%
실제 스캔 정확도 (29/42)
100%
자가 테스트 (30/30)
~700ms
스캔 응답 시간
150D
PH 54D + Color 96D
등록모드 — Product Registration
PH 54D + Color 96D + OCR
상품 사진을 서버에 업로드하면
PH(형태) + Color(색상) + OCR(글자) 세 가지 피처
모두 계산하여 DB에 저장한다. ~8초/장.
스캔모드 — Product Scan
PH 54D + Color 96D (OCR 제외)
카메라로 상품을 비추면 2초 간격으로
PH+Color만 추출하여 DB와 비교한다.
OCR 제외로 ~700ms에 응답.

이전 주차에서는 등록 시 MobileSAM(물체 인식 크롭)을 사용했으나, 스캔 시에는 SAM 없이 center_crop을 사용했다.
SAM 크롭과 center_crop이 만드는 이미지가 다르기 때문에 — 같은 상품을 찍어도
피처 벡터가 완전히 다른 공간에 놓이는 문제가 발생하였다 (PH L2 차이: 5,267).
등록과 스캔 모두 center_crop(3:4 비율 중앙 크롭)으로 통일하여 피처 공간 불일치를 해결하였다.

3주차에서는 Min-Max 정규화를 사용했다. 그러나 Min-Max는 쿼리마다 최소/최대가 바뀌어 결과가 불안정하다.
4주차에서 Z-score 정규화로 전환하여 DB 전체의 평균(μ)과 표준편차(σ)를 기준으로 정규화한다.

Min-Max (3주차)
(x - min) / (max - min)
쿼리마다 min/max가 달라져 상대적 → 86.7%
Z-score (4주차)
(x - μ) / σ
DB 전체 통계 기준으로 고정 → 100%

자가 테스트는 DB에 등록된 이미지를 다시 쿼리로 넣는 것이다. 같은 이미지이므로 100%가 당연하다.
실제 스캔은 스마트폰 카메라로 실물 상품을 촬영한다. 조명, 각도, 거리, 배경이 모두 달라진다.
이 차이가 정확도 100% → 69.0% 하락의 원인이다.

주차별 정확도 비교
1~3주차는 자가 테스트(LOO) / 4주차는 실제 스캔 — 3주차 100%와 실제 스캔 69.0%의 gap
상품별 실제 스캔 정확도
초록: 100% / 노랑: >0% / 빨강: 0% — stanley(0%), kavalan(0%), kitkat(0%)에서 전혀 인식 실패
Product스캔정답정확도주요 오판
PhilipsJC30255100%
orthomol88100%
cookie66100%
every time4375%→ kitkat ×1
pokemon go5360%→ PhilipsJC302 ×2
tubing band5360%→ kavalan ×2
stanley300%→ every time ×3
kavalan400%→ every time ×3, kitkat ×1
kitkat100%→ every time ×1
정답없음 (미등록)30pokemongo, kitkat, everytime으로 오분류

오판이 특정 상품 쌍에 집중된다. stanley → every time (3회), kavalan → every time/kitkat (4회), tubingband → kavalan (2회).
every time이 강한 어트랙터로 작용하여, stanley·kavalan·kitkat이 모두 every time으로 끌린다.
PH+Color 만으로는 이 유사성을 구분하지 못한다 — 텍스트(OCR)가 구분의 열쇠가 될 수 있다.

혼동 패턴
반복적 혼동 패턴: every time이 어트랙터 — stanley(3회), kavalan(3회), kitkat(1회)이 every time으로 오분류

Android 앱의 스캔모드에서 실제 상품을 카메라로 비추고, O(정답)/X(오답) 버튼으로 판정한 결과이다.
상단에 예측 상품명과 신뢰도, 하단에 Top-3 매칭 결과와 서버 응답 시간이 표시된다.

정답 사례 (O) — 대표 6건correct
PhilipsJC302 correct
PhilipsJC302 — 정답 (conf 0.079)
orthomol correct
orthomol — 정답 (conf 0.253)
cookie correct
cookie — 정답 (conf 0.194)
tubingband correct
tubing band — 정답 (conf 0.041)
everytime correct
every time — 정답 (conf 0.245)
pokemongo correct
pokemon go — 정답 (conf 0.115)
오답 사례 (X) — 대표 4건wrong
stanley wrong
stanley → every time으로 오판 (conf 0.147)
kavalan wrong
kavalan → every time으로 오판 (conf 0.047)
tubingband wrong
tubing band → kavalan으로 오판 (conf 0.095)
pokemongo wrong
pokemon go → PhilipsJC302로 오판 (conf 0.038)

신뢰도는 1위와 2위의 거리 차이를 나타낸다: confidence = (d₂ - d₁) / d₂
값이 클수록 1위가 확실히 가깝고, 작으면 1위와 2위가 비슷하다는 뜻이다.
실제 결과에서 정답도 오답도 대부분 0.002~0.17 범위로 낮았다 —
상품 간 거리가 전반적으로 비슷하여 신뢰도만으로 정답/오답을 구분하기 어렵다.

자가 테스트 100%와 실제 스캔 69.0%의 차이는 카메라 촬영 환경의 변동성(조명, 각도, 거리)이 원인이다.
등록된 이미지는 고정된 조건에서 촬영되었지만, 실제 스캔은 매번 다른 조건에서 촬영된다.
9개 상품 중 3개(PhilipsJC302, orthomol, cookie)가 100%를 달성했지만,
stanley(0%), kavalan(0%), kitkat(0%)에서 전혀 인식에 실패하였고, every time(75%), pokemongo·tubingband(60%)도 불완전하다.

그러나 랜덤(10%) 대비 PH+Color(69.0%)는 의미 있는 개선이며,
PH 피처(위상적 형태 정보)가 색상 정보와 결합하여 식별력에 기여한다는 근거가 된다.
every time이 어트랙터로 작용하여 stanley·kavalan·kitkat을 끌어당기는 패턴이 확인되었으며,
텍스트가 뚜렷한 상품의 혼동은 OCR 추가가 해소의 열쇠가 될 수 있다.

4주차 시행착오log
  • SAM ↔ center_crop 피처 불일치 — 등록(SAM)과 스캔(center_crop)의 크롭 영역이 달라 피처 벡터가 완전히 다른 공간에 놓였다. PH L2 차이 5,267. center_crop 통일로 해결.
  • Min-Max → Z-score 정규화 — Min-Max는 쿼리마다 기준이 바뀌어 86.7%. Z-score(DB 전체 통계 고정)로 전환 후 100%.
  • Color Histogram 불일치 — 쿼리는 H/S/V 분리 32bin, DB는 HSV joint [8,8,2]로 계산. H32+S32+V32 = 96D로 통일.
  • OCR 해상도 — 256px 리사이즈 시 OCR이 무의미한 결과("fi ss", "bw"). 원본 해상도에서 의미 있는 텍스트 추출 확인("sugar butter tree kit"). 등록모드에서만 원본 해상도 OCR 수행.
  • result_summary 컬럼 오버플로우 — TEXT(64KB) 제한으로 OCR이 긴 이미지에서 저장 실패. MEDIUMTEXT로 변경.
  • 스캔모드에 OCR 추가 검토 — OCR이 ~6초 걸려 스캔에서 제외했으나, kavalan↔every time 혼동을 OCR로 해소할 수 있는지 검증. OCR 경량화(해상도 조정, 엔진 교체) 또는 비동기 처리 방식을 탐색한다.
  • PH+Color vs PH+Color+OCR 정량 비교 — 동일 스캔 세트에서 OCR 유무에 따른 정확도를 비교하여, OCR의 실질적 기여도를 정량적으로 확인한다.
  • 혼동 상품 쌍 심층 분석 — kavalan/every time, pokemon go/tubing band의 피처 벡터를 시각화하여, 어떤 차원에서 혼동이 발생하는지 분석한다.
사용 도구 (모두 오픈소스)tools
용도도구버전라이선스
PH 계산GUDHI3.12.0MIT
이미지 처리 + Color HistogramOpenCV4.13.0Apache 2.0
OCR 엔진 (등록모드)Tesseract5.5.0Apache 2.0
Android 앱CameraX + Retrofit 2Apache 2.0
서버Spring Boot + MySQL3.5 / 8.4Apache / GPL
3주차 — PH + Color + OCR 결합 (Top-1 100%)

2주차에서 PH 단독 94%의 한계를 확인하고, 색상 히스토그램(HSV)OCR 텍스트 인식을 결합하여
동일 100장(10종×10장)에 대해 Top-1 100%, Top-5 100%를 달성하였다.
PH는 형태, Color는 색상, OCR은 글자를 보기 때문에 세 관점이 상호 보완된다.

100%
Top-1 (PH + Color)
100%
Top-5
10 / 100
상품 수 / 사진 수
150D
PH 54D + Color 96D
Color Histogram (HSV) — 96D
이미지의 색상 분포를 숫자로 요약
HSV 색공간으로 변환 후 각 채널(색상/채도/명도)을
32구간으로 나눠 픽셀 수를 셈. H(32) + S(32) + V(32) = 96차원.
OpenCV cv2.calcHist() 한 줄로 계산. Apache 2.0.
OCR Text — Tesseract 5.5
상품 표면의 글자를 읽어서 비교
크롭된 이미지에서 Tesseract OCR로 텍스트를 추출하고,
character trigram Jaccard 유사도로 비교.
Google 유지보수 오픈소스. Apache 2.0.

동일 100장에 대해 특징 조합을 바꿔가며 LOO(한 장씩 빼면서 검증) 정확도를 측정했다.
PH 거리는 수만 단위, Color 거리는 소수점, OCR 유사도는 0~1 — 단위가 제각각이라
그냥 합산하면 숫자가 큰 PH만 결과를 지배한다. 모든 거리를 0~1 범위로 맞춘 뒤(Min-Max 정규화)
동등하게 합산해야 세 특징이 공정하게 기여할 수 있다.

Min-Max 정규화란?
각 값을 가장 작은 값 = 0, 가장 큰 값 = 1로 변환하는 방법이다.
정규화된 값 = (원래 값 − 최소값) / (최대값 − 최소값)
예시 — 시험 점수 60, 70, 80, 90, 100점
최소=60, 최대=100일 때
60점 → (60−60)/(100−60) = 0  |  80점 → (80−60)/(100−60) = 0.5  |  100점 → (100−60)/(100−60) = 1
왜 필요한가 — 정규화 전후 비교
PH Color OCR 합계
정규화 전 5,000 0.1 0.2 5,000.3 (PH가 99.9%)
정규화 후 0.3 0.4 0.5 1.2 (셋 다 공평)
Method Accuracy Comparison
파란 막대: Top-1 / 초록 막대: Top-5 / 빨간 점선: 2주차 PH baseline (94%)
MethodDimTop-1Top-5설명
PH 54D (baseline)54D79%89%형태만 — 정규화 적용 시
Color 96D only96D97%99%색상만 — 단독으로도 매우 강력
OCR onlytext74%88%글자만 — 노이즈 多, 텍스트 뚜렷한 상품에서 유효
PH + Color150D100%100%Best — 형태 + 색상 결합으로 완벽 보완
PH + OCR54D+text90%94%형태 + 글자
PH + Color + OCR150D+text100%100%3가지 모두 결합

PH + Color만으로 이미 100%. OCR은 현재 추가 이득이 없지만, 같은 상품의 다른 맛/색상/사이즈 변형(예: 킷캣 오리지널 vs 딸기)처럼 박스 형태와 색은 거의 같고 글자만 다른 경우에 필수적이 된다.

Per-Product Accuracy
파랑: PH / 노랑: Color / 보라: OCR / 초록: PH+Color — 모든 상품이 100%로 개선
상품별 상세 결과detail
ProductPH onlyColor onlyOCR onlyPH+ColorPH 오분류
tubing band100%100%90%100%
cookie90%100%100%100%→ every time ×1
orthomol90%100%80%100%→ Airpods Pro ×1
Airpods Pro90%80%20%100%→ stanley ×1
pokemon go ++90%90%80%100%→ kitkat ×1
kitkat80%100%100%100%→ pokemon ×2
Philips JC30270%100%100%100%→ every time, tubing, cookie
stanley70%100%40%100%→ cookie, kitkat, Airpods
every time60%100%80%100%→ pokemon, stanley, tubing, cookie
kavalan50%100%50%100%→ tubing, Philips, stanley ×2
PH 54D — 형태
흑백 밝기 패턴의 위상 구조
색을 무시하고 형태만 본다.
같은 색이어도 모양이 다르면 구분.
tubing band 100%, kavalan 50%.
Color 96D — 색상
HSV 색상 분포
형태를 무시하고 색만 본다.
색이 다르면 즉시 구분. 단독 97%.
같은 색 상품이 늘면 한계.
OCR — 글자
상품 표면 텍스트 인식
형태·색 무시, 글자만 본다.
kitkat, Philips 등 텍스트 뚜렷한 상품 100%.
Airpods(매끈) 20%, stanley 40%.
OCR 인식 현황 — 상품별 텍스트 추출data

Tesseract 5.5.0 (Apache 2.0, Google 유지보수)을 사용하였다. 촬영 각도와 표면 재질에 따라 인식률 차이가 크다.

Product인식률대표 추출 텍스트
kitkat10/10sugar butter tree kitkat
cookie10/10premium cookie set
Philips JC30210/10keep your shaver like new
orthomol10/10orthomol ronnefeldt tea excellence
every time10/10korean ginseng everytime
stanley10/10stanley
tubing band10/10(noisy, low quality)
kavalan10/10distillery reserve (sparse)
Airpods Pro9/10(mostly noise — smooth white surface)
pokemon go ++8/10niantic (sparse)

PH(형태) + Color(색상) + OCR(글자), 세 가지 관점을 결합하면
각각의 약점을 상호 보완하여 10종 100장에서 Top-1 100%, Top-5 100%를 달성한다.
PH + Color만으로 이미 100%이며, OCR은 현재 추가 이득이 없지만 —
같은 상품의 다른 맛/색상/사이즈(예: 킷캣 오리지널 vs 딸기)처럼 박스 형태와 색은 같고 글자만 다른 경우에 핵심 구분자가 된다.

핵심 발견은 Color Histogram이 단독 97%로 매우 강력하다는 점이다.
이는 현재 10종 상품의 색이 모두 다르기 때문이며, 같은 색 상품이 추가되면
Color 단독의 한계가 드러나고 PH의 형태 구분 능력이 필수적이 될 것이다.

이 세 특징을 결합한 벡터(150D + 텍스트)는 상품의 “시각적 지문(Fingerprint)”으로 기능한다.
물리적 바코드 없이, 겉모습만으로 상품을 식별하는 “TDA-based Product Fingerprint” 개념이다.
GPU나 AI 모델 없이 CPU 1~2초, 스마트폰에서 오프라인으로 동작 가능하다.

실험 한계 & 다음 주차에서 보완할 점
  • 10종은 색이 모두 달라 Color만으로 97% — PH의 기여가 3%에 불과하다. 유사 색상 상품을 추가해야 PH의 진가가 드러난다.
  • OCR 노이즈 — 촬영 각도·표면 재질에 따라 인식률 편차가 크다 (Airpods 20%, stanley 40%). 전처리 개선 또는 다른 OCR 엔진 검토 필요.
  • 동일 세션 데이터 — 여전히 같은 날 같은 환경에서 촬영한 100장이다. Temporal Split 미검증.
  • 상품 수 확대 (30~40종) — 기존 10종에 20~30종을 추가하여 Color 단독의 한계를 확인하고, PH + Color + OCR 결합의 확장성을 검증한다. 특히 같은 브랜드의 다른 맛/색상/사이즈(예: 킷캣 오리지널 vs 딸기 — 박스 형태와 색은 같고 글자만 다른 경우)를 포함하여 OCR의 실질적 기여를 검증한다.
  • 실시간 스캔 프로토타입 — 카메라 프리뷰에서 상품을 실시간으로 인식하는 모드. PH(64×64) + Color로 200~300ms 내 처리, 초당 3~5회 인식 목표.
  • Product Fingerprint DB — 상품별 fingerprint(150D + 텍스트)를 온디바이스 DB에 저장하고, 서버 없이 즉시 매칭하는 구조 구현.
사용 도구 (모두 오픈소스)tools
용도도구버전라이선스
PH 계산GUDHI3.12.0MIT
이미지 처리 + Color HistogramOpenCV4.13.0Apache 2.0
OCR 엔진Tesseract5.5.0Apache 2.0
OCR Python 래퍼pytesseract0.3.13Apache 2.0
DB 연동MySQL + mysql-connector8.4GPL / MIT
2주차 — PH 기반 상품 식별 정확도 개선 (94%)

10종 100장으로 PH 분류를 검증하고, 전처리와 분류 방법을 개선하였다.
중앙 50% 고정 크롭 + 128×128 해상도 표준화 + 다중 filtration 결합으로
100번 중 94번 첫 번째 답이 정답(Top-1 94%), 5개 후보 안에 정답이 반드시 포함(Top-5 100%)을 달성하였다.

94%
첫 답 정답률 (Top-1)
100%
5개 후보 내 정답 (Top-5)
10 / 100
상품 수 / 사진 수
54D
3가지 관점 결합

카메라 가이드 프레임 안에 상품을 놓고 촬영하면, 상품이 사진 중앙에 위치한다.
중앙 50%를 고정 크롭하여 항상 동일한 영역을 잘라내고,
128×128 grayscale로 통일하여 PH 비교의 일관성을 확보한다.

kitkat original kitkat crop kitkat gray
kitkat
cookie original cookie crop cookie gray
cookie
kavalan original kavalan crop kavalan gray
kavalan
airpods original airpods crop airpods gray
Airpods Pro

위: 원본(3024×4032) → 중앙: 50% 크롭(1512×2016) → 아래: 128×128 grayscale

실험 데이터 — 10종 × 10장data

10종 박스형 상품을 각 10장씩, CameraX 가이드 프레임 안에서 촬영했다.

ProductTypeImages
kitkat초콜릿 (박스)10
cookie쿠키 (박스)10
every time영양제 (박스)10
orthomol영양제 (박스)10
Airpods Pro이어폰 (박스)10
Philips JC302면도기 세정액 (박스)10
pokemon go ++카드 (박스)10
stanley텀블러 (박스)10
kavalan위스키 (박스)10
tubing band운동밴드 (박스)10
사진 → 숫자 → 비교 → 판정
  1. 사진을 숫자로 변환 — 128×128 grayscale 이미지에 PH를 적용하면,
    그 사진의 형태적 특징을 요약한 숫자 벡터(예: 18개의 숫자)가 나온다.
  2. 숫자끼리 거리 비교 — 두 사진의 숫자 벡터 간 거리를 계산한다.
    같은 상품이면 숫자가 비슷해서 거리가 가깝고, 다른 상품이면 멀다.
  3. 가장 가까운 것을 정답으로 판정 — “이 사진은 뭘까?” 물으면,
    나머지 99장 중 거리가 가장 가까운 사진의 상품명을 답으로 내놓는다.
  4. 100장 모두 반복 (Leave-One-Out) — 100장을 하나씩 빼면서 위 과정을 반복한다.
    100번 물어서 94번 맞히면 Top-1 94%.

Top-1 = 첫 번째 답이 정답인 비율  /  Top-5 = 가까운 순서로 5개를 후보로 줬을 때 그 안에 정답이 있는 비율

위 과정에서 “사진을 숫자로 변환하는 방법”과 “비교하는 방법”을 바꿔가며 정확도를 측정했다.
Sublevel(밝기값 기반)  /  Edge(윤곽선 기반)  /  Gradient(밝기 변화량 기반)
1-NN(가장 가까운 1장으로 판정)  /  3-NN(가장 가까운 3장의 다수결)  /  Centroid(상품별 평균 벡터와 비교)

Classification Accuracy Comparison
파란 막대: Top-1  /  초록 막대: Top-5  /  빨간 점선: 이전 Baseline 78%
관점차원Top-1Top-5설명
Sublevel (밝기값)18D89%99%밝기 패턴에서 PH 추출
Edge / Sobel (윤곽선)18D75%96%윤곽선에서 PH 추출
Gradient / Laplacian (변화량)18D67%97%밝기 변화량에서 PH 추출
Combined 54D (3관점 결합)54D94%100%Best — 위 3개를 합쳐서 상호 보완

각 관점은 단독으로 67~89%이지만, 3개를 합치면 서로 다른 특징을 보완하여 94% / 100%를 달성한다.

전체 실험 결과 — 비교 방식별 상세detail

같은 관점에서도 비교 방식을 바꿔 실험했다: 1-NN(가장 가까운 1장), 3-NN(3장 다수결), Centroid(평균 벡터 비교).
추가로 Persistence Image(450D), CFV 3D(핵심 값 3개) 등 다른 벡터화 방법도 시도했다.

MethodDimTop-1Top-5설명
SUBLEVEL (밝기값 기반) — 비교 방식별
Sublevel 1-NN18D89%99%가장 가까운 1장으로 판정
Sublevel 3-NN18D92%99%3장 다수결 — 안정성 향상
Sublevel 5-NN18D84%99%5장 다수결 — k가 크면 오히려 하락
Sublevel Centroid18D84%99%상품 평균 벡터와 비교
다른 벡터화 방법
CFV 3D3D52%92%핵심 값 3개만 — 해석 쉬움, 정확도 낮음
Persistence Image 1-NN450D87%98%birth-death 밀도 격자 — 고차원
COMBINED 54D — 비교 방식별
Combined 54D 1-NN54D94%100%Best
Combined 54D 3-NN54D92%100%Top-5 100% 유지
Combined 54D Centroid54D88%100%평균 벡터 비교
54D + PI (504D)504D91%99%차원 증가 대비 효과 제한적
핵심 발견
고정 크롭의 일관성이 핵심
항상 같은 영역을 자르면 PH 비교가 공정해진다.
같은 상품 → 비슷한 PH, 다른 상품 → 다른 PH가
명확하게 분리되어 정확도가 상승한다.
3가지 Filtration 결합
54D = 94% Top-1, 100% Top-5
밝기(sublevel) + 윤곽(edge) + 변화량(gradient)
서로 다른 관점의 PH를 결합하면
단일 관점에서 놓치는 차이를 상호 보완한다.
상품별 분류 결과 (Sublevel 18D 1-NN, 89%)detail
Product정답Accuracy오분류
kitkat10/10100%
orthomol10/10100%
stanley10/10100%
cookie9/1090%→ Airpods Pro ×1
every time9/1090%→ cookie ×1
Philips JC3029/1090%→ pokemon ×1
pokemon go ++9/1090%→ Philips ×1
tubing band9/1090%→ pokemon ×1
kavalan8/1080%→ kitkat ×1, Airpods ×1
Airpods Pro6/1060%→ stanley ×1, cookie ×2, every time ×1

Cubical Complex Filtration (격자 복합체 여과) — 이미지의 밝기값을 threshold(문턱값)로 사용한다.
threshold t를 0에서 1까지 올리면, 어두운 픽셀부터 순서대로 "켜지면서" connected component(연결 성분)가 생겼다 합쳐지고, hole(구멍)이 생겼다 사라진다.
생성(birth)과 소멸(death)의 패턴이 곧 그 이미지의 위상적 지문이다.

Cubical Complex Filtration Steps
위: threshold t에서의 sublevel set(하위준위집합) — 흰색 = 아직 안 켜짐  /  아래: 해당 threshold에서 켜진 영역(cyan)과 connected component(연결 성분) 수

Persistence Diagram (지속성 다이어그램) — 각 위상적 특징의 birth(생성)과 death(소멸)를 점으로 찍는다.
대각선에서 먼 점 = 오래 살아남은 구조 = 의미 있는 특징. 같은 상품은 다이어그램 패턴이 유사하고, 다른 상품은 다르다.

Persistence Diagram Comparison
왼쪽: 같은 상품(kitkat) 2장 → PD 패턴 유사  /  가운데: 다른 상품 → PD 분포 상이  /  오른쪽: 3종 비교
● H0 = connected components (연결 성분)   ● H1 = holes (구멍)

Persistence Barcode (지속성 바코드) — 각 특징의 수명을 bar(막대)로 표현한다.
긴 막대 = 노이즈가 아닌 실제 구조. 상품마다 막대의 길이 분포와 개수가 다르므로, 이를 통계적으로 요약하면 18차원 특징 벡터가 된다.

Persistence Barcode
H0 — connected components (연결 성분)  /  H1 — holes (구멍) — 상품마다 막대 분포가 다름 = PH가 상품을 구분하는 근거
클러스터 분리 시각화 — t-SNE(고차원→2D 압축), 참고ref

54D 벡터를 t-SNE(고차원→2D 압축 도구)로 2D로 줄이면 상품별로 깔끔하게 분리되는 것을 확인할 수 있다.
t-SNE(고차원→2D 압축 시각화)는 시각화 도구이며, 실제 정확도(94%)는 원본 54D에서 LOO(한 장씩 빼면서 검증)로 측정한 값이다.

t-SNE Cluster Comparison
왼쪽: Combined 54D t-SNE (94% Top-1)  /  오른쪽: CFV 3D (52% Top-1) — 차원이 높을수록 분리가 명확
Zero-shot (학습 없이 바로 인식)
학습 데이터 불필요
CNN은 상품별 수백~수천 장을 학습해야 한다.
PH는 사진 1장만 등록하면 바로 인식이 가능하다.
새 상품 추가 시 재학습 없이 즉시 적용된다.
Interpretable
(판단 근거 설명 가능)
왜 이 상품인지 수치로 제시
CNN은 “왜 이 상품인가”를 설명할 수 없다.
PH는 어떤 위상 구조가 유사한지
수치적으로 근거를 제시할 수 있다.
Lightweight (경량 연산)
CPU 1초, 스마트폰에서 바로
GPU도, 모델 파일(수백MB)도 필요 없다.
순수 수학 연산만으로 스마트폰에서
실시간 동작이 가능하다.

PH는 색상도 안 보고, 글자도 안 읽고, AI 학습도 없이 —
순수하게 grayscale 밝기 패턴의 위상적 구조만으로 상품을 구분하는 방법이다.
이것만으로 10종 상품을 94% 정확도로 맞히고, 5개 후보를 주면 100% 정답이 포함된다는 것은
PH가 상품 식별에 유효한 특징을 잡아낸다는 것을 증명한다.

핵심 발견은 크롭의 일관성이다.
단순한 고정 크롭이 높은 정확도를 냈다. 항상 같은 영역을 자르면
같은 상품은 비슷하게, 다른 상품은 다르게 나오는 것이 보장되기 때문이다.
비싼 모델 없이도, CPU 1초 연산만으로 이 정도 정확도를 낼 수 있다.

다만, 현재는 10종 박스형 상품이라는 제한된 조건이다.
Airpods Pro(60%)처럼 매끈한 표면은 grayscale에서 형태 차이가 적어 구분이 어렵고,
상품 수가 늘어나면 정확도가 떨어질 수 있다. PH 단독의 한계를 넘기 위해
다음 주차에서 색상과 텍스트 정보를 결합한다.

실험 한계 & 다음 주차에서 보완할 점
  • LOO(한 장씩 빼면서 검증)는 동일 세션 데이터 — 같은 날 같은 환경에서 촬영한 100장 안에서의 정확도다. 시간이 지난 뒤 다시 촬영한 사진으로 Temporal Split(시간차 재촬영 검증)을 해야 실사용 성능을 확인할 수 있다.
  • 10종 × 10장은 proof-of-concept — 촬영 장수를 늘리고 시간차를 두고 재촬영했을 때의 정확도 변화를 추적해야 실사용 가능성을 증명할 수 있다.
  • 색상 히스토그램 — PH는 흑백만 보므로, 색상(HSV) 분포를 추가하여 "형태는 비슷하지만 색이 다른" 상품을 구분한다
  • OCR 텍스트 — 상품 표면의 브랜드명/상품명을 읽어, 형태와 색상이 비슷해도 글자가 다르면 구분할 수 있게 한다
  • 데이터 확장 + 시간차 검증 — 기존 10종에 대해 촬영 장수를 늘리고(10장→20+장), 수일 뒤 재촬영한 사진으로 Temporal Split(시간차 재촬영 검증)을 수행하여 실사용 환경에서의 정확도를 검증한다
  • 온디바이스 인식 모드 — 고정 크롭 + PH를 폰에서 직접 실행하여, 서버 없이 2~3초 내 상품명을 표시하는 프로토타입
시스템 구축 사항infra
  • CameraX 커스텀 카메라 — 중앙 80% 가이드 프레임 + 탭 포커스
  • Spring Boot API — 이미지 업로드, PH 계산(@Async), 결과 조회
  • 이미지 서빙 — GET /api/tda/results/{id}/image
  • EC2 인프라 — nginx + MySQL 8.4 + GUDHI + PyTorch
환경 구축 상세infra
System Architecture
Android tda-android
CameraX 촬영
가이드 프레임
Retrofit 2
HTTPS
Multipart
EC2 t3.medium · kyuwan.kim
nginx nginx (SSL + Proxy)
Spring Spring Boot 3.5
GUDHI PH
MySQL MySQL 8.4
JSON
Android 결과 표시
PH 특징 벡터
cropBox 좌표
결과 조회
단일 EC2 · 고정 크롭 + GUDHI PH를 subprocess로 호출 · @Async 비동기 처리
  • AWS EC2(t3.medium, Seoul)에 nginx, Java 17, MySQL 8.4, Python 3.14, PyTorch 설치
  • 도메인(kyuwan.kim) 연결, Let's Encrypt SSL 인증서 발급 및 자동 갱신
  • Spring Boot 3.5.0 API 서버 — 고정 크롭 + GUDHI PH를 Python subprocess로 호출, @Async 비동기 처리
  • REST API 6종: POST /analyze, GET /results, GET /products, GET /products/{name}, GET /results/{id}/image, GET /health
  • MySQL DB — tda_analysis + tda_persistence_pair 2개 테이블, cropBox 좌표 저장
  • systemd 서비스, nginx 리버스 프록시(kyuwan.kim/api/* → :8080)
  • Android 앱 — CameraX 커스텀 카메라 + 가이드 프레임 + 탭 포커스, Multipart 업로드, 상품별 목록/상세 조회, 오프라인 큐
3
GitHub 레포지토리
6
REST API 엔드포인트
2
DB 테이블
HTTPS
보안 통신
Component Stack Role
tda-apiSpring Boot 3.5 · Java 17 · GUDHIREST API + 고정 크롭 + PH 계산
tda-androidJava · CameraX · Android SDK 34 · Retrofit 2가이드 프레임 촬영 + 결과 조회
EC2Ubuntu 26.04 · nginx · MySQL 8.4 · Python 3.14서버 인프라
1주차 — 환경 구축 및 파이프라인 검증
  • Python + GUDHI 기반 PH 바코드 파이프라인 구현
    초기에 JavaPlex(Java 기반 TDA 라이브러리)를 검토했으나, 이미지 PH에 특화된 CubicalComplex가 없어 GUDHI(C++ 기반, Python 바인딩)로 전환. 픽셀 격자를 직접 입력할 수 있어 변환 없이 빠르게 PH를 계산한다.
  • 같은 상품 10장 촬영 — 조건(각도, 거리, 조명)별 PH 바코드 일관성 검증
  • Canny 엣지 자동 크롭 실패(5/10) → 고정 크롭 1816×2420으로 해결
  • 18차원 특징 벡터 설계 — H₀/H₁ count, total/max/mean/std persistence, 구간별 Betti number
PH Pipeline: Original → Crop → Grayscale → Persistence Diagram → Barcode
원본 촬영 → 고정 크롭 → 흑백 변환 → Persistence Diagram → PH Barcode
Image H₀ count H₁ count H₀ max pers. H₁ max pers.
img_015,8035,53424727
img_024,7844,49924531
img_034,8694,59824623
img_045,2564,97024721
img_054,6144,32624024
img_063,8843,70624824
img_074,6984,41924627
img_084,8264,56024932
img_094,9794,69724528
img_104,6544,37724627
22,032
평균 거리
13,946
편차
997
최소 거리
50,810
최대 거리

동일 상품(kitkat) 10장을 각도·거리·조명을 달리하며 촬영하고
PH 특징 벡터를 비교한 결과,
H₀ max persistence 240~249, H₀ count 3,884~5,803으로
모든 이미지가 일정 범위 안에 모이는 것을 확인했다.

즉, 촬영 조건이 달라져도 같은 상품의 위상적 구조는 안정적으로 유지된다.
이는 PH가 같은 상품을 "같다"고 인식할 수 있음을 의미한다.

다음 주에는 여러 종류의 상품을 촬영하여,
서로 다른 상품끼리도 PH로 구별이 가능한지
검증하겠다.