[Project] 닮은 연예인 분류 Django 구현 - (2) Django 웹 페이지 제작

DeMar_Beom·2023년 5월 22일
0

project

목록 보기
3/4

프로젝트 개요

1. 전이학습 활용 연예인 얼굴 분류 모델(.h5)생성

2. Django로 이미지 업로드 시 닮은 연예인을 분류하는 홈페이지 생성

전체적 구조

face
 ┣ mysite
 ┃ ┣ config
 ┃ ┃ ┣ __pycache__
 ┃ ┃ ┃ ┣ __init__.cpython-310.pyc
 ┃ ┃ ┃ ┣ __init__.cpython-39.pyc
 ┃ ┃ ┃ ┣ settings.cpython-310.pyc
 ┃ ┃ ┃ ┣ settings.cpython-39.pyc
 ┃ ┃ ┃ ┣ urls.cpython-310.pyc
 ┃ ┃ ┃ ┣ urls.cpython-39.pyc
 ┃ ┃ ┃ ┣ wsgi.cpython-310.pyc
 ┃ ┃ ┃ ┗ wsgi.cpython-39.pyc
 ┃ ┃ ┣ __init__.py
 ┃ ┃ ┣ asgi.py
 ┃ ┃ ┣ settings.py
 ┃ ┃ ┣ urls.py
 ┃ ┃ ┗ wsgi.py
 ┃ ┣ star
 ┃ ┃ ┣ __pycache__
 ┃ ┃ ┃ ┣ __init__.cpython-310.pyc
 ┃ ┃ ┃ ┣ __init__.cpython-39.pyc
 ┃ ┃ ┃ ┣ admin.cpython-310.pyc
 ┃ ┃ ┃ ┣ admin.cpython-39.pyc
 ┃ ┃ ┃ ┣ apps.cpython-310.pyc
 ┃ ┃ ┃ ┣ apps.cpython-39.pyc
 ┃ ┃ ┃ ┣ forms.cpython-310.pyc
 ┃ ┃ ┃ ┣ models.cpython-310.pyc
 ┃ ┃ ┃ ┣ models.cpython-39.pyc
 ┃ ┃ ┃ ┣ urls.cpython-310.pyc
 ┃ ┃ ┃ ┣ urls.cpython-39.pyc
 ┃ ┃ ┃ ┣ views.cpython-310.pyc
 ┃ ┃ ┃ ┗ views.cpython-39.pyc
 ┃ ┃ ┣ migrations
 ┃ ┃ ┃ ┣ __pycache__
 ┃ ┃ ┃ ┃ ┣ __init__.cpython-310.pyc
 ┃ ┃ ┃ ┃ ┗ __init__.cpython-39.pyc
 ┃ ┃ ┃ ┗ __init__.py
 ┃ ┃ ┣ .DS_Store
 ┃ ┃ ┣ __init__.py
 ┃ ┃ ┣ admin.py
 ┃ ┃ ┣ apps.py
 ┃ ┃ ┣ forms.py
 ┃ ┃ ┣ models.py
 ┃ ┃ ┣ team3_new.h5
 ┃ ┃ ┣ tests.py
 ┃ ┃ ┣ urls.py
 ┃ ┃ ┗ views.py
 ┃ ┣ static
 ┃ ┃ ┣ assets
 ┃ ┃ ┃ ┣ img
 ┃ ┃ ┃ ┃ ┣ .DS_Store
 ┃ ┃ ┃ ┃ ┣ bg-callout.jpg
 ┃ ┃ ┃ ┃ ┣ bg-masthead.jpg
 ┃ ┃ ┃ ┃ ┣ portfolio-1.jpg
 ┃ ┃ ┃ ┃ ┣ portfolio-2.jpg
 ┃ ┃ ┃ ┃ ┣ portfolio-3.jpg
 ┃ ┃ ┃ ┃ ┗ portfolio-4.jpg
 ┃ ┃ ┃ ┣ .DS_Store
 ┃ ┃ ┃ ┗ favicon.ico
 ┃ ┃ ┣ css
 ┃ ┃ ┃ ┣ style.css
 ┃ ┃ ┃ ┗ styles.css
 ┃ ┃ ┣ js
 ┃ ┃ ┃ ┗ scripts.js
 ┃ ┃ ┗ .DS_Store
 ┃ ┣ templates
 ┃ ┃ ┣ index.html
 ┃ ┃ ┗ result.html
 ┃ ┣ .DS_Store
 ┃ ┣ db.sqlite3
 ┃ ┣ manage.py
 ┃ ┗ requirements.txt
 ┗ .DS_Store

