Djangoで画像処理アプリケーションを作った

#はじめに
* djangoで画像処理アプリケーションを作成しました。
* とりあえずそれらしく動いたので現状をメモ。

#サンプルコード
https://github.com/yakiimo121/image_processing_web_app
#環境
Python 3.6.7 
django 2.1.2
OpenCv 4.0.0
PyTorch 1.0.0
#グレースケールに変換するアプリ
##主な構成
```
gray_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py
│   └ templates
│         └ app1
│             └ index.html
├ media
│   │ documents
│   └ output  
└ myapp
    │ settings.py
    └ urls.py
```
##主なコード
```python:models.py
from django.db import models

class Document(models.Model):
    description = models.CharField(max_length=255, blank=True)
    photo = models.ImageField(upload_to='documents/', default='defo')
    uploaded_at = models.DateTimeField(auto_now_add=True)
    output = models.ImageField(default = 'output/output.jpg')

```
```python:forms.py
from django import forms
from .models import Document

class DocumentForm(forms.ModelForm):
    class Meta:
        model = Document
        fields = ('description', 'photo',)
```
* 一番下の関数を書き換えることによって様々な画像処理が可能です。

```python:views.py
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings

def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)
        input_path = settings.BASE_DIR + obj.photo.url
        output_path = settings.BASE_DIR + "/media/output/output.jpg"
        gray(input_path,output_path)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })


###########ここをカスタマイズ############

def gray(input_path,output_path):
    img = cv2.imread(input_path)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    cv2.imwrite(output_path, img_gray)

######################################
```
```html:index.html
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Upload</title>
    </head>
    <body>
 
        <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit">Upload</button>
        </form>

        <td>{{ obj.description }}</td>
        <!--<td>{{ obj.gray_photo.url }}</td>-->
        <td><img src="{{ obj.output.url }}" width="100" height="100"/></td>
        <td>{{ obj.uploaded_at }}</td>
    </body>
</html>
```
##画面イメージ
<img width="297" alt="スクリーンショット 2019-02-26 1.50.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/344018/9406c3d2-3845-bc94-7245-7e731284c6d1.png">

#超解像画像に変換するアプリ
##主な構成
```
super_resolve_app
│ manage.py
│ db.sqlite3
├ app1
│   │ models.py
│   │ forms.py
│   │ urls.py
│   │ views.py *変更点
│   │ super_resolve.py *変更点
│   │ model.py *変更点
│   │ model_epoch_30.pth *変更点
│   └ templates
│         └ app1
│             └ index.html  
├ media
│   │ documents
│   └ output   
└ myapp
    │ settings.py
    └ urls.py
```
##主なコード
超解像の部分は、以下を参考にしました。
https://github.com/pytorch/examples/tree/master/super_resolution

```python:views.py
from __future__ import print_function
from django.http import HttpResponse
from django.shortcuts import render, redirect
from .forms import DocumentForm
from .models import Document
import cv2
from django.conf import settings
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from .super_resolve import super_resolve


def index(request):
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return redirect('index')
    else:
        form = DocumentForm()
        max_id = Document.objects.latest('id').id
        obj = Document.objects.get(id = max_id)
        
        input = settings.BASE_DIR + obj.photo.url
        output = settings.BASE_DIR + "/media/output/output.jpg"
        super_resolve(input, output)

    return render(request, 'app1/index.html', {
        'form': form,
        'obj':obj,
    })
```
```python:super_resolve.py
import torch
from PIL import Image
from torchvision.transforms import ToTensor
import numpy as np
from django.conf import settings
from .model import Net


def super_resolve(input_url, output_url):
    # Training settings

    input_image = input_url

    img = Image.open(input_image).convert('YCbCr')
    y, cb, cr = img.split()

    model_path = settings.BASE_DIR + '/app1/model_epoch_30.pth'

    the_model = Net(3)
    the_model.load_state_dict(torch.load(model_path))

    img_to_tensor = ToTensor()
    input = img_to_tensor(y).view(1, -1, y.size[1], y.size[0])

    out = the_model(input)
    out = out.cpu()
    out_img_y = out[0].detach().numpy()
    out_img_y *= 255.0
    out_img_y = out_img_y.clip(0, 255)
    out_img_y = Image.fromarray(np.uint8(out_img_y[0]), mode='L')

    out_img_cb = cb.resize(out_img_y.size, Image.BICUBIC)
    out_img_cr = cr.resize(out_img_y.size, Image.BICUBIC)
    out_img = Image.merge('YCbCr', [out_img_y, out_img_cb, out_img_cr]).convert('RGB')

    out_img.save(output_url)
    print('output image saved to ', output_url)

```
##画面イメージ
<img width="293" alt="スクリーンショット 2019-02-26 1.49.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/344018/289f61dd-bbc0-298c-c76c-984693ead8df.png">

#実行方法
```
python manage.py makemigrations
python manage.py migrate
python manage.py runserver (IPアドレス:ポート番号)
```
#注意事項
IPアドレスを指定する場合

```python:settings.py
ALLOWED_HOSTS = ['IPアドレス']
```
#参考記事
https://ymgsapo.com/show-image-imagefield/
https://ymgsapo.com/gray-scale-app/
https://qiita.com/hiroyuki_mrp/items/8b2b78e066f35edbfbfd