■ JITHub 개발일지 57일차
□ TIL(Today I Learned) ::
DRF, 딥러닝_이미지 유화(Painting) 처리 및 게시글 생성
1. Django 구조 설계
- 이미지 생성 기능은 'paintings'라는 App에서 관리한다.
- 생성기능은 딥러닝을 사용하기 위해서 크게 아래와 같은 순서로 구성했다.
1) 유화 스타일 선택(*딥러닝 모델 선택)
2) 이미지 업로드
3) 업로드된 이미지와 스타일(*딥러닝 모델) 정보를 활용하여 이미지 처리
4) 유화를 설명할 수 있는 제목과 내용 정보를 활용하여 DB에 등록
- 간단하게 위의 순서로 코드를 설명할 수 있지만, 실제로 코드를 들어가보면 아래와 같이 복잡한 절차들이 필요했다.
※ 유화 스타일 선택 페이지
- PaintingStyleSelectView 동작 -> 유화 스타일 리스트 Get
- 유화 스타일 선택 -> 스타일 No를 url로 전달
※ 유화 생성 페이지
- 사용할 이미지 업로드
- 제목, 내용 입력
- Create 버튼 클릭
※ Create 버튼 클릭시 동작
- 유화 Style 리스트 Get
- 유화 No와 업로드된 이미지 DB에 저장(1)
- Serializer - 머신러닝 처리(매개변수 : 업로드 이미지, 스타일 no)
- Serializer에서 유효성 검사 후, 제목, 내용, 처리된 그림, 작가, 소유자 정보 DB에 저장(2)
위의 절차들을 보면 DB에 저장하는 절차가 2회 필요했다. 그 중 이미지를 업로드하고 딥러닝 처리하는 부분은 아래의 view에서 처리하고 있다.
urlpatterns = [
#Image style
path('style/', views.PaintingStyleSelectView.as_view(), name='style_select_view'),
path('img/', views.ImageUploadView.as_view(), name='image_upload_view'),
...
]
1) 스타일 선택
- 첫번째 뷰는, 스타일을 선택하는 뷰이며 선택된 스타일은 frontend 페이지에서 '...?id=0' 형식으로 style No를 넘겨주고 있다.
from .models import Painting, STYLE_CHOICES
...
class PaintingStyleSelectView(APIView):
permission_classes = [IsAuthenticated]
#유화 스타일 선택 페이지
@swagger_auto_schema(operation_summary="유화 스타일 선택",
responses={ 200 : '성공', 500:'서버 에러'})
def get(self, requets):
style = [[x, y] for x, y in STYLE_CHOICES]
return Response(style, status=status.HTTP_200_OK)
- 여기서 모든 스타일의 리스틑 위와 같이 가져오고 있는데, 여기서 'STYLE_CHOICE'를 통해 스타일 리스트를 불러와야 한다. 필요한 STYLE은 아래와 같이 models.py에서 미리 정의해두었다.
- 이전과 달리 해봤던 시도는 STYLE 리스트를 DB에 테이블을 만들어 저장하지 않고, models.py에서 튜플형태로 저장해둔 후 db에서는 'choice=STYLE_CHOICES'와 같이 카테고리를 선택하는 타입으로 지정한 점이다. (*참고 : 링크)
# paintings/models.py
STYLE_CHOICES = (
('1','composition'),
('2','la_muse'),
('3','starry_night'),
('4','the_wave'),
('5','candy'),
('6','feathers'),
('7','mosaic'),
('8','the_scream'),
('9','udnie'),
)
class Painting(models.Model):
title = models.CharField('제목', null=True, blank=True, max_length=20)
content = models.TextField('내용', null=True, blank=True, max_length=200)
before_image = models.ImageField('변환 전 사진', blank=True, upload_to='before_img')
after_image = models.ImageField('변환 후 사진', blank=True, upload_to='after_img')
created_at = models.DateTimeField('생성 시간', auto_now_add=True)
updated_at = models.DateTimeField('수정 시간', auto_now=True)
style = models.CharField('스타일', max_length=20, choices=STYLE_CHOICES)
is_auction = models.BooleanField('경매상태', default=False)
author = models.ForeignKey(User, verbose_name='원작자',on_delete=models.PROTECT, null=True, related_name='author_painting' )
owner = models.ForeignKey(User, verbose_name='소유자',on_delete=models.PROTECT, null=True, related_name='owner_painting')
class Meta:
db_table = 'painting'
def __str__(self):
return f'[제목]{self.title}'
2) 유화 처리
- 유화 스타일을 입히는 과정은 딥러닝 기술 중 하나인 OpenCV를 사용하였다.
- 크게 딥러닝은 준비(read) → 전처리(pre-processing) → 추론(inference) → 후처리(post-processing) → 저장(save) 순으로 코드를 짰다.
※ 머신러닝 처리(매개변수 : 업로드 이미지, 스타일 no)
- 스타일 No를 사용하여 모델 불러오기
- 업로드 경로를 통해 이미지 불러오기
- 이미지 전처리(리사이징)
- 이미지 추론(머신러닝 과정, Input → Output)
- 이미지 후처리(이미지 크기, 차원, 형식 변환)
- 이미지 저장(저장되는 현재시간으로 이미지 저장)
- 이미지 저장 경로 리턴
- 이전 프로젝트와 마찬가지로 딥러닝 코드는 django에서 제공하는 시스템이 아니므로 model을 불러오기 위해 아래와 같이 환경설정을 해주어야 했다.
import sys
import os
import django
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project_back.settings')
django.setup()
- 모델 불러오기
: 딥러닝을 진행하기 위해서는 사전에 이미지가 저장되고 경로를 가져와야 하기 때문에 아래 serializer를 통해 이미 이미지는 DB 및 media폴더에 저장시켜두었다.
#이미지 스타일러 serializer
class ImageSerializer(serializers.ModelSerializer):
class Meta:
model = Painting
fields = ('id', 'style', 'before_image',)
def create(self, validated_data):
style_no = validated_data["style"]
before_image = validated_data["before_image"]
painting= Painting(
style=style_no,
before_image=before_image,
)
painting.save()
return painting
- 저장된 정보들을 활용하여 최종적으로 생성할 때 딥러닝이 동작하도록 하는데, 이번에는 딥러닝 부분만 먼저 구현하였다.
def painting_styler(img_url, style_id):
model = STYLE_CHOICES[int(style_id)-1][1]
net = cv2.dnn.readNetFromTorch(f'./paintings/models/{model}.t7')
img = cv2.imread('./media/'+str(img_url))
- 전처리(리사이징)
: 효과적인 이미지처리를 위해서 리사이징 및 mean value를 연산해준다.
# pre-processing
h, w, c = img.shape
img = cv2.resize(img, dsize=(500, int(h / w * 500)))
MEAN_VALUE = [103.939, 116.779, 123.680]
blob = cv2.dnn.blobFromImage(img, mean=MEAN_VALUE)
- 추론
: 전처리된 이미지는 input으로 넣고, output을 추론하는 과정을 진행한다.
# inference
net.setInput(blob)
output = net.forward()
- 후처리
: 계산된 output은 컴퓨터가 읽어들일 수 있도록 후처리를 통해 차원 및 형식 변환을 해준다.
# post-processing
output = output.squeeze().transpose((1, 2, 0))
output += MEAN_VALUE
output = np.clip(output, 0, 255)
output = output.astype('uint8')
- 저장 및 결과 리턴
: 본 함수는 최종적으로 처리된 이미지를 저장하고 경로를 DB에 전달해주어야 한다. 저장될 경로는 저장된 일자를 사용하기 위해서 datetime모듈을 가져오고, media폴더에 saving 되도록 OpenCV의 imwrite를 사용하였다.
: 최종 리턴될 결과는 db에 저장될 데이터이기 때문에 saving_path의 인덱스 8부터 리턴하게 하여 'after_img/...'와 같은 형식으로 db에 저장되도록 전달한다.
: 이 때 저장될 이름을 datetime을 활용하는데 f스트링으로 짰는데, 다양한 포맷 방식들이 있어서 방식 채택에 어려움이 있었지만, 아래와 같이 작성하였다. 예를들면 %m은 month를 나타내고, %M은 minute를 나타내는 점 등이 쉽게 헷갈릴 수 있는 부분이었다.
date = datetime.datetime.now()
saving_path = f'./media/after_img/img_{date:%y%m%d}_{date:%H%M%S}.png'
cv2.imwrite(saving_path, output)
img_path = saving_path[8:]
return img_path
'DEV > Web 개발' 카테고리의 다른 글
Web 개발 :: 딥러닝 이미지 처리(유화제작) 프로젝트 구현_TIL59 (0) | 2022.11.28 |
---|---|
Web 개발 :: 딥러닝 이미지 처리(유화제작) 프로젝트 구현_TIL58 (0) | 2022.11.28 |
Web 개발 :: 딥러닝 이미지 처리(유화제작) 프로젝트 구현_TIL56 (0) | 2022.11.23 |
Web 개발 :: 딥러닝 프로젝트 주제 선정 _TIL55 (0) | 2022.11.23 |
Web 개발 :: DRF 리뷰, 파이썬 and와 &의 차이 _TIL#51 (0) | 2022.11.16 |
댓글