프로젝트 목표 및 진행방향

1. 이미지 분류 모델(.h5)파일 장고 구현

2. DB연결 및 EC2서버 배포

- 프로젝트 시작 전 강사님께서 각 팀당 AWS EC2 서버 주소를 공유

프로젝트 시작

django-admin startproject config .
django-admin startapp star

config - settings.py 설정

# settings.py
ALLOWED_HOSTS = ['?.??.???.???']


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrap4',
    'star',
    
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'team3',
        'USER': '????',
        'PASSWORD': '?????',
        'HOST': '?.??.???.???',
        'PORT': '3306'
    }
}
]

STATIC_URL = 'static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
    os.path.join(BASE_DIR, 'static'),
    os.path.join(BASE_DIR, 'static', 'assets'),
    os.path.join(BASE_DIR, 'static', 'assets', 'img'),
    ]

  • DATABASES는 서버에서 실행하는 mysql로 연결
  • ALLOWED_HOSTS는 강사님이 제공해준 EC2서버 주소로 설정
  • STATIC폴더 생성 및 url 설정(기본 static/)
    - static : 이미지 분류 결과 연예인 사진 저장
    - assets-img : html 스타일 jpg 저장
    -css : 기본 style.css 파일 저장

config - urls.py

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('star.urls')), 
]
  • ''로 시작하는 모든 url은 star폴더 안의 urls.py파일 안에서 관리하도록 설정

views.py

import os
from PIL import Image
from .models import Post
from django.shortcuts import render
from django.http import HttpResponse
from .forms import ImageUploadForm
from .models import ImageClassifier,Post
import numpy as np
import glob
# Create your views here.

def classify_image(request):
    if request.method == 'POST':
        form = ImageUploadForm(request.POST, request.FILES)
        if form.is_valid():
            image = form.cleaned_data['image']
            # 모델 경로 설정
            model_path = 'star/team3_new.h5'  # 실제 모델 파일의 경로로 수정
            # 이미지 분류기 초기화
            classifier = ImageClassifier(model_path)
            # 이미지 분류
            result = classifier.classify_image(image)
            Post.objects.create(confidence=result['confidence'], result=result['class_label'])
            return render(request, 'result.html', {'result': result})
    else:
        form = ImageUploadForm()
    return render(request, 'index.html', {'form': form})

def rank(request):
    results = Post.objects.all()
    return render(request, 'ranking.html', {'results': results})

def sub_menu_1(request):
    return render(request, 'sub_menu_1.html')
  • PTL.Image : 이미지 처리 모듈
  • .models.py에서 ImageClassifier, Post 모델 호출
  • .forms.py에서 ImageUploadForm 폼 호출

classify_image 함수 생성

  • 이미지 분류 과정을 처리하기 위한 함수
  • 이미지 파일을 POST 방식으로 받았을 때 ImageUploadForm 폼이 유효할 때 폼의 클린 데이터에서 이미지를 가져옴
  • model_path 변수의 이미지 분류기 모델 파일 경로로 설정
  • ImageClassifier(model_path)를 classifier객체로 저장하고 classify_image메서드를 호출하여 이미지를 매개변수로 전달
  • 분류 결과는 result에 저장되고 결과로 도출된 확률과 연예인 이름은 db에 저장 후 result.html템플릿에 렌더링되서 분류 결과 표시
  • sub_menu_1.html 템플릿을 렌더링

models.py

import tensorflow as tf
from django.db import models
from PIL import Image
import numpy as np
import os

class ImageClassifier:
    def __init__(self, model_path):
        self.model = tf.keras.models.load_model(model_path)
    def classify_image(self, image):
        class_label=['강해린',
'김채원',
'뉴진스 하니',
'안유진',
'아린',
'장원영',
'카즈하',
'차은우',
'방탄소년단 뷔',
'정준하',
 '정형돈',
 '서강준',
 '카리나',
 '마동석',
 '박보검',
 '손석구',
 '아이브 가을',
 '이광수',
 '침착맨',
 '르세라핌 사쿠라',]
        img = Image.open(image)
        img = img.resize((224, 224))  # 모델에 맞는 이미지 크기로 조정
        img = np.array(img) / 255.0  # 이미지 정규화
        img = np.expand_dims(img, axis=0)  # 배치 차원 추가
        predictions = self.model.predict(img)
        pred_class = np.argmax(predictions, axis=1)
        class_index = np.argmax(predictions[0])  # 가장 높은 확률을 가진 클래스 인덱스
        confidence = predictions[0][class_index]  # 분류 확률
        result = class_label[pred_class[0]]
        result = {
            'class_label': result,
            'confidence': confidence,
        }
        return result

