고급 YOLO 모델 및 Spring Boot 기반 반려동물 품종 식별 및 분석 플랫폼

고급 YOLO 모델 및 Spring Boot 기반 반려동물 품종 식별 및 분석 플랫폼

본 프로젝트는 최신 딥러닝 기술과 현대적인 웹 개발 프레임워크를 결합하여 반려동물 품종을 정밀하게 식별하고 분석하는 지능형 플랫폼을 구축하는 것을 목표로 합니다. 특히, 빠르게 발전하는 YOLO 계열의 객체 탐지 모델(YOLOv8, YOLOv10, YOLOv11, YOLOv12)들을 핵심 엔진으로 활용하여 12가지 고양이 품종과 25가지 강아지 품종을 포함한 총 37가지 특정 반려동물 품종을 고도로 정확하게 인식할 수 있는 시스템을 설계했습니다. 백엔드는 Spring Boot 프레임워크를 기반으로 구축되었으며, 프론트엔드와의 분리된 아키텍처를 채택하여 높은 유지보수성, 확장성, 그리고 우수한 사용자 경험을 제공합니다.

단순한 식별 도구를 넘어, 이 시스템은 데이터 관리, 지능형 분석, 그리고 사용자 상호작용이 통합된 종합적인 솔루션입니다. 주요 기능으로는 이미지, 비디오 스트림, 그리고 실시간 카메라 피드를 통한 다중 탐지 모드 지원; 탐지 결과에 대한 풍부한 배경 설명을 제공하는 DeepSeek 대규모 언어 모델 기반 지능형 분석 모듈; 탐지 통계와 모델 성능을 시각적으로 보여주는 데이터 대시보드; 그리고 사용자 등록/로그인, 개인 정보 관리 및 관리자 백엔드 제어를 포함하는 사용자 관리 시스템이 있습니다. 모든 탐지 기록 및 사용자 데이터는 MySQL 데이터베이스에 영구적으로 저장되어 전체 프로세스에 대한 데이터 추적 및 관리가 가능합니다.

다양한 버전의 YOLO 모델을 통합하고 비교함으로써, 이 프로젝트는 실용적인 반려동물 식별 애플리케이션을 제공할 뿐만 아니라, 미세 분류(fine-grained classification) 작업에서 객체 탐지 모델의 성능 비교 및 선택을 위한 실질적인 기반을 제공합니다. 최종적으로 본 시스템은 알고리즘부터 애플리케이션, 데이터부터 통찰력까지의 완전한 순환을 구현하며, 딥러닝 기술과 웹 엔지니어링 개발의 결합이 실제 문제를 해결하는 데 있어 거대한 잠재력을 가지고 있음을 보여줍니다.

시스템 핵심 기능 개요

본 시스템은 다양한 핵심 모듈로 구성되어 사용자에게 포괄적인 반려동물 품종 식별 및 관리 기능을 제공합니다.

  • 사용자 인증 및 관리: 안전한 비밀번호 검증과 MySQL 데이터베이스 저장을 지원하는 사용자 로그인 및 회원가입 기능. 관리자는 모든 사용자 계정에 대한 CRUD(생성, 읽기, 업데이트, 삭제) 작업을 수행할 수 있습니다.
  • 다중 YOLO 모델 지원: YOLOv8, YOLOv10, YOLOv11, YOLOv12 모델 간의 전환을 통해 사용자는 필요에 따라 최적의 탐지 성능을 선택할 수 있습니다.
  • 정보 및 데이터 시각화: 탐지 결과 및 시스템 운영 관련 통계 데이터를 직관적인 대시보드 형태로 제공하여 한눈에 파악할 수 있도록 합니다.
  • AI 분석 기능 (DeepSeek 연동): DeepSeek 대규모 언어 모델과의 통합을 통해 탐지된 품종에 대한 상세한 특성, 습성, 관리 요령 등 심층적인 AI 분석 결과를 제공합니다.
  • 다양한 탐지 모드:
    • 이미지 탐지: 사용자가 업로드한 이미지를 분석하여 품종을 식별합니다.
    • 비디오 탐지: 업로드된 비디오 파일을 프레임별로 분석하고, 식별 결과가 표시된 비디오를 생성합니다.
    • 실시간 카메라 탐지: 웹 브라우저를 통해 사용자 카메라에 접근하여 실시간으로 품종을 탐지하고 피드백을 제공합니다.
  • 탐지 기록 관리: 이미지, 비디오, 실시간 카메라 탐지 등 모든 분석 작업의 기록을 MySQL 데이터베이스에 저장하고, 사용자가 이력을 검색, 조회, 관리할 수 있도록 합니다.
  • 개인 설정: 사용자는 개인 정보(이름, 아바타, 비밀번호 등)를 수정하고 관리할 수 있는 개인 센터를 이용할 수 있습니다.

