본문 바로가기
Flutter

Flutter(플러터) Python Flask 서버 만들어서 CartoonGAN 적용하기

by 퍼즐잎 2021. 3. 16.

개요

학습된 머신러닝 모델들을 찾을 수 있는 tfhub에서 cartoongan 모델을 발견하게 되었습니다.

이미지를 만화같은 스타일로 변환해주는 모델인데 재미있을 것 같아서 모델 파일을 다운로드 받고 플러터 프로젝트에 적용 해봤습니다.

 

 

TensorFlow Hub

 

tfhub.dev

그런데 실제 적용 했을 때 몇 가지 문제가 있었습니다.

 

Flutter에는 공식적인 tflite 라이브러리가 없어서 서드파티 라이브러리를 사용하는데 실제 동작하지 않는 모델이 많이 있었습니다.

 

사용할 수 있는 모델인 경우에도 입력가능한 이미지 사이즈 크기 제한이 있어 이미지를 리사이징해서 사용하는데,

만화 스타일로 변화된 이미지도 똑같이 화질이 안좋아서 제대로 사용할 수 없는 상태였습니다.

 

Google Colaboratory

 

colab.research.google.com

마침 Colab으로 cartoongan을 적용할 수 있는 프로젝트가 있어서 해당 프로젝트를 기반으로 직접 파이썬 서버를 만들어서 Flutter에 적용 해보기로 했습니다.

 

파이썬 서버 만들어보기

파이썬으로 서버를 만들어 보는 것은 처음이라서 여러가지를 찾아보다가 Flask를 이용하여 API 서버를 만들어 보기로 했습니다.

 

Flask는 파이썬으로 웹 애플리케이션 개발을 위한 프레임워크로, 최소한의 구성 요소와 요구사항을 제공하기 때문에 필요한 기능만 간단하게 개발하기에 적합해서 선택하게 되었습니다.

 

 

What is Flask Python - Python Tutorial

Flask is a web framework, it’s a Python module that lets you develop web applications easily. It’s has a small and easy-to-extend core: it’s a microframework that doesn’t include an ORM (Object Relational Manager) or such features. It does have man

pythonbasics.org

Django도 유명한데 Flask보다 무겁고 제공하는 기능이 많아서 간단한 API 서버를 만드는 목적에는 적합하지 않은 것 같아서 제외 하게 되었습니다.

 

환경설정

Colab의 cartoongan 프로젝트의 경우 오래된 프로젝트라서 tensorflow 1로 구현이 되어 있습니다.

 

파이썬 최신버전을 사용하면 동작하지 않기 떄문에 다음과 같이 tensorflow 1.x 버전을 사용할 수 있는 파이썬의 가상환경을 만들고 환경설정을 진행합니다.

# Windows
virtualenv ml --python=3.7.9
cd ml
cd scripts
activate.bat

# Mac
source ml/bin/activate

프로젝트에서 필요한 라이브러리를 설치합니다.

(git에서 필요한 라이브러리가 설정 된 프로젝트를 확인할 수 있습니다.)

pip install -r requirements.txt

파이썬 Flask 프로젝트의 기본 설정을 합니다.

cartoongan 모델이 적용 된 API를 만들기 위해서 아래와 같이 틀을 잡았습니다.

 

@app.route로 API경로와 methods를 설정할 수 있습니다.

 

간단하게 /v1/image/convert_cartoon 으로 이름을 정하고 POST 방식으로 설정을 했습니다.

base64 형태로 인코딩 된 이미지 데이터를 JSON 형태로 받아서 image로 확인하고 있습니다.

# app.py
from flask import Flask, request, jsonify
from werkzeug.serving import WSGIRequestHandler

from v1.image.cartoongan import cartoongan

app = Flask(__name__)

@app.route('/v1/image/convert_cartoon', methods = ['POST'])
def convert_cartoon():
    data = request.get_json()

    if 'image' not in data:
        return "", 400

    cartoon_img_data = cartoongan.convert(data['image'])

    return cartoon_img_data, 200

@app.route("/")
def index():
    return "<h1>Welcome to puzzleleaf ml server !!</h1>"

if __name__ == "__main__":
    # https://stackoverflow.com/questions/63765727/unhandled-exception-connection-closed-while-receiving-data
    WSGIRequestHandler.protocol_version = "HTTP/1.1"
    app.run(threaded=True, host='0.0.0.0', port=5000)

 