class Post(models.Model):
    confidence = models.FloatField()
    result = models.CharField(max_length=100)

    def __str__(self):
        return self.result
  • tensorflow(딥러닝 프레임워크), PIL.Image(이미지 처리),numpy 등 모듈 호출

ImageClassifer 클래스 생성

  • model_path(star/team3_new.h5)를 받아서 해당 경로의 모델을 로드 후 self.model에 저장
  • classify_image 메서드는 이미지를 분류하는 역할로 이미지를 받아, 사전에 정의된 클래스 레이블을 사용하여 이미지를 분류
  • img로 image를 받아 VGG에 적합한 244x244로 크기를 재조정하고 0~1사이로 정규화
  • 4차원 배열로 만들기 위해 배치차원을 추가하고, 예측값을 얻어 가장 높은 확률을 가진 클래스 인덱스를 찾고 해당 클래스의 레이블과 분류 확률을 반환

Post 클래스 생성

  • 데이터베이스의 Post 모델을 생성하여 확률(confidence)은 실수, 이름은(result) 문자열로 저장하고, str메서드로 result필드값을 반환

forms.py

from django import forms
class ImageUploadForm(forms.Form):
    image = forms.ImageField()
  • 이미지를 입력받는(ImageField) form 생성

star-urls.py

from django.urls import path, include
from . import views
from star.views import classify_image

app_name = 'star'

urlpatterns = [
    path('', classify_image, name='classify_image'),
    path('sub_menu_1/', views.sub_menu_1, name='sub_menu_1'), 
]
  • app_name을 star로 설정하고 views.py에서 classify_image 함수 호출
  • 'http://도메인/' url에 접속하면 'classify_image' 함수가 실행되고 패턴이름은 함수 이름과 동일하게 설정
  • 'http://도메인/sub_menu_1' url에 접속 시, sub_menu_1 함수 실행

templates 설정

index.html

        <nav id="sidebar-wrapper">
            <ul class="sidebar-nav">
                <style>
                    .sub-menu {
                        display: none;
                    }
                    .sidebar-nav-item:hover .sub-menu {
                        display: block;
                    }
                </style>                
                <li class="sidebar-nav-item"><a href="{% url 'star:sub_menu_1' %}">About</a>
                </li>
                <li class="sidebar-nav-item"><a href="{% url 'star:classify_image' %}">닮은꼴 찾기</a></li>
            </ul>
        </nav>
  • sub_menu와 sidebar쪽에 스타일을 설정하고,sidebar_nav_item 쪽에 sub_menu1와 classify_image함수로 연결되는 url 지정
<body>
    <h5 style="text-align: center;"> ※ '.png' 파일은 안됩니다! ※</h5>
    <form method="POST" enctype="multipart/form-data" style="text-align: center;">
        {% csrf_token %}
        {{ form }}
        <div class="button-container">
            <button type="submit" class="btn btn-primary btn-xl">이미지 분류하기</button>
        </div>
    </form>
</body>
  • form태그는 이미지를 업로드하여 분류하기 위한 폼을 표시하고, method 속성은 POST로 설정되어 잇어 폼 데이터는 POST요청으로 서버에 전송, enctype속성은 multipart/form-data로 설정되어 있어 파일 업로드를 지원

result.html

<!-- result.html -->
{%load static%}
<!DOCTYPE html>
<html>
<header>
	<meta charset="UTF-8">
	<title>분류 결과</title>
	<style>
		body {
			display: flex;
			flex-direction: column;
			justify-content: top center;
			align-items: center;
			height: 100vh;
			text-align: center;
		}
		.return-button {
			display: inline-block;
			padding: 10px 20px;
			background-color: #006242;
			color: white;
			text-decoration: none;
			border-radius: 5px;
			font-size: 16px;
			margin-top: 20px;
		}

		.return-button:hover {
			background-color: #4CAF50;
		}

		.profile-image {
            width: 400px; /* 원하는 너비로 조정 */
            height: auto; /* 너비에 맞춰 자동으로 높이 조정 */
        }
		</style>
	</style>
	