데이터 관리 모듈 (MySQL 테이블 설계)

시스템의 모든 데이터는 MySQL 데이터베이스에 영구적으로 저장됩니다. 주요 테이블은 다음과 같습니다:

  • users - 사용자 정보 테이블
  • image_detections - 이미지 탐지 기록 테이블
  • video_detections - 비디오 탐지 기록 테이블
  • camera_detections - 실시간 카메라 탐지 기록 테이블

YOLO 모델 개요

YOLO(You Only Look Once)는 단일 신경망을 사용하여 이미지에서 객체를 빠르게 탐지하는 실시간 객체 탐지 알고리즘입니다. YOLO 시리즈는 속도와 정확도 사이의 균형을 지속적으로 개선해왔습니다.

YOLOv8

2023년 Ultralytics에서 출시된 YOLOv8은 이전 버전의 발전을 기반으로 최첨단 성능을 제공합니다. YOLOv8의 주요 특징은 다음과 같습니다:

  • 향상된 백본 및 넥 아키텍처: 특징 추출 및 객체 탐지 성능을 개선했습니다.
  • 앵커-프리 분리형 헤드: 앵커 기반 방식 대비 정확도와 효율성을 높였습니다.
  • 최적화된 정확도-속도 균형: 다양한 실시간 객체 탐지 작업에 적합합니다.

YOLOv10

칭화대학교 연구원들이 개발한 YOLOv10은 이전 YOLO 버전의 후처리 및 모델 아키텍처 한계를 해결하기 위해 NMS(비최대 억제)를 제거하고 모델 구성 요소를 최적화했습니다. 이는 계산 오버헤드를 현저히 줄이면서도 최첨단 성능을 달성합니다.

  • NMS 없는 학습: 일관된 이중 할당(Consistent Dual Assignment)을 활용하여 추론 지연을 줄였습니다.
  • 전체적인 모델 설계: 경량 분류 헤드, 공간 채널 분리 다운샘플링 등 효율성과 정확성을 모두 고려한 포괄적인 최적화를 특징으로 합니다.
  • 향상된 모델 기능: 대형 커널 컨볼루션과 부분적 자기 주의 모듈을 결합하여 성능을 향상시켰습니다.

YOLOv11

Ultralytics YOLO 시리즈의 최신 반복 중 하나인 YOLOv11은 이전 YOLO 버전의 중요한 개선 사항을 기반으로 아키텍처 및 훈련 방법론에서 상당한 발전을 이루었습니다.

  • 강화된 특징 추출: 개선된 백본 및 넥 아키텍처를 채택하여 보다 정밀한 객체 탐지 능력을 제공합니다.
  • 최적화된 효율성 및 속도: 향상된 아키텍처와 훈련 프로세스를 통해 처리 속도가 빨라지면서도 정확도와 성능의 균형을 유지합니다.
  • 높은 정확도와 적은 파라미터: YOLOv11m은 YOLOv8m보다 22% 적은 파라미터를 사용하면서도 COCO 데이터셋에서 더 높은 mAP(평균 정밀도)를 달성했습니다.

YOLOv12

YOLOv12는 기존 CNN 기반 방식과 차별화되는 어텐션 중심 아키텍처를 도입하면서도 실시간 추론 속도를 유지합니다. 새로운 어텐션 메커니즘과 네트워크 아키텍처를 통해 최첨단 객체 탐지 정확도를 달성했지만, 무거운 어텐션 모듈로 인해 훈련 불안정성, 메모리 소비 증가, CPU 처리량 저하 등의 문제가 발생할 수 있어, Ultralytics는 대부분의 프로덕션 작업에 YOLOv11을 권장합니다.

  • 영역별 어텐션 메커니즘: 특징 맵을 여러 영역으로 나누어 대규모 수용 필드를 효율적으로 처리하며 계산 비용을 크게 절감합니다.
  • 잔차 효율 계층 집계 네트워크 (R-ELAN): ELAN 기반의 개선된 특징 집계 모듈로, 특히 대규모 어텐션 모델에서 최적화 문제를 해결하도록 설계되었습니다.
  • 최적화된 어텐션 메커니즘 아키텍처: FlashAttention 사용, 위치 인코딩 제거, MLP 비율 조정 등을 통해 YOLO 프레임워크와의 호환성과 효율성을 높였습니다.

