개요
이전에 기술 구현 가능 여부를 조사하면서 파이썬을 사용한 내용을 정리한 내용이다.
사용 기술
언어: Python 3.10
이미지 생성: matplotlib
서비스: AWS Lambda, AWS API Gateway
이미지 저장 및 URL: AWS S3, AWS CloudFront
플로우는 다음과 같다.
요구사항
우측 상단의 경로 이미지를 생성하려고 한다.
경로 이미지 생성에 대한 요구사항은 다음과 같다.
- 위도, 경도로 이루어진 배열을 입력받는다.
- 이미지 생성
- 선과 점 표현
- 투명한 배경색
- 위경도 차이가 크든 작든 제공하는 이미지 내에 경로가 다 포함되어 있어야 한다.
이미지 출력 방식
- 위경도를 처리한 값으로 직접 경로를 그린 다음 이미지 형태로 저장
- 플롯을 그려주는 라이브러리 사용하여 이미지 형태로 저장
이미지 출력 방식의 경우 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)
생성 결과는 아래와 같다. (예시를 위해 검은색으로 출력)
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