디코딩된 이미지 데이터를 사용하기 위해 프로젝트에 저장된 cartoongan 모델을 불러옵니다.

# cartoongan.py
import base64
from . import cartoonize

def convert(image):
    model_path = './v1/image/cartoongan/saved_models'
    imgdata = base64.b64decode(image)
    cartoon_img_data = cartoonize.cartoonize(imgdata, model_path)

    return base64.b64encode(cartoon_img_data)

 

이미지 데이터를 RGB 이미지로 변환하고 resize 과정을 수행합니다.

모델에 변환된 이미지를 적용하여 만화 스타일로 변환 된 이미지를 얻을 수 있습니다.

최종적으로 cv2로 이미지를 인코딩하는 작업을 거쳐서 반환하게 됩니다.

 

이렇게 만든 API 서버를 로컬 서버가 아닌 Heroku를 통해서 배포해봤습니다.

Heroku

Heroku는 컨테이너 기반 클라우드 PaaS (Platform as a Service)입니다.

개발자는 Heroku를 사용하여 최신 앱을 배포, 관리를 쉽게할 수 있습니다. 무료로 배포하고 사용할 수 있어서 Heroku를 적용하게 되었습니다.

(무료일 경우 500MB 용량 제한과 약 5~15분 동안 사용이 없으면 서버가 자동으로 정지되고 이후에 다시 재 시작하는데 20~30초 정도가 소요됩니다.)

 

 

Deploying Python Applications with Gunicorn | Heroku Dev Center

Last updated June 03, 2020 Web applications that process incoming HTTP requests concurrently make much more efficient use of dyno resources than web applications that only process one request at a time. Because of this, we recommend using web servers that

devcenter.heroku.com

파이썬 애플리케이션을 배포하기 위한 가이드를 제공하고 있어서 쉽게 배포할 수 있습니다. 이외에도 다양한 언어들을 지원하고 있습니다.

 

 

Language Support | Heroku Dev Center

 

devcenter.heroku.com

Heroku 페이지에서 프로젝트를 생성하고 Github과 연동해서 배포 설정을 할 수 있습니다.

master에 push가 되면 자동으로 배포가 되도록 설정했습니다.

API 서버

puzzleleaf-ml-server.herokuapp.com/

API 적용하기

실제 Flutter에서 다음과 같이 API 호출을 통해서 사용할 수 있습니다.

서버로 전달받은 이미지를 디코딩하는데 시간이 소요되어서 compute를 통해 백그라운드에서 처리할 수 있습니다.

https://flutter-ko.dev/docs/cookbook/networking/background-parsing

 

백그라운드에서 JSON 파싱하기

기본적으로, Dart 앱은 모든 작업을 단일 스레드에서 수행합니다. 대부분의 경우 이러한 모델은코딩을 단순화시키며, 앱 성능이 떨어지거나 jank라고 불리는 뚝뚝 끊기는 애니메이션을 야기하지

flutter-ko.dev

import 'dart:convert';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

class MLService {
  Dio dio = Dio();

  // ml server
  // https://github.com/PuzzleLeaf/tensorflow_flask_api_server
  Future<Uint8List> convertCartoonImage (Uint8List imageData) async {
    try {
      var encodedData = await compute(base64Encode, imageData);
      Response response = await dio.post('https://puzzleleaf-ml-server.herokuapp.com/v1/image/convert_cartoon',
        data: {
          'image': encodedData
        }
      );
      String result = response.data;
      return compute(base64Decode, result);
    } catch (e) {
      return null;
    }
  }
}

갤러리에서 이미지를 선택하고 서버에서 이미지를 처리 후 다시 전달하는 예제입니다.

전체적인 코드나 구현 방법은 아래의 링크를 통해서 확인할 수 있습니다.

 

Flask API Server

 

PuzzleLeaf/tensorflow_flask_api_server

Contribute to PuzzleLeaf/tensorflow_flask_api_server development by creating an account on GitHub.

github.com

Flutter Client

 

PuzzleLeaf/flutter_image_cartoongan_with_server

Contribute to PuzzleLeaf/flutter_image_cartoongan_with_server development by creating an account on GitHub.

github.com

 

댓글