본문 바로가기
[ 빅데이터 ]

[빅데이터] 홈페이지 만들기(3) : 파이썬으로 파일 업로드 앱 만들기(cnn, 이미지분류)

by 히앤님 2020. 10. 17.
반응형
SMALL

스키장에서 물건을 주웠다. 그 물건을 분실물센터에 올려야하는데, 이미지를 올려야 한다. 어떤걸 개발해야할까?

 

1) 분실물 카테고리

2) 클라이언트가 사용할 앱

3) 올리는 순간 위치도 찍도록

4) 기타 등등

 

가장 중요한 것은 물건을 찾거나 찾아줄 때를 위한 알바생이 필요하다.

다행히 우리에게는 이중분류 또는 다중분류로 불리는 알고리즘 친구가 있다.

이번엔 분류 알고리즘을 써서 훈련 -> 머신러닝까지는 안하고, 준비된 파일을 이용해서 분류 앱만 만들어 보도록 하자.

 

준비된 파일에는 이미지 분류를 위한 h5 파일과 json 파일이 있다.

 

▼파일 받기

 


[ fileup  웹 페이지 기능 구현하기 ]


#자세한 세팅은 앞에 포스팅 참조

1. fileup 앱 만들기

늘 하던대로 fileup > templates > fileup > upform1.html 파일 생성

python manage.py startapp fileup

2. upform1.html 파일 만들기

3. 뷰 추가(view.py)

4. urls.py 만들고 내용 추가

5. config/setting 추가

6. config/urls 추가

7. 서버 구동 및 upform1.html 파일 열기

 

기본 세팅 끝!


본격적으로 첫 페이지의 파일 업로드 폼을 만들러 가자.


8. catdog 테이블 생성

개나 고양이의 별명(aname), 작성자, 카테로리, 데이터를 추가하기 위한 (cont clob) 등등으로 이루어져 있다.

▼clob란?

더보기

CLOB 이란?

사이즈가 큰 데이터를 외부 파일로 저장하기 위한 데이터 타입이다.

 

  • 문자열 데이터를 DB 외부에 저장하기 위한 타입이다.
  • CLOB 데이터의 최대 길이는 외부 저장소에서 생성 가능한 파일 크기이다.
  • CLOB 타입은 SQL 문에서 문자열 타입으로 입출력 값을 표현한다. 즉, CHAR(n), VARCHAR(n), NCHAR(n), NCHAR VARYING(n) 타입과 호환된다. 단, 명시적 타입 변환만 허용되며, 데이터 길이가 서로 다른 경우에는 최대 길이가 작은 타입에 맞추어 절삭(truncate)된다.
  • CLOB 타입 값을 문자열 값으로 변환하는 경우, 변환된 데이터는 최대 1GB를 넘을 수 없다. 반대로 문자열을 CLOB 타입으로 변환하는 경우, 변환된 데이터는 CLOB 저장소에서 제공하는 최대 파일 크기를 넘을 수 없다.

즉, 문자형 대용량 파일 저장 하는데 유용하고 가변길이로 잘려서 저장이 된다. 라고 생각하시면 되겠네요 ㅎㅎ 

 

BLOB이란?

바이너리 데이터를 DB 외부에 저장하기 위한 타입이다.

 

  • BLOB 데이터의 최대 길이는 외부 저장소에서 생성 가능한 파일 크기이다.
  • BLOB 타입은 SQL 문에서 비트열 타입으로 입출력 값을 표현한다. 즉, BIT(n), BIT VARYING(n) 타입과 호환되며, 명시적 타입 변환만 허용된다. 데이터 길이가 서로 다른 경우에는 최대 길이가 작은 타입에 맞추어 절삭(truncate)된다.
  • BLOB 타입 값을 바이너리 값으로 변환하는 경우, 변환된 데이터는 최대 1GB를 넘을 수 없다. 반대로 바이너리를 BLOB 타입으로 변환하는 경우, 변환된 데이터는 BLOB 저장소에서 제공하는 최대 파일 크기를 넘을 수 없다. 

즉, 컴퓨터가 인식하는 모든 파일(이진 데이터)을 저장하는 타입이다.

 

대용량 -> 4GB까지 저장이 된다.(long의 2배)

LOB 타입은 데이터를 저장하는게 아니라 DB에 저장된 LOB값의 위치 포인터를 저장하기 때문에 일반적으로 읽어오는 SELECT 구문을 사용하면 위치값만 나오게 된다.

 

출처 : http://www.cubrid.org/ko_manual41/entry/BLOB%7CCLOB


create table catndog(
num number constraint shop_num_pk primary key,
aname varchar2(100),
writer varchar2(30),
categories varchar2(10),
cont clob,
img varchar2(50),
reip varchar2(50),
mdate date);


create sequence catndog_seq
increment by 1
start with 1;

 

 

