CS 분석 보고서 · 2026-04-16

이미지 회전 문제 분석 — QM41200565

AI 포토북 자동 편집 · 표준화 포토북 · 프로젝트 20260412002130

💬 고객 리뷰 (★3): "사진 날짜별로 차례로 올렸는데 뒤죽박죽에 거꾸로 인쇄된것도 있네요 ㅠㅠ"
72
총 이미지
18
회전 필요 이미지
(EXIF OT≠1)
18
AI OT 불일치
(미보정 추정)
1
AI DB 저장값
(모든 이미지 동일)

📊 EXIF Orientation 분포 vs AI 분석 결과

EXIF OT 값 의미 이미지 수 AI DB 저장값 상태
OT 1 정상 (0°) 22개 OT 1 ✅ 일치
OT 0 EXIF 없음/미설정 32개 OT 1 — AI 판단 사용
OT 6 시계방향 90° 회전 필요 ⚠️ 12개 OT 1 ❌ 불일치 — 미보정
OT 3 180° 뒤집힘 ⚠️ 4개 OT 1 ❌ 불일치 — 미보정
OT 8 반시계방향 90° 회전 필요 ⚠️ 2개 OT 1 ❌ 불일치 — 미보정
🔑 핵심: 72개 이미지 모두 AI DB에 OT=1(정상)로 저장됨 — 실제로 회전이 필요한 이미지 18개가 보정 없이 배치됨

🔍 코드 분석: 왜 회전 보정이 안 됐나?

핵심 로직 1 — EXIF 메타가 있으면 AI 분석 무시

# image_analysis_service.py:135 def _calc_orientation(ai_ot, original_o): ot_value = ai_ot.get("value", 1) confidence = round(ai_ot.get("confidence", 0), 2) if 1 <= original_o <= 8: # ← EXIF 메타 값이 유효하면 return original_o # ← AI 분석 결과 무시, EXIF 값 그대로 반환 else: if confidence < 0.8: return 1 # AI 확신도 낮으면 정상(1) 반환 return ot_value # AI 확신도 높으면 AI 결과 사용
📌 original_o = Java 백엔드가 AI 서버 호출 시 전달하는 o 파라미터 (이미지의 EXIF 방향값)

핵심 로직 2 — AI 모델은 항상 img_ot=0 으로 이미지 읽음 (EXIF 미적용)

# image_analysis_service.py:49 async def _read_image_for_inference(imageData): ... return SnapsImage.read_imageData( data=bytes_data, img_type='bytes', img_ot=0, # ← EXIF 회전 미적용, raw 픽셀 그대로 AI에 전달 color_model='bgr', cvt_type='cv2', )
📌 AI OT 모델은 이미지의 픽셀만 보고 회전을 예측함 — EXIF 값을 참고하지 않음

최종 처리 흐름

1️⃣ Java → AI 서버 호출 시 o 파라미터 전달 (이미지 EXIF 값)
2️⃣ AI 모델이 raw 픽셀 분석 → OT 예측값 반환
3️⃣ _calc_orientation: o가 1~8이면 EXIF 우선, 아니면 AI 결과 사용
4️⃣ DB 저장 결과: 모든 이미지 OT=1 → EXIF가 유효하게 전달되지 않았거나 AI가 OT=1 예측

🚨 핵심 가설

Java 백엔드가 AI 서버를 호출할 때 o 파라미터로 유효한 EXIF 값(1~8)을 전달하지 않았을 가능성이 높음.
또는 AI 모델이 회전된 이미지를 정상(OT=1)으로 잘못 예측.
→ ELK 로그에서 실제 API 호출 시 전달된 o 파라미터 확인 필요

⚠️ 회전 미보정 이미지 갤러리 (18개)

EXIF 회전 정보가 있으나 AI DB에 OT=1로 저장된 이미지들. 썸네일 클릭 시 원본 열림.

