⚖️ 1. 1초 만에 확인하는 직관성, 'Before & After' 비교 화면
카메라 화면에 과거 사진을 반투명하게 겹쳐서 완벽한 구도로 사진을 찍는 것까지는 성공했습니다. 하지만 찍고 나서 갤러리 앱을 따로 열어 두 사진을 번갈아 확인하는 건 너무 번거로웠습니다. 눈바디의 핵심은 '변화를 한눈에 비교하는 것'이니까요.
그래서 카메라 화면 상단에 보라색 [⚖️ 비교] 버튼을 만들었습니다. 이 버튼을 누르면 화면이 스르륵 전환되며 좌우 2분할 비교 창이 나타나도록 설계했습니다.
- 왼쪽 (BEFORE): 아까 가이드라인으로 썼던 과거 사진이 자동으로 쏙!
- 오른쪽 (AFTER): 방금 '찰칵' 찍은 따끈따끈한 오늘 사진이 자동으로 쏙!
직접 구현해 놓고도, 사진을 찍자마자 1초 만에 과거와 현재의 몸 상태가 나란히 비교되는 화면을 보니 묘한 쾌감이 느껴졌습니다.
🤖 2. 스인개에서 공부했던 내용을 써볼까? Python AI 서버 연동
비교 화면까지 만들고 나니 갑자기 욕심이 생겼습니다. 저는 현재 스마트인재개발원(스인개)에서 파이썬과 인공지능, 컴퓨터 비전(MediaPipe, YOLO 등)을 공부하고 있습니다.
"단순히 사진만 나란히 보여줄 게 아니라, 방금 찍은 사진을 내 컴퓨터(파이썬)로 보내서 어깨 비대칭이나 골반 틀어짐을 AI로 분석한 결과를 앱에 띄워주면 어떨까?"
안드로이드 앱 안에서 무거운 AI 모델을 직접 돌리는 건 초보자에게 너무 험난한 길이었기에, 앱(프론트엔드)에서 사진을 쏘면 파이썬(백엔드)이 받아서 분석 후 결과를 돌려주는 통신 구조를 짜보기로 했습니다.
안드로이드에 통신 부품 달기 (OkHttp)
앱이 외부 인터넷(서버)과 통신하려면 권한과 통신 라이브러리가 필요했습니다.
제미나이의 도움을 받아 build.gradle.kts에 OkHttp 라이브러리를 추가하고, Multipart 형식으로 이미지를 파이썬 서버로 쏘아 올리는 코드를 작성했습니다.
// 안드로이드 앱에서 파이썬 서버로 사진(이미지) 전송하기
val requestBody = MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart(
"file", "eyebody.jpg",
imageBytes.toRequestBody("image/jpeg".toMediaTypeOrNull())
)
.build()
val request = Request.Builder()
.url("http://10.0.2.2:8000/analyze") // 마법의 IP 주소 (트러블 슈팅 참조)
.post(requestBody)
.build()
🐍 3. FastAPI로 초간단 AI 백엔드 구축하기
앱 쪽 통신 코드를 짰으니, 이번엔 제게 친숙한 VS Code를 열어 파이썬 서버를 만들 차례입니다. FastAPI를 이용해 안드로이드에서 날아오는 사진을 받아주는 초간단 API 서버를 구축했습니다.
# server.py (파이썬 AI 서버)
from fastapi import FastAPI, File, UploadFile
import uvicorn
import cv2
import numpy as np
app = FastAPI()
@app.post("/analyze")
async def analyze_body(file: UploadFile = File(...)):
# 1. 안드로이드 앱이 보낸 눈바디 사진 읽기
contents = await file.read()
nparr = np.frombuffer(contents, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# 2. 이미지 정보 추출 및 AI 분석 로직 (현재는 기본 정보 분석)
height, width, _ = img.shape
avg_brightness = np.mean(img)
analysis_msg = (
f"사진 수신 성공! (해상도: {width}x{height})\n"
f"• 화면 밝기: {avg_brightness:.1f}점\n"
f"• 구도 판정: 이전 눈바디와 촬영 각도가 95% 일치합니다!"
)
return {"result": analysis_msg}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
이곳에 평소 다루던 MediaPipe 관절 추출 코드만 끼워 넣으면 훌륭한 AI 체형 분석 서버가 완성되는 구조입니다!
🚨 4. 트러블 슈팅: "서버 연결 실패!" (localhost의 함정)
서버 코드를 실행하고, 안드로이드 가상 휴대폰(에뮬레이터)에서 당당하게 [🤖 AI 체형 분석] 버튼을 눌렀습니다.
그런데 결과창에 빨간 글씨로 ❌ 서버 연결 실패! (Connection refused) 에러가 떴습니다.
- 현상: 에뮬레이터에서 내 컴퓨터(로컬)에서 켜둔 파이썬 서버(
[http://127.0.0.1:8000](http://127.0.0.1:8000))로 접속 불가. - 원인 분석: 곰곰이 생각해 보니, 안드로이드 에뮬레이터는 컴퓨터 안에서 독립적인 '또 하나의 가상 스마트폰'으로 동작합니다. 따라서 에뮬레이터 안에서
127.0.0.1 (localhost)을 호출하면, 내 윈도우 PC가 아니라 에뮬레이터 자기 자신을 가리키게 되는 치명적인 함정이 있었습니다. - 해결 방법: 제미나이에게 이 문제를 묻자, 안드로이드 에뮬레이터에서 호스트 PC(내 컴퓨터)를 가리키는 마법의 특수 IP 주소가 있다는 것을 알려주었습니다.
바로10.0.2.2입니다. 앱 코드의 URL을[http://10.0.2.2:8000/analyze](http://10.0.2.2:8000/analyze)로 수정했습니다.
수정 후 다시 버튼을 누르는 순간!
앱 화면 하단에 "✅ AI 분석 결과: 사진 수신 성공! 구도 판정: 95% 일치합니다!"라는 텍스트가 거짓말처럼 떴습니다. 안드로이드 프론트엔드와 파이썬 백엔드가 데이터를 주고받는 API 통신을 제 손으로 직접 연결해 낸, 짜릿한 순간이었습니다.
다음 편에 계속...
기능은 모두 완성되었습니다! 대망의 마지막 4편에서는 이 앱을 컴퓨터 가상 화면이 아닌 '내 진짜 스마트폰'에 설치하는 배포 과정과, UI 오류 및 로컬 서버의 한계를 짚어보는 솔직한 회고(Future Work)를 다루어 보겠습니다.
'Projects > 눈바디' 카테고리의 다른 글
| [4편] 내 폰에 진짜 앱 설치하기! 배포 꿀팁과 솔직한 개발 회고 (0) | 2026.10.23 |
|---|---|
| [2편] 텅 빈 화면에 카메라를 띄우다: XML 뼈대 구축과 '투명도 오버레이'의 마법 (0) | 2026.10.23 |
| [1편] AI와 단 2시간 만에 만든 '눈바디 가이드 카메라' 앱 개발기: 기획부터 Gemini의 뜻밖의 각성까지 (0) | 2026.10.23 |