Skip to content

SmartBrush/Frontend

Repository files navigation

두피어나 두피어나

한번의 터치로 두피를 진단하다.

🪮 프로젝트 개요 및 소개

두피어나는 빗으로 두피 상태를 쉽고 빠르게 진단하고, 맞춤형 두피 케어 솔루션을 제공하는 AI 기반의 두피 분석 서비스입니다. 매일 사용하는 빗을 활용하여 별도의 복잡한 과정 없이 매일 두피 상태를 확인할 수 있도록 도와주는 서비스입니다.

두피어나

💡 개발 배경 및 필요성

1) 프로젝트 개발 동기 및 목적

프로젝트 개발 동기 및 목적
  • 건강보험심사평가원의 조사에 따르면 국내 탈모 환자의 수는 2018년 22만 4,840명에서 2022년 24만 7,915명으로 지속적인 증가 추세로, 현대인들은 두피 염증, 비듬, 지루성 두피염 등 다양한 두피 문제를 호소하고 있습니다.
  • 그러나 정확한 진단을 위해 병원을 방문해야 하는 등 번거로움과 비용, 시간적 제약으로 인해 꾸준한 관리가 어려운 현실입니다.
  • 이러한 문제점을 해결하기 위해 매일 하는 평범한 빗질하드웨어AI를 결합해집에서도 손쉽게 두피 상태를 진단기록하고 개인 맞춤형 관리 솔루션을 제공하는 를 개발하게 되었습니다.

2) 프로젝트 특·장점

  • 별도의 장비나 병원 방문 없이 두피 상태를 간편하게 진단이 가능합니다.
  • 인공지능 분석으로 가성비 높은 맞춤형 두피 관리 솔루션을 제공합니다.
  • 올리브영 등 쇼핑몰과 연동하여 최적의 케어 샴푸 등을 추천해줍니다.
  • 모바일 앱으로 실시간 진단 결과 확인 및 두피 이력 관리가 가능합니다.

⚙️ 주요 기능

1) 🪮 SmartBrush를 활용한 두피 진단

SmartBrush에 내장된 카메라와 센서로 두피 이미지를 촬영하고, AI가 각질·유분·민감도·밀도·두께·탈모를 종합적으로 분석하여 양호, 경증, 중등도, 중증으로 진단합니다. 이를 통해 사용자는 가정에서도 자신의 두피 상태를 빠르고 간단하게 알 수 있습니다.

Smartbrush 결과페이지

2) 🧴 두피 MBTI별 제품 추천

사용자의 두피 진단 결과를 한눈에 이해할 수 있도록 두피 MBTI(트러블 폭풍형, 지성 민감형, 민감 건조형, 지성 비듬형, 건조 비듬형, 건조 트러블형, 깔끔 지성형, 밸런스형)로 유형을 분류합니다. 분류된 MBTI 유형에 맞춰 샴푸, 린스, 트리트먼트/팩, 두피 토닉, 헤어 에센스를 맞춤 추천합니다.

추천제품 추천제품상세페이지

3) ✅ 두피 관련 질문과 진단을 통한 습관 챌린지

두피 관련 질문과 진단을 통해 사용자의 두피 상태와 생활 습관을 분석하고, 결과에 따라 습관 챌린지를 매일 다르게 추천합니다. 챌린지는 LIFESTYLE(수면·스트레스·활동 습관 개선), SCALP(세정·건조·스타일링 루틴), NUTRITION(영양 균형·섭취 가이드) 세 가지 카테고리로 구성되며, 하루에 각 2개씩 제공됩니다.

습관챌린지 질문페이지

4) 📜 두피 월별 레포트

사용자가 매일 SmartBrush로 진단한 누적 진단 데이터를 기반으로 월별 변화 추이를 시각화하여 보여줍니다. 사용자의 진단 데이터가 매일 저장되고 한 달 단위로 쌓이게 되면, 개인별 기준선이 형성되어 더 정확하고 신뢰도 높은 판단이 가능해집니다.

월별레포트

5) 🗓️ 진단 캘린더

두피 분석 캘린더를 통해 사용자는 월별 두피 상태 변화를 한눈에 확인할 수 있습니다. 또한 원하는 날짜를 클릭하면 해당일의 진단 결과를 상세히 확인할 수 있습니다.

달력 달력_진단후

✨ 기대효과 및 활용분야

  • 일상 속 두피 진단 : 빗 하나로 언제 어디서나 간편하게 두피 상태 확인이 가능합니다.
  • 전문 서비스 대체 : 고가 장비 없이 정밀 진단 가능, 비용·시간 부담 해소됩니다.
  • 산업 연계 확장 : 뷰티샵·클리닉·의료기관과 협업 가능한 플랫폼 확장이 가능합니다.
  • 기업 연동 강화 : 쇼핑몰과 연계해 제품 추천 및 구매까지 연결이 가능합니다.
  • 개인화 관리 지원 : 데이터 기반 맞춤 케어와 두피 관리 가이드 제공이 가능합니다.