</header>

<body>
   

    <h1>분류 결과</h1>
    <p>예측 결과: 대박 미친 {{ result.class_label }} 입니다...</p>
    <img class="profile-image" src="{% static result.class_label|add:'.jpg' %}">

    <p><a href="{% url 'star:classify_image' %}" class="return-button">돌아가기</a></p>
</body>
{% comment %} 
<body>
	<h1>분류 결과</h1>
	<p>예측 결과: {{ result }}</p>
	<img class="profile-image" src="{% static result.class_label|add:'.jpg' %}">

	<p><a href="http://127.0.0.1:8000/star/classify/">돌아가기</a></p>
</body>
</html> {% endcomment %}
  • {{result.class_label}}에서 Django뷰에서 전달된 result의 class_label 속성을 출력
  • src 속성에 result.class_label 변수에 .jpg확장자를 추가한 경로가 들어감

VGG16모델에서 .png파일을 인식하지 못하는 이유

  • VGG16모델은 RGB이미지를 입력으로 사용하고, png파일은 RGBA형식으로 저장(=이미지에 투명도 채널을 추가하는 것)
  • VGG16모델은 투명도 채널을 처리할 수 없어 .png파일을 인식하지 못함

해결방법

  • .png파일을 RGBA에서 RGB형식으로 변경
  • 예시코드
    from PIL import Image
    image = Image.open('image.png')
    image = image.convert('RGB')
    image.save('image.jpg', 'JPEG')
<!-- sub_menu_1.html -->
<!DOCTYPE html>
<html>
<head>
    <title>아이템 선정</title>
    <!-- 필요한 스타일시트 및 스크립트 태그를 추가하세요 -->
    <style>
         body {
            background-image: url('/static/assets/img/bg-masthead.jpg');
            /* background-repeat: no-repeat; */
            background-size: cover;
        }
        .center-text {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
            height: 100vh;
        }
        .container h1 {
            font-size: 48px;
            /* 화면 전체 높이에 맞게 조절 */
        }
        .header-container {
            text-align: center;
            margin-top: 50px;
        }
        .split-container {
            display: flex;
            justify-content: center;
            border-top: 1px solid black;
            flex-wrap: wrap;
            position: relative;
        }
        .split-container::before {
            content: "";
            width: 1px;
            background-color: black; /* 세로줄 색상 */
            position: absolute; /* 절대적 위치 설정 */
            top: 240px; /* 세로줄이 가로줄 위에 위치하도록 설정 */
            bottom: -400px; /* 세로줄이 가장 아래까지 표시되도록 설정 */
            left: 50%; /* 가운데로 위치하도록 설정 */
            transform: translateY(-50%); /* 세로줄을 정중앙에 위치시키도록 설정 */
            margin-top: 50px; /* 상단 여백 조정 */
        }
        .split-container .col {
            flex: 1;
            padding: 20px;
        }
        body, html {
            height: 100%;
            margin: 0;
            display: flex;
            flex-direction: column;
        }
        .content {
            flex: 1;
        }
    </style>
    
    
</head>

<body>
    <div class="header-container">
        <h1 >프로젝트 Face</h1>
        <h3 class="mb-5"><em>딥러닝을 이용하여 학습시킨 모델을 활용하여<br>닮은 유명인을 찾아주는 홈페이지 만들기</em></h3>
    </div>
    <div class="split-container">
        <div class="col" style="background-color: white;">
            <h2 style="text-align: center;">프로젝트명칭: Face</h2>
            <p>개발 인원: 6명</p>
            <p>개발 기간: 2023.05.12 - 2023.05.18</p>
            <p>간단한 소개: 딥러닝을 이용하여 학습시킨 모델을 홈페이지에 적용하여 사용자들이 사진을 올리면 닮은 연예인을<br>        보여주도록 함</p>
            <p>개발 언어: python</p>
            <p>형상 관리 틀: GitHub</p>
            <p>데이터베이스: SQLite</p>
            
        </div>
            <!-- 왼쪽 내용 -->
        <div class="col">
            <h2 style="text-align: center;">DB 설계</h2>
            <img src="/static/DB.jpg" alt="DB 설계 이미지" width="700">
        </div>
    </div>
</body>

</html>

구현 이미지


현재 강사님께서 주신 서버가 내려가서 이미지가 부족하네요..
향후 추가하도록 하겠습니다.

0개의 댓글