본문으로 건너뛰기

"Python" 태그로 연결된 1개 게시물개의 게시물이 있습니다.

모든 태그 보기

· 약 7분

개요

이전에 기술 구현 가능 여부를 조사하면서 파이썬을 사용한 내용을 정리한 내용이다.

사용 기술

언어: Python 3.10
이미지 생성: matplotlib
서비스: AWS Lambda, AWS API Gateway
이미지 저장 및 URL: AWS S3, AWS CloudFront

플로우는 다음과 같다.

요구사항

./route.png

우측 상단의 경로 이미지를 생성하려고 한다.
경로 이미지 생성에 대한 요구사항은 다음과 같다.

  • 위도, 경도로 이루어진 배열을 입력받는다.
  • 이미지 생성
  • 선과 점 표현
  • 투명한 배경색
  • 위경도 차이가 크든 작든 제공하는 이미지 내에 경로가 다 포함되어 있어야 한다.

이미지 출력 방식

  1. 위경도를 처리한 값으로 직접 경로를 그린 다음 이미지 형태로 저장
  2. 플롯을 그려주는 라이브러리 사용하여 이미지 형태로 저장

이미지 출력 방식의 경우 1번과 2번을 고민했었다.
파이썬으로는 플롯을 그려주는 라이브러리인 matplotlib을 사용했다.

로컬에서 기능 구현

import time

import matplotlib.pyplot as plt


def draw(point):
start = time.time()
x, y = zip(*point)
pixel_x, pixel_y = convert_to_pixel_values(x, y)
draw_lines(pixel_x, pixel_y)
end = time.time()
print(end - start)

def convert_to_pixel_values(x, y):
max_diff = max(max(x) - min(x), max(y) - min(y))
return scale_to_pixel_values(x, max_diff), scale_to_pixel_values(y, max_diff)


def scale_to_pixel_values(points, max_diff):
min_value = min(points)
scaled_coordinates = [(p - min_value) / max_diff for p in points]
return scaled_coordinates


def draw_lines(x, y):
figure = plt.gcf()
figure.set_size_inches(5, 5)
plt.plot(x, y, c = 'w',linewidth=5)
plt.scatter(x[3],y[3], c = 'w', s = 125)
plt.axis('off')
plt.savefig('name.png', transparent=True, format='png')

point = [
[126.96352960597338, 37.590841000217125],
[126.96987292787792, 37.58435564234159],
[126.98128481452298, 37.58594375113966],
[126.99360339342958, 37.58248524741927],
[126.99867565340067, 37.56778118088622],
[127.001935378366117, 37.55985240444085],
[126.9831048919687, 37.548030119488665],
[126.97189273528845, 37.5119879225856],
[127.02689859997221, 37.48488593333883]
]

draw(point)

생성 결과는 아래와 같다. (예시를 위해 검은색으로 출력)

./routeImage.png

AWS Lambda

썸네일 생성 서버를 따로 두기는 기능 대비 비용이 너무 클 것이라고 생각했다.
따라서 서버리스로 파일을 처리했다.
추가로 s3 접근은 boto3를 사용했다.

람다 S3 접근을 위한 IAM 생성

AmazonS3FullAccess, AmazonS3ObjectLambdaExecutionRolePolicy 두가지를 추가해서 Lambda 전용 역할을 만들어 사용했다.

람다 배포용 코드

기술 구현 가능 여부를 확인할 땐 위치 점을 찍는 기능을 람다에 배포하지 않았다.


import io
import uuid

import boto3
import matplotlib.pyplot as plt

PIXEL = 255
BUCKET_NAME = 'image-plot'
S3 = 's3'

def lambda_handler(event, context):
x = event['x']
y = event['y']
image_name = str(uuid.uuid4())

img_data = draw(x, y)
s3 = boto3.client(S3)
s3.put_object(Body=img_data.getvalue(), ContentType='image/png', Bucket=BUCKET_NAME, Key=image_name)
url = f'https://{BUCKET_NAME}.s3.ap-northeast-2.amazonaws.com/{image_name}'

return {
'statusCode': 200,
'body': url
}

def draw(x, y):
pixel_x, pixel_y = convert_to_pixel_values(x, y)
img_data = draw_lines(pixel_x, pixel_y)
plt.close()
return img_data

def convert_to_pixel_values(x, y):
max_diff = max(max(x) - min(x), max(y) - min(y))
return scale_to_pixel_values(x, max_diff), scale_to_pixel_values(y, max_diff)

def scale_to_pixel_values(points, max_diff):
min_value = min(points)
scaled_coordinates = [(p - min_value) / max_diff for p in points]
pixel_values = [int(p * PIXEL) for p in scaled_coordinates]
return pixel_values

def draw_lines(x, y):
plt.plot(x, y, 'k-', linewidth=10)
plt.axis('off')
img_data = io.BytesIO()
plt.savefig(img_data, transparent=True, format='png')
img_data.seek(0)
return img_data

Layer 추가를 위한 zip 파일 생성

matplotlib의 경우 외부 라이브러리기 때문에 따로 Layer를 추가해야 한다.
zip 파일을 만들어서 업로드해야한다.
이때 python의 Lambda 런타임에 대한 계층 경로는 python이다.
따라서 압축한 zip 파일은 다음과 같은 구조를 띄어야 한다.

pillow.zip
│ python/PIL
└ python/Pillow-5.3.0.dist-info

Ubuntu 기준 다음 명령어를 입력하여 생성을 진행했다.

sudo apt update
sudo apt install zip
sudo apt install python3-pip

mkdir python
pip3 install matplotlib -t python # pip3 install 설치할_패키지 -t 설치_경로
zip -r my_layer.zip python # zip -r 압축_파일명 압축_파일이_존재하는_경로

No module named 'numpy.core._multiarray_umath' 에러

Layer 추가 후 람다 실행 시 발생한 에러였다.
처음에 mac에서 zip 파일을 생성해서 업로드했는데 해당 문제가 발생했다.
이는 lambda가 돌아가는 동일한 환경에서 layer를 위한 zip 파일을 만들지 않아서 발생하는 문제다.
간단하게 ec2 인스턴스를 하나 만들어서 따로 Layer를 생성하면 문제가 발생하지 않는다.

적정기술에 대한 생각

프로젝트에 Lambda와 Python을 사용하려고 했지만 아쉽게도 반려당했다.
AWS Lambda를 사용하는 것은 인스턴스에 해당 코드를 배포하는 것보다 더 효율적인 방법일 수 있다.
하지만 현재 프로젝트에서 가용 가능한 자원, 기술의 난이도, 사용하는 팀원을 고려한다면 Lambda는 적정기술이 아닐 수 있다.
따라서 해당 이미지 생성기를 어떻게 적용할지 조금 더 고려를 해야 될 것으로 보인다.

최종적으로 Java AWT를 사용하기로 결정했다.

참고 자료

AWS Lambda
Lambda Layer
Python Lambda 함수에 대한 .zip 파일 아카이브 작업
No module named 'numpy.core._multiarray_umath'
사례별로 알아본 안전한 S3 사용 가이드