모델 학습 코드 예시

다음은 Ultralytics 라이브러리를 사용하여 YOLO 모델을 학습시키는 Python 코드의 예시입니다. 실제 배포 환경에 따라 모델 파일 경로, 데이터셋 설정, 학습 파라미터 등을 조정할 수 있습니다.

# -*- coding: utf-8 -*-
# 프로젝트 요구사항에 맞춰 모델 가중치와 데이터셋 경로를 조정하세요.
# Ultralytics YOLO 모델 버전 선택 가이드:
#  - nano (n): 경량화된 모델, 임베디드 장치에 적합 (빠르지만 낮은 정확도).
#  - small (s): 소형 모델, 실시간 처리 작업에 최적화.
#  - medium (m): 중간 크기 모델, 속도와 정확도 균형 유지.
#  - large (l): 대형 모델, 높은 정확도가 요구되는 작업에 적합.
#  - xlarge (x): 초대형 모델, 최고 정확도를 목표로 할 때 사용.

from ultralytics import YOLO

if __name__ == '__main__':
    # 사전 학습된 모델 파일 경로 지정
    pretrained_model_file = 'models/yolo_v12_s.pt' # 예시: YOLOv12-small 모델
    # 데이터셋 구성 파일 (YAML 형식) 경로 지정
    dataset_configuration = 'datasets/pet_breeds.yaml'

    # YOLO 모델 인스턴스 초기화
    detection_model = YOLO(pretrained_model_file)

    # 모델 학습 시작
    training_results = detection_model.train(
        data=dataset_configuration,
        epochs=300,             # 학습 에폭 수
        batch=32,               # 배치 크기
        device='0',             # 사용할 GPU 장치 ID (CPU 사용 시 'cpu' 또는 '0' 제거)
        workers=4,              # 데이터 로딩에 사용할 워커 수
        project='training_runs',# 학습 결과가 저장될 상위 디렉토리
        name='pet_breed_detection_experiment' # 현재 학습 세션의 이름
    )

프론트엔드 코드 예시

아래는 Vue.js로 구현된 프론트엔드 이미지 탐지 인터페이스의 일부 코드입니다. 사용자가 모델을 선택하고 이미지를 업로드하여 분석 결과를 확인할 수 있도록 구성되어 있습니다.