No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074052820.jpg','_blank')" title="원본 보기"> ⚠️
0036833120
EXIF: OT 8: 반시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 3648×2736 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074241025.jpg','_blank')" title="원본 보기"> ⚠️
0036833125
EXIF: OT 8: 반시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 3648×2736 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072379619.jpg','_blank')" title="원본 보기"> ⚠️
0036833019
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072495122.jpg','_blank')" title="원본 보기"> ⚠️
0036833022
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072316517.jpg','_blank')" title="원본 보기"> ⚠️
0036833017
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072955849.jpg','_blank')" title="원본 보기"> ⚠️
0036833049
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073072856.jpg','_blank')" title="원본 보기"> ⚠️
0036833056
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073139960.jpg','_blank')" title="원본 보기"> ⚠️
0036833060
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073012452.jpg','_blank')" title="원본 보기"> ⚠️
0036833052
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073264466.jpg','_blank')" title="원본 보기"> ⚠️
0036833066
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073334270.jpg','_blank')" title="원본 보기"> ⚠️
0036833070
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073889210.jpg','_blank')" title="원본 보기"> ⚠️
0036833110
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074941441.jpg','_blank')" title="원본 보기"> ⚠️
0036833141
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074995843.jpg','_blank')" title="원본 보기"> ⚠️
0036833143
EXIF: OT 6: 시계방향 90° 회전 필요
AI DB: OT 1: 정상 (0°)
실제: 4032×3024 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073823605.jpg','_blank')" title="원본 보기"> ⚠️
0036833105
EXIF: OT 3: 180° 뒤집힘
AI DB: OT 1: 정상 (0°)
실제: 4000×3000 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074107422.jpg','_blank')" title="원본 보기"> ⚠️
0036833122
EXIF: OT 3: 180° 뒤집힘
AI DB: OT 1: 정상 (0°)
실제: 3648×2736 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073750698.jpg','_blank')" title="원본 보기"> ⚠️
0036833098
EXIF: OT 3: 180° 뒤집힘
AI DB: OT 1: 정상 (0°)
실제: 4000×3000 | DB: -1×-1
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073678392.jpg','_blank')" title="원본 보기"> ⚠️
0036833092
EXIF: OT 3: 180° 뒤집힘
AI DB: OT 1: 정상 (0°)
실제: 3648×2736 | DB: -1×-1

🔘 EXIF 없음 이미지 (32개)

EXIF OT=0 — 카메라가 방향 정보를 저장하지 않은 이미지. AI 모델이 판단했지만 모두 OT=1로 반환됨. 실제 회전 상태 육안 확인 필요.

No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072052312.jpg','_blank')" title="원본 보기">
0036833012
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2160×2880 | DB: 2160×2880
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072122214.jpg','_blank')" title="원본 보기">
0036833014
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2160×2880 | DB: 2160×2880
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211072256616.jpg','_blank')" title="원본 보기">
0036833016
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2880×2160 | DB: 2880×2160
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073396574.jpg','_blank')" title="원본 보기">
0036833074
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1050×1400 | DB: 1050×1400
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073446179.jpg','_blank')" title="원본 보기">
0036833079
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1050×1400 | DB: 1050×1400
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073610289.jpg','_blank')" title="원본 보기">
0036833089
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 960×1280 | DB: 960×1280
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211073501781.jpg','_blank')" title="원본 보기">
0036833081
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1050×1400 | DB: 1050×1400
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074302826.jpg','_blank')" title="원본 보기">
0036833126
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 960×1280 | DB: 960×1280
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074359627.jpg','_blank')" title="원본 보기">
0036833127
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 960×1280 | DB: 960×1280
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074415229.jpg','_blank')" title="원본 보기">
0036833129
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1280×960 | DB: 1280×960
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074609234.jpg','_blank')" title="원본 보기">
0036833134
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2160×2880 | DB: 2160×2880
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074662937.jpg','_blank')" title="원본 보기">
0036833137
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2160×2880 | DB: 2160×2880
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074723838.jpg','_blank')" title="원본 보기">
0036833138
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2880×2160 | DB: 2880×2160
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074531233.jpg','_blank')" title="원본 보기">
0036833133
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2160×2880 | DB: 2160×2880
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074873640.jpg','_blank')" title="원본 보기">
0036833140
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2880×2160 | DB: 2880×2160
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211074805439.jpg','_blank')" title="원본 보기">
0036833139
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 2880×2160 | DB: 2880×2160
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211075438252.jpg','_blank')" title="원본 보기">
0036833152
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1400×1050 | DB: 1400×1050
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211075497553.jpg','_blank')" title="원본 보기">
0036833153
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1400×1050 | DB: 1400×1050
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211075549154.jpg','_blank')" title="원본 보기">
0036833154
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1400×1050 | DB: 1400×1050
No Image'" style="width:80px;height:80px;object-fit:cover;border-radius:8px;cursor:pointer" onclick="window.open('https://r142.snaps.com/Upload/Cart15/KOR0031/2026/Q2/20260412/20260412002130/oripq/2026041211075612156.jpg','_blank')" title="원본 보기">
0036833156
EXIF: OT 0: 없음/미설정
AI DB: OT 1: 정상 (0°)
실제: 1400×1050 | DB: 1400×1050

+ 12개 더 있음

📋 요약 및 다음 단계

발견된 문제
EXIF OT=6(12개), OT=3(4개), OT=8(2개) 이미지가 회전 보정 없이 배치됨 — 총 18개
코드 동작
Java가 유효한 EXIF값을 전달 시 AI 무시 → EXIF 우선 적용 (설계대로)
Java가 o=0 전달 시 AI 모델 결과 사용 → AI가 OT=1 예측한 것으로 보임
확인 필요
1. ELK 로그에서 proj 20260412002130 처리 시 o 파라미터 값 확인
2. Java 백엔드가 EXIF를 어떻게 읽어서 전달하는지 확인
3. AI OT 모델 정확도 이슈 여부 확인 (EXIF 없는 32개 이미지)
생성: 2026-04-16 · AI팀 분석 자동화