본문 바로가기
DEV/Web 개발

Web 개발 :: 딥러닝 이미지 처리(유화제작) 프로젝트 구현_TIL57

by 올커 2022. 11. 28.

■ 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

 

반응형

댓글