<template>
  <div class="pet-detection-app" v-loading="appState.isLoading">
    <!-- 애플리케이션 상단 바 -->
    <header class="app-header">
      <div class="app-logo">
        <i class="icon-camera"></i>
        <span>PetBreed Vision</span>
      </div>
      <div class="user-profile">
        <el-avatar :size="32" :src="userInfo.profileImage" />
        <span class="username">{{ userInfo.userName }}</span>
      </div>
    </header>

    <main class="content-area">
      <!-- 왼쪽 제어 패널 -->
      <aside class="control-panel">
        <section class="panel-group">
          <h3 class="group-title">식별 설정</h3>
          <div class="setting-item">
            <label>모델 선택</label>
            <el-select v-model="selectedModel" placeholder="감지 모델 선택" size="large">
              <el-option
                v-for="modelOption in appState.availableModels"
                :key="modelOption.value"
                :label="modelOption.label"
                :value="modelOption.value"
              />
            </el-select>
          </div>
          <div class="setting-item">
            <label>AI 분석 도구</label>
            <el-select v-model="selectedAIHelper" placeholder="AI 분석 도구 선택" size="large" @change="fetchData">
              <el-option
                v-for="aiOption in appState.aiAssistants"
                :key="aiOption.value"
                :label="aiOption.label"
                :value="aiOption.value"
              />
            </el-select>
          </div>
          <div class="setting-item">
            <label>정확도 임계값: {{ (confidenceThreshold / 100).toFixed(2) }}</label>
            <el-slider v-model="confidenceThreshold" :format-tooltip="formatSliderTooltip" show-stops :max="100" :step="5" />
          </div>
          <div class="action-buttons">
            <el-button type="primary" @click="startDetection" class="detect-button">
              <i class="icon-play"></i>
              분석 시작
            </el-button>
            <el-button @click="resetInputs" class="clear-button">
              <i class="icon-refresh"></i>
              초기화
            </el-button>
          </div>
        </section>

        <section class="panel-group">
          <h3 class="group-title">최근 기록</h3>
          <div class="history-display">
            <div v-for="(record, idx) in appState.recentHistory" :key="idx" class="history-entry">
              <div class="entry-time">{{ record.timestamp }}</div>
              <div class="entry-result">{{ record.detectionSummary }}</div>
            </div>
            <div v-if="appState.recentHistory.length === 0" class="empty-message">
              표시할 기록이 없습니다.
            </div>
          </div>
        </section>
      </aside>

      <!-- 중앙 콘텐츠 영역 -->
      <div class="main-content-panel">
        <section class="upload-area">
          <el-card class="upload-card">
            <template #header>
              <div class="card-header-content">
                <span>이미지 업로드</span>
                <el-button type="text" @click="viewExample">예시 보기</el-button>
              </div>
            </template>
            <el-upload
              v-model="appState.uploadedFile"
              ref="imageUploader"
              class="image-upload-component"
              action="http://localhost:9999/api/files/upload"
              :show-file-list="false"
              :on-success="handleImageUploadSuccess"
              drag
            >
              <div class="upload-zone">
                <el-icon v-if="!uploadedImageUrl" class="upload-plus-icon">
                  <Plus />
                </el-icon>
                <img v-else :src="uploadedImageUrl" class="preview-image" />
                <div v-if="!uploadedImageUrl" class="upload-instructions">
                  <p>파일을 여기에 드롭하거나 <em>클릭하여 업로드</em></p>
                  <p class="upload-hint">JPG, PNG 형식 지원, 최대 10MB</p>
                </div>
              </div>
            </el-upload>
          </el-card>
        </section>

        <section class="analysis-results" v-if="appState.analysisOutput.primaryLabel">
          <el-card class="results-card">
            <template #header>
              <div class="card-header-content">
                <span>분석 결과</span>
                <el-button type="primary" @click="() => exportReport('detection_report_id', '품종_식별_보고서')" size="small">
                  <i class="icon-download"></i>
                  보고서 내보내기
                </el-button>
              </div>
            </template>
            <div class="results-display">
              <div class="summary-metrics">
                <div class="metric-item">
                  <div class="metric-icon result-icon"></div>
                  <div class="metric-details">
                    <div class="metric-label">식별된 품종</div>
                    <div class="metric-value highlight">{{ appState.analysisOutput.primaryLabel || '-' }}</div>
                  </div>
                </div>
                <div class="metric-item">
                  <div class="metric-icon confidence-icon"></div>
                  <div class="metric-details">
                    <div class="metric-label">신뢰도</div>
                    <div class="metric-value accent">{{ appState.analysisOutput.confidenceScore || '-' }}</div>
                  </div>
                </div>
                <div class="metric-item">
                  <div class="metric-icon time-icon"></div>
                  <div class="metric-details">
                    <div class="metric-label">분석 시간</div>
                    <div class="metric-value">{{ appState.analysisOutput.processingTime ? `${appState.analysisOutput.processingTime} 초` : '-' }}</div>
                  </div>
                </div>
              </div>

              <div class="detailed-table">
                <h4>상세 분석 테이블</h4>
                <el-table :data="appState.detailedResults" style="width: 100%">
                  <el-table-column prop="label" label="예측 품종" align="center" />
                  <el-table-column prop="confidence" label="신뢰도" align="center" />
                  <el-table-column prop="timeTaken" label="소요 시간(초)" align="center" />
                </el-table>
              </div>
            </div>
          </el-card>
        </section>
      </div>

      <!-- 오른쪽 AI 추천 영역 -->
      <aside class="ai-recommendation-panel" v-if="appState.analysisOutput.aiRecommendation">
        <section class="panel-group">
          <h3 class="group-title">AI 추천 정보</h3>
          <div class="ai-content">
            <div v-html="appState.analysisOutput.aiRecommendation" class="markdown-renderer"></div>
          </div>
          <div class="recommendation-actions">
            <el-button type="text" @click="copyRecommendation">
              <i class="icon-copy"></i>
              내용 복사
            </el-button>
            <el-button type="text" @click="saveRecommendation">
              <i class="icon-save"></i>
              내용 저장
            </el-button>
          </div>
        </section>
      </aside>
    </main>

    <!-- 하단 상태 바 -->
    <footer class="app-status-bar">
      <div class="status-indicator">
        <i class="icon-system-status"></i>
        <span>시스템 상태: 정상</span>
      </div>
      <div class="status-indicator">
        <i class="icon-update-time"></i>
        <span>최종 업데이트: {{ currentSystemTime }}</span>
      </div>
    </footer>
  </div>
</template>

태그: YOLOv8 YOLOv10 YOLOv11 YOLOv12 객체_탐지

6월 24일 22:20에 게시됨