9. unform1.html에 제대로 body 채워주기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upform1.html</title>
</head>
<body>
<h1>파일 업로드 예제</h1>
<div id="wrap">
    <form method="post" id="form1" enctype="multipart/form-data">
       {% csrf_token %}
        <p>이미지 등록</p>
        <p><input type="file" name="file1" id="file1"></p>
        <p><input type="button" value="등록" id="writeBtn"></p>
    </form>
</div>
</body>
</html>

 

10. 구글 CDN 링크를 하단 script에 입력해주기(3.5버전)

▼CDN이란?

더보기

CDN이란?

CDN(콘텐츠 전송 네트워크)은 서버와 사용자 사이의 물리적 거리를 줄여 웹 페이지 콘텐츠 로드 지연을 최소화하는, 촘촘히 분산된 서버로 이루어진 플랫폼이다.

CDN을 사용하지 않으면 콘텐츠 오리진 서버들은 모든 엔드유저의 요청에 일일이 응답해야 한다. 이는 오리진과 오리진에 막대한 트래픽을 유발하고 이후에도 엄청난 부하를 유발하여 트래픽이 과도하게 증가하거나 부하가 끊임없이 들어오는 경우 오리진에서 장애가 발생할 확률을 높인다.CDN은 오리진을 대신하여 엔드유저와 가까운 물리적 위치 및 네트워크에서 엔드유저 요청에 응답함으로써 콘텐츠 서버의 트래픽 부하를 오프로드하고 웹 경험을 개선하여 콘텐츠 제공업체와 엔드유저 모두에게 막대한 이점을 제공한다.

 

인터넷 트래픽의 절반 이상이 CDN(콘텐츠 전송 네트워크)을 통해 전송된다. CDN의 목표는 웹 페이지에 대한 요청이 이동해야 하는 물리적 거리를 줄여 요청 제출 시간과 장치에 완전히 로딩되는 웹 페이지 간의 지연 시간을 줄이는 것이다.

출처:www.akamai.com/kr/ko/cdn/what-is-a-cdn.jsp


이거 붙여넣기

 <!--구글 CDN 링크 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

헤드에 넣었다

 

11. static 아래 images 디렉토리 만들기

이제 파일 업로드 하면 거기에 사진이 들어갈 수 있도록 만들 것.

 

12. upform1 하단에 제이쿼리 쓰자.

<script>
    $(function(){
        $('#writeBtn').click(function(){
            $('#form1').attr('action','upload_success');
            $('#form1').submit();
        });
    });
</script>

 

실행 후 F12 개발자 모드 들어가서 요소를 보면(form 부분) 전송이 되는지 확인해 볼 수 있음. -> ????

 

13. 파이어폭스에서 강아지와 고양이 사진을 다운받아 보자.

14. views 가서 정의하자.

만든 것 중에 upload_success를 만들어야함.

파일 업로드 하는 방법이다.

이렇게하면 파일을 업로드 했을 때 위에서 설정한 링크로 들어간다.(이미지 폴더로)

# 업로드 링크
UPLOAD_DIR = '/home/kosmo_03/PycharmProjects/myapps/fileup/static/images/'


@csrf_protect
def upload_success(request):
    # request.FILES : enctype으로 전소오디어 온 파일 파라미터 객체
    # .name 등의 파일의 정보를 받을 수 있다.
    if 'file1' in request.FILES:
        # 파라미터 처리
        file = request.FILES['file1']
        file_name = file.name  # 첨부파일 이름

        # 파일 오픈 - wb모드(binary)
        fp = open("%s%s" % (UPLOAD_DIR, file_name), 'wb')

        # 파일을 1바이트씩 조금씩 읽어서 저장
        for chunk in file.chunks():
            fp.write(chunk)
        fp.close()  # 파일 닫기

    else:
        file_name = '-'
    return render(request, "fileup/success.html", {'file_name': file_name})

15. urls 등록하기

    path('upload_success',views.upload_success),

16. success.html 파일만 대충 만들어놓고 사진 업로드 해보자

잘 들어갔다

17. success.html 수정하기

등록버튼을 누르면 사진이 나온다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>success.html</title>
    <style>
        image { width:300px }
    </style>
</head>

{% load static %}
{% static "" as baseUrl %}

<body>
<img src="{{baseUrl}}/images/{{file_name}}">


</body>
</html>

 

18. upform2.html 만들기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>upform2.html</title>
    <style>
        #wrap { width:350px; margin:auto }
    </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<h1>파일 업로드 예제</h1>
<div id="wrap">
    <form method="post" id="form1" enctype="multipart/form-data">
        {% csrf_token %}
        <p>강아지/고양이 이미지 등록</p>
        <p><input type="file" name="file1" id="file1"></p>
        <div>
            <img src="" id="targetImg" style="width:300px">
        </div>
        <p><input type="button" value="등록" id="writeBtn"></p>
    </form>
