랜덤 프로필 이미지를 만들어볼까?

현운용·2021년 2월 21일
0
post-thumbnail

영감

ref: https://www.youtube.com/watch?v=qhbuKbxJsk8&t=590s


Mathloger라는 유튜버가 있다.
다양한 수학 지식을 설명해주시는 감사한 분이다. 이 분이 올려주신 영상중 하나에서 영감을 얻었다.
어떠한 방식으로 점과 선을 연결하다보면 위와 같은 모양을 얻을 수 있다고 설명하고 있는데
특정 값에 대한 모양이 신비롭고 입력이 실수라서 Github의 랜덤 프로필 이미지처럼 만들 수 있지 않을까? 라는 상상을 했다.

작동원리

Mathloger가 아주 친절하게 작동원리에 대해서 설명하고 있지만 다시 한번 본 내용에서 정리해보자면

1. N개의 점으로 원을 일정한 각도로 두른다.
2. 곱해질 값을 설정한다 (default = 2, 실수)
3. N개의 점중 하나를 피벗한다.
4. 피벗한 점을 기준을 순서로 앞서 정한 곱해질 값을 곱한 뒤 결과값에 모듈러 연산을 한 뒤 나온 값만큼 순서대로 이동한 점에 선을 긋는다.
5. 모든 점에 대해 위의 4의 행동을 반복한다.


N개의 점이 10개 였고 피봇이 제일 위쪽의 점이었다면 위와 같은 모양이 발생한다.

#%%
import math
import numpy as np
import plotly.express as px
import math
import plotly.graph_objects as go

from typing import List
from PIL import Image, ImageDraw, ImageFont
from matplotlib import pyplot as plt
from scipy.fft import fft, fftfreq

size = 1000
TWO_PI = 2 * math.pi

#%%
def rotate(origin, point, angle):
  ox, oy = origin
  px, py = point

  qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
  qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
  return qx, qy

def line(array, point1, point2):
  x1, y1 = point1
  x2, y2 = point2

  if (x2 - x1 == 0):
    slope = 0
  else:
    slope = (y2 - y1) / (x2 - x1)

  b = (y1 - x1 * slope)
  fn = lambda x: x * slope + b
  for i in range(min(x2, x1), min(x2, x1) + abs(x2 - x1)):
    array[round(fn(i))][i] = 1

#%%
datas = []

for iter in range(2, 3):
  # iter /= 10
  array = np.zeros((size, size))
  countPoint = 10

  origin = (0, 0)
  circlePoints = []
  for i in range(countPoint):
    x, y = rotate(origin, (-size / 2, 0), math.radians(360 / countPoint * i))
    circlePoints.append((round(y + size / 2) - 1, round(x + size / 2) - 1))
    array[round(y + size / 2) - 1, round(x + size / 2) - 1] = 1

  for (index, circlePoint) in enumerate(circlePoints):
    line(array, circlePoint, circlePoints[round(index * iter) % countPoint])

  datas.append({
    'index': iter,
    'value': np.count_nonzero(array == 1),
  })
  im = Image.fromarray(array * 255)
  im.show()

구현 후...

https://www.youtube.com/watch?v=tABzChxJfTs&t=300s
구현을 0 ~ 100 까지 소수 둘째자리 실수로 입력하여 만든 동영상

실수에 대해서 이미지를 그리는 것까지는 완벽했다 하지만 생각보다 모양이 균일하여 프로필 이미지로 사용하기 원활하지는 않았다. 정수가 아닌 실수범위의 입력에 대해서는 조화롭지 않았다.

아래의 이미지를 통해 조화로운 상태 오른쪽과 조화롭지 않은 상태 왼쪽의 비교해볼 수 있다.

자세히보면 왼쪽의 이미지보다 오른쪽의 조화로운 이미지에서 선이 더 중복되어 표현되는 것을 볼 수 있다.
전체적으로 간결한 상태이다. 그래서 원안의 채워짐을 지표로하여 원을 구분하면 어떨까라는 생각을 하게되었다.
채워짐: 원안의 발생한 픽셀의 총합으로 계산함
N: 원을 두르고 있는 점의 수
N = 50

N = 100

N을 기준으로 데이터가 주기를 갖는 것을 확인할 수 있다.
주기를 다시한번 확인해보면

붉은 지점들이
위와 같은 그래프를 얻을 수 있다. 해당 위치의 이미지를 확인해보면! 아래과 같이 깔끔한 이미지들을 얻을 수 있다.

profile
개발자

0개의 댓글