🛠️ 기술 스택

  • 프론트엔드
    My Skills

  • 백엔드
    My Skills

  • AI
    My Skills

  • 하드웨어
    My Skills

  • 배포 및 관리
    My Skills


👥 팀원

김희원 남시윤 박효진 장다연
@heeone1 @nadomola @phjlia2430 @noeyadd

💡 시스템 구성도

🔹 아키텍처 구조

아키텍처 구조

🔹 하드웨어 구조

하드웨어 설계도 SmartBrush 내부
하드웨어설계도 Smartbrush내부

🎥 작품 소개 영상

시연 영상 보기


🖥️ 핵심 소스코드

UV 측정 및 이미지 자동 업로드

Adafruit_VEML6070 uvSensor = Adafruit_VEML6070();
float uvEMA = 0.0f, meanUV = 0.0f, varUV = 0.0f;
uint16_t baseUV = 0;

void calibrateUV() {
  setIT(IT_8T);
  uint32_t sum = 0;
  for (int i = 0; i < CALI_SAMPLES; ++i) {
    sum += uvSensor.readUV();
    delay(20);
  }
  baseUV = sum / CALI_SAMPLES;
  uvEMA  = baseUV;
  meanUV = baseUV;
  varUV  = fmaxf(5.0f, (float)baseUV * 0.2f);
}

String getUVState(uint16_t uv) {
  float sigma = sqrtf(fmaxf(1.0f, varUV));
  float z = ((float)uv - (float)baseUV) / fmaxf(1.0f, sigma);
  if (z <= 1.0f) return "건성";
  else if (z <= 2.5f) return "보통";
  else return "지성";
}

~~

void loop() {
  uint16_t raw = uvSensor.readUV();
  float sigma = sqrtf(fmaxf(1.0f, varUV));
  float z = ((float)raw - (float)baseUV) / fmaxf(1.0f, sigma);
  float deltaRise = (float)raw - uvEMA;

  if (armed && (z >= Z_ON || deltaRise >= DELTA_ON)) {
    uint16_t medianUV; float burstEMA;
    burstMeasure(medianUV, burstEMA);
    String state = getUVState(medianUV);
    sendUVToServer(medianUV, state);
    captureAndUploadImage();
    armed = false;
    lastTriggerMs = millis();
  } else {
    sampleAmbientSlow(raw);
  }

  delay(IDLE_POLL_MS);
}

두피 진단 AI 코드

from flask import Flask, request, jsonify
import torch
from efficientnet_pytorch import EfficientNet
from torchvision import transforms
from PIL import Image
import numpy as np

torch.serialization.add_safe_globals({'EfficientNet': EfficientNet})

app = Flask(__name__)

# Load all models
model_paths = {
    "미세각질": "model1_full.pt",
    "탈모": "model2_full.pt",
    "모낭사이홍반": "model3_full.pt",
    "모낭홍반농포": "model4_full.pt",
    "비듬": "model5_full.pt",
    "피지과다": "model6_full.pt",
    "모발밀도": "model7_full.pt"
}

models = {}
for name, path in model_paths.items():
    m = torch.load(path, map_location=torch.device('cpu'), weights_only=False)
    m.eval()
    models[name] = m

# Preprocessing
transform = transforms.Compose([
    transforms.Resize([600, 600]),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225])
])

@app.route("/ai", methods=["POST"])
def ai():
    # image 필드로 여러 개 업로드
    files = request.files.getlist('image')
    if not files:
        return jsonify({'error': 'No image provided'}), 400

    # 질환별 확률 누적
    sum_probs = {disease: None for disease in models.keys()}
    valid_count = 0

    with torch.inference_mode():
        for f in files:
            try:
                image = Image.open(f.stream).convert('RGB')
            except Exception:
                # 잘못된 이미지는 평균에서 제외
                continue

            x = transform(image).unsqueeze(0)     # [1, 3, H, W]

            for disease, model in models.items():
                logits = model(x)                  # [1, C]
                prob = torch.softmax(logits[0], dim=0).cpu().numpy()  # [C]

                if sum_probs[disease] is None:
                    sum_probs[disease] = prob.copy()
                else:
                    sum_probs[disease] += prob

            valid_count += 1

    if valid_count == 0:
        return jsonify({'error': 'All images were invalid'}), 400

    # 평균 확률 → 최종 결과
    results = {}
    for disease, s in sum_probs.items():
        mean_prob = s / float(valid_count)       
        pred = int(np.argmax(mean_prob))
        conf = float(mean_prob[pred])
        results[disease] = {
            "class_index": pred,
            "confidence": round(conf, 3)
        }

    return jsonify({
        "count": valid_count,   # 평균에 사용된 유효 이미지 수
        "results": results
    })

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
    #app.run(host="0.0.0.0", port=8000)

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages