멋쟁이사자처럼 X K-DIGITAL Training - 08.02
파이널 프로젝트 전 마지막 수업내용은 기다리고 기다렸던 파이썬 장고
간단한 로또번호 생성 페이지부터 이미지 업로드와 머신러닝 모델 연결까지 짧은 시간이였지만 파이널프로젝트를 해낼 수 있을 정도까지는 배울 수 있었다.
마지막으로 파이썬 애니웨어에 빠르게 배포하는 법까지!
수업시간에 배포한 웹 서비스는 openCV를 이용한 얼굴 감지 서비스이지만 중요한것은 openCV가 아니라 Django 이기에
장고와 파이썬애니웨어 배포를 중심으로 포스팅 할 예정
[GITHUB] https://github.com/ijo0r98/django-opencv
# 장고를 위한 가상환경은 이곳에 둘 예정
mkdir work_django
cd work_django
# 가상환경을 생성할 폴더
mkdir django_mldl
cd django_mldl
가상환경 생성 및 라이브러리 설치
# 가상환경 관리 라이브러리
pip install virtualenv==16.7.7
# 가상환경 생성
virtualenv django_env
# 가상환경 실행
django_env\Scripts\activate
# 가상환경 종료
deactivate
장고 라이브러리 설치
pip install django==2.2.6
pip freeze # 현재 설치된 라이브러리 리스트 검토
장고 프로젝트 생성
django-admin startproject {project_name}
장고 app 생성
* 하나의 웹 사이트 내에 있는 기능들에 해당 (회원가입, 상품 관련 기능 등)
cd cv_project
python manage.py startapp {app_name}
파일 구성
* static 폴더는 collectstatic 후 생성됨
* media 폴더는 직접 생성
프로젝트 설정
▷ cv_project > settings.py
* DEBUG는 배포시 false로 설정
DEBUG = True # 배포 시 false
INSTALLED_APPS 리스트 상단에 생성한 앱 추가
INSTALLED_APPS = [
'opencv_webapp', # 앱 추가
'django.contrib.admin',
'django.contrib.auth',
...
]
언어, 시간 설정
LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
STATIC 경로 설정
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA 경로 설정 (업로드된 이미지등의 파일을 다룰 때)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_ROOT_URL = '.'
▷ cv_project > urls.py
url 권한 app에게 위임 (전체 url을 app 단위로 나눠서 관리)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
# path(url, include('app_name.urls'))
path('', include('opencv_webapp.urls')), # 앱에게 위임
]
앱 설정
▷ opencv_webapp > urls.py
위에서 위임받은 url 연결
from django.urls import path
from . import views # 같은 폴더 내의 views.py를 import
from django.conf import settings
from django.conf.urls.static import static
app_name = 'opencv_webapp' # 프로젝트 설정에서 app name으로 url 권한 위임
urlpatterns = [
]
# MEDIA
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
▷ cv_project(project) > opencv_webapp(app) > urls.py
path(url, views.function, name='url_name') url과 views의 함수 매핑
* 보통 url, views 함수, url name은 모두 일치하도록 설정
urlpatterns = [
path('', views.index, name='index'),
path('simple_upload/', views.simple_upload, name='simple_upload'),
path('detect_face/', views.detect_face, name='detect_face'),
]
▷ cv_project(project) > opencv_webapp(app) > models.py
python Django ORM, 데이터베이스에 매핑될 테이블 설계
from django.db import models
# Create your models here.
class ImageUploadModel(models.Model):
description = models.CharField(max_length=255, blank=True)
document = models.ImageField(upload_to='images/%Y/%m/%d')
uploaded_at = models.DateTimeField(auto_now_add=True)
- blank=True : 빈 값으로 저장 허용 (views.py에서 활용한 .is_valid() 함수가 검증 진행 시)
- upload_to : 저장될 파일의 경로를 지정 (ex. ‘images/2020/02/21/image.jpg’)
- auto_now_add : 등록 시, 자동으로 저장 시간을 현재 시간으로 세팅
- auto_now : 수정 시, 저장될 때마다 현재 시간으로 갱신
▷ cv_project(project) > opencv_webapp(app) > forms.py
위에서 생성한 모델 기반으로 사용자에게 입력받을 폼 생성
from django import forms
from .models import ImageUploadModel
# simple upload form
class SimpleUploadForm(forms.Form):
title = forms.CharField(max_length=50)
image = forms.ImageField() # file field + image
# description 추가
class ImageUploadForm(forms.ModelForm):
class Meta:
model = ImageUploadModel
fields = ('description', 'document',)
url 매핑 시 작성했던 함수들을 구현하여 사용자에게 보여질 화면 매핑
request 타입 확인
request.method # GET / POST
request에 담긴 post 데이터 확인 - input 태그의 name이 key, 입력받은 값이 value인 dict 형태
request.POST['name'] # <input name="name">
제출된 파일의 원본 확인
request.FILES # <MultiValueDict: {'image': [<InMemoryUploadedFile: ses.jpg (image/jpeg)>]}>
html render
render(request, app_name/.html, data)
▷ cv_project(project) > opencv_webapp(app) > views.py
simple_upload : 단순 이미지 파일 업로드
from django.shortcuts import render, redirect
from .forms import SimpleUploadForm, ImageUploadForm
from django.core.files.storage import FileSystemStorage
from django.conf import settings
def simple_upload(request):
if request.method == 'POST': # POST request
form = SimpleUploadForm(request.POST, request.FILES)
if form.is_valid():
myfile = request.FILES['image'] # 제출된 이미지 객체(image.jpg)
# DB 사용하지 않을 때
fs = FileSystemStorage()
filename = fs.save(myfile.name, myfile) # 이미지 이름과 저장된 파일 객체 반환
uploaded_file_url = fs.url(filename) # '/media/image.jpg'
context = {'form': form, 'uploaded_file_url': uploaded_file_url}
return render(request, 'opencv_webapp/simple_upload.html', context)
else: # GET request
form = SimpleUploadForm()
context = {'form': form}
return render(request, 'opencv_webapp/simple_upload.html', context) # input & label tag
detect_face: 업로드한 이미지에서 opencv를 활용하여 얼굴과 눈의 위치 찾기
from django.shortcuts import render, redirect
from .forms import SimpleUploadForm, ImageUploadForm
from django.core.files.storage import FileSystemStorage
from django.conf import settings
from .cv_functions import cv_detect_face
def detect_face(request):
if request.method == 'POST': # POST request
form = ImageUploadForm(request.POST, request.FILES)
if form.is_valid():
post = form.save(commit=False)
###
# 실제로 저장하기 전 필요한 작업을 추가하여 변경, 추가 가능
###
post.save() # DB에 실제로 form 객체('form')에 채워져 있는 데이터를 저장
imageURL = settings.MEDIA_URL + form.instance.document.name
# 실제로 db에 저장되어있는 경로 '/media/images/2021/07/30/image.jpg'
cv_detect_face(settings.MEDIA_ROOT_URL + imageURL) # machine learning
return render(request, 'opencv_webapp/detect_face.html', {'form':form, 'post':post})
else:
form = ImageUploadForm() # GET reuest
return render(request, 'opencv_webapp/detect_face.html', {'form':form})
▷ cv_project(project) > media > 모델
이미 학습된 모델 제공 https://github.com/opencv/opencv/tree/master/data/haarcascades
▷ cv_project(project) > opencv_webapp(app) > cv_functions.py
openCV 이용한 얼굴과 눈 탐지
from django.conf import settings
import numpy as np
import cv2
def cv_detect_face(path): # ./media/images/2021/07/30/image.jpg'
img = cv2.imread(path, 1) # image read
if (type(img) is np.ndarray):
print(img.shape) # 세로, 가로, 채널
# image resize
resize_needed = False
if img.shape[1] > 640:
resize_needed = True
new_w = img.shape[1] * (640.0 / img.shape[1])
new_h = img.shape[0] * (640.0 / img.shape[1])
elif img.shape[0] > 480:
resized_needed = True
new_w = img.shape[1] * (480.0 / img.shape[0])
new_h = img.shape[0] * (480.0 / img.shape[0])
if resize_needed == True:
img = cv2.resize(img, (int(new_w), int(new_h)))
# Haar-based Cascade Classifier : AdaBoost 기반 머신러닝 물체 인식 모델
baseUrl = settings.MEDIA_ROOT_URL + settings.MEDIA_URL # '.' + '/media/'
face_cascade = cv2.CascadeClassifier(baseUrl + 'haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(baseUrl + 'haarcascade_eye.xml')
# 흑백 이미지로 변경 -> 차원 수 감소
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 얼굴 사각형 좌표
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
# 눈의 위치
eyes = eye_cascade.detectMultiScale(roi_gray)
for (ex, ey, ew, eh) in eyes:
cv2.rectangle(roi_color, (ex, ey), (ex+ew, ey+eh), (0, 255, 0), 2)
cv2.imwrite(path, img) # cv에서 만든 이미지로 바꿈
else:
print('Error occurred within cv_detect_face!')
print(path)
collectstatic 이후 생기는 static 폴더의 css 적용
<link rel='stylesheet', href="{% static 'cv_project/css/styles.css' %}">
▷ cv_project(project) > opencv_webapp(app) > templates > opencv_webapp(app_name) > simple_upload.html
forms.py에서 등록한 폼 자동 생성
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }} <!--p태그로 자동으로 묶어줌-->
<button type="submit">Upload</button>
</form>
업로드 후 저장된 이미지 확인
{% if uploaded_file_url %}
<a>업로드 확인👇🏻</a>
<img src="{{ uploaded_file_url }}">
<p>Uploaded file @ : <a href="{{ uploaded_file_url }}">{{ uploaded_file_url }}</a></p>
{% endif %}
링크 연결 - urls.py에서 등록한 url name
# opencv_webapp > urls.py
path('', views.index, name='index')
<p><a href="{% url 'opencv_webapp:index' %}">Return to home</a></p>
▷ cv_project(project) > opencv_webapp(app) > templates > opencv_webapp(app_name) > detect_face.html
이미지 업로드 폼
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<a style="color:red;">얼굴을 감지할 이미지 선택 후 upload를 눌러주세요</a>
<button type="submit">Upload</button>
</form>
얼굴 감지 결과 확인
{% if post %}
<a>결과 확인👇🏻</a>
<img src="{{ post.document.url }}">
<p>Uploaded file @ : <a href="{{ post.document.url }}">{{ post.document }}</a></p>
{% endif}
데이터베이스 설계 적용
- 마이그레이션 파일 생성 : 모델을 변경 혹은 생성한 변경사항을 마이그레이션으로 저장하고자함
python manage.py makemigrations
- 마이그레이션 적용 : 모델의 변경사항 저장 (*모델 수정 시)
python manage.py migrate
서버 시작
* 종료는 cmd창에서 ctrl+c (window)
python manage.py runserver
[K-DIGITAL] 파이널프로젝트. BEERCRAFT 맥주 추천 서비스(1) 데이터 수집부터 클러스터링까지 (0) | 2021.08.09 |
---|---|
[K-DIGITAL] Django 실습과 pythonanywhere 배포(2) 서비스 배포 (0) | 2021.08.03 |
[K-DIGITAL] 이미지 데이터 처리를 위한 CNN (0) | 2021.08.01 |
[K-DIGITAL] 세미프로젝트3. 딥러닝을 활용한 주차 수요 예측 (0) | 2021.07.26 |
[K-DIGITAL] sklearn / tf 모델 저장 & Keras Callbacks API (0) | 2021.07.16 |
댓글 영역