<script>
    $(function(){
        $('#writeBtn').click(function(){
            $('#form1').attr('action','upload_success')
            $('#form1').submit()
        });//클릭함수
        
        //html5 파일 기능
        $('#file1').change(function(){
            //업로드 파일 읽기
            let fileInfo = document.getElementById("file1").files[0];
            console.log(fileInfo)
            let reader = new FileReader();
            //readAsDataURL()을 통해 파일을 읽어들일 때 onload가 실행
            reader.onload=function(){
                document.getElementById("targetImg").src = reader.result;
            };
            if(fileInfo){
                //readAsDataURL()을 통해 파일의 URL을 읽어온다.
                reader.readAsDataURL(fileInfo);
            }
        })//chang 함수
    })//시작함수
</script>
</div>
</body>
</html>

19. 경로와 views에 main2 등록

urls.py
views.py

main2로 바로 접속하면 잘 된다.

 

20. 설치하자

pip install pillow
pip install tensorflow

텐서플로우 설치 못해서 아무것도 못했던게 엊그제 같은데ㅠㅠ

 

views.py에 import 해준다.

from PIL import Image
import tensorflow as tf
import os,glob
import numpy as np
from tensorflow.python.keras.models import load_model, model_from_json
from tensorflow.python.keras.preprocessing.image import load_img

 

21. success2.html을 만든다.

내용 일단 그냥 복붙해놓고.

 

22. views.py에 success2 추가

파일을 받아서 모델을 열어서 모델가지고 전에 올렸던 강아지나 고양이 사진을 가지고 학습해서 y_pridict(=결과값)을 출력해서 실험해보자. 예측을 하는데 도와주는 것이지, 예측에는 100프로는 없기 때문에 참고용으로 사용할 수 있다.

@csrf_protect
def upload_success2(request):
    if 'file1' in request.FILES:

        file = request.FILES['file1']
        file_name = file.name

        fp = open("%s%s" % (UPLOAD_DIR, file_name), 'wb')

        for chunk in file.chunks():
            fp.write(chunk)
        fp.close()

        # ---추가-- 어차피 개 어려운거 실행이라도 해보는게 의의-------
        # model.json 파일 열기
        json_file = open('/home/kosmo_03/PycharmProjects/myapps/fileup/static/catdog_model.json')
        loaded_model_json = json_file.read()
        json_file.close()

        # json 파일로부터 model 로드하기
        loaded_model = model_from_json(loaded_model_json)
        # json model에 가중치 값 로드하기
        loaded_model.load_weights("/home/kosmo_03/PycharmProjects/myapps/fileup/static/model.h5")
        loaded_model.compile(loss='binary_crossentopy', optimizer='adam', metrics=['accuracy'])
        # 가중치와 모델을 로드 완료
        image = Image.open("%s%s"%(UPLOAD_DIR,file_name))
        width = 64
        height = 64
        image = image.resize((width,height))

        # 이미지를 벡터화
        image = np.array(image)
        x_test = [image]
        x_test = np.array(x_test)
        x_test = x_test /255
        y_predict = loaded_model.predict(x_test)
        category = ""

        # 예측해서 50% 이면 cat, 아니면 dog
        if y_predict >= 0.5:
            category = "cat"
            print("cat",y_predict)
        else:
            category = "dag"
            print("dog",y_predict)

        # --------------- 추가 완료 -----------------------------
    else:
        file_name = '-'
    return render(request, "fileup/success2.html", {'file_name': file_name, 'y_predict':y_predict, 'category':category})

어떻게 분류할까?

이미지의 경우, 예를 들면 색이 들어간 곳은 1, 아닌곳은 0(물론 실제로 이것보다 복잡하다)으로 두는 등, 이런 식으로 벡터로 array를 만들고, 그걸 수학적으로 훈련시킨다.

그러한 데이터로 확률을 구하는 것.

23. 아까 만든 success2.html 수정

분류된 결과값이 나올 수 있도록 써주기!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>success2.html</title>
    <style>
        image { width:300px }
    </style>
</head>

{% load static %}
{% static "" as baseUrl %}

<body>
<img src="{{baseUrl}}/images/{{file_name}}">

<!-- ----------- 추가 ------------------- -->
{% if 'cat' in category %}
<p>위의 이미지는 {{y_predict}} 값으로 <b> 고양이 [{{category}}]</b>로 예측되었습니다.</p>
{% else %}
<p>위의 이미지는 {{y_predict}} 값으로 <b> 강아지 [{{category}}]</b>로 예측되었습니다.</p>
{% endif %}

<p>
    <input type="submit" value="파일업로드" onclick="location='main2'">
</p>
<!-- ----------- 추가 끝----------------- -->
</body>
</html>

 

24. urls.py 패스도 추가해주어야한다.

    path('upload_success2',views.upload_success2),

 

25. 결과

1) main

2) main2

아래 확률까지 잘 나온다.

 

반응형
LIST

댓글