← 발견
ASTERXOR / 발견

이 로켓은
원으로 그렸습니다

어떤 원도 로켓이 무엇인지 모릅니다 그저 각자의 속도로 돌고 있을 뿐인데 펜 끝은 어느새 제자리를 찾아갑니다

32개의 회전하는 푸리에 벡터로 복원한 로켓 윤곽의 한 순간
32개의 회전 · 하나의 펜 끝
발견ASTERXOR / LEON LEUNG

원은 빙글빙글 돌기만 하는데 어떻게 모서리를 그릴까요?

회전하는 막대 끝에 펜을 달면 원이 그려집니다 그 끝에 또 다른 회전 막대를 연결하면 펜의 움직임은 조금 더 재미있어집니다 막대의 길이와 속도 시작 방향을 잘 조합하면 로켓 같은 모양도 그릴 수 있습니다

원은 그림을 배우지 않았습니다 좋은 지시를 받았을 뿐입니다
THE IDEA

그림을 움직임으로 바꿔 보기

로켓은 잠시 잊고 작은 불빛 하나가 윤곽을 따라 한 바퀴 돈다고 생각해 보세요. 매 순간 불빛에는 가로 위치와 세로 위치가 있습니다. 이 두 값의 변화를 기록하면 전체 여정을 기록한 셈입니다.

푸리에 분석은 다른 질문을 던집니다 이 움직임을 더 단순한 움직임들의 합으로 표현할 수 있을까요. 여기서 단순한 움직임은 회전입니다. 회전하는 화살표들이 각각 가로와 세로 방향의 움직임을 조금씩 보태면 마지막 끝점이 그림의 한 점이 됩니다.

화음을 여러 음으로 나누는 것과 비슷합니다 다만 여기서는 소리가 아니라 경로를 나눕니다 그림이 다른 무언가로 변한 것은 아닙니다 같은 그림을 설명하는 방법이 달라진 것입니다.

같은 윤곽을 표본 점 회전 계수 복원 경로로 차례로 표현했습니다
FIG 01같은 윤곽을 표본 점 회전 계수 복원 경로로 차례로 표현했습니다
THE MECHANISM

각 원에 필요한 세 가지 지시

반지름은 움직임의 크기를 정합니다 주파수는 펜이 경로를 한 바퀴 도는 동안 몇 번 회전할지 정합니다 시작 각도는 어느 방향에서 출발할지 정합니다 시계 방향으로 도는 화살표도 있고 반시계 방향으로 도는 화살표도 있습니다.

화살표는 끝과 시작이 이어집니다 그래서 다음 원의 중심은 앞 화살표의 끝을 따라 움직입니다. 금색 점은 이 연결 전체의 마지막 끝점입니다. 숨겨 둔 로켓 선을 혼자 따라가는 점이 아닙니다.

연결 전체를 그림의 적절한 위치에 놓는 고정값도 하나 있습니다. 윤곽에서 뽑은 점들의 평균 위치이며 회전하지 않습니다. 이 글에서 말하는 32개의 원에는 이 고정 중심이 포함되지 않습니다.

실제 계산한 32개 회전 벡터 연결의 한 순간입니다 파란 원은 각 벡터의 움직임 범위 금색 점은 마지막 펜 끝입니다
FIG 02실제 계산한 32개 회전 벡터 연결의 한 순간입니다 파란 원은 각 벡터의 움직임 범위 금색 점은 마지막 펜 끝입니다
THE EXPERIMENT

여덟 개면 알아보고 서른두 개면 자세히 보입니다

이번 예제는 사진이 아니라 직접 설계한 다각형 로켓 윤곽으로 시작합니다 윤곽의 길이를 따라 같은 간격으로 1024개의 점을 뽑고 고속 푸리에 변환 FFT로 회전 성분을 계산합니다.

느리게 도는 원만 남기는 대신 기여하는 크기가 큰 성분부터 선택했습니다. 원이 여덟 개일 때도 로켓은 알아볼 수 있지만 날개는 둥글게 보입니다. 32개가 되면 주요 특징이 돌아오고 128개에서는 뾰족한 부분도 원본에 더 가까워집니다.

흥미로운 점은 원이 많을수록 자세해진다는 사실만이 아닙니다 작은 세부를 다 복원하기 전에도 전체 형태가 상당히 남아 있다는 점입니다. 큰 회전이 형태를 잡고 작은 회전들이 방향을 급하게 바꾸는 부분을 함께 다듬습니다.

금색은 복원 경로 점선은 원본 윤곽입니다 모두 같은 1024개 표본 위치를 사용합니다
FIG 03금색은 복원 경로 점선은 원본 윤곽입니다 모두 같은 1024개 표본 위치를 사용합니다
1,024윤곽 표본
32회전 성분
0.232%평균 오차
THE DETAILS

어려운 부분은 모서리입니다

아래에서 밝은 노란색과 분홍색 부분은 32개의 원으로 복원했을 때 위치 차이가 큰 곳입니다. 로켓의 끝과 날개 꼬리를 보세요. 직선은 비교적 따라가기 쉽지만 방향이 갑자기 바뀌는 부분은 제한된 수의 매끄러운 회전만으로 표현하기 어렵습니다.

평균만 보면 이 차이를 놓칠 수 있습니다. 32개일 때 평균 거리는 원본 외접 사각형 대각선의 0.232퍼센트이고 가장 큰 거리는 1.314퍼센트입니다. 평균적으로 얼마나 다른지와 가장 크게 어긋난 곳이 얼마나 다른지는 서로 다른 질문입니다.

선택한 세 단계에서는 오차가 줄었지만 원을 하나 추가할 때마다 모든 점과 모든 오차 지표가 좋아진다는 뜻은 아닙니다 크기가 가장 큰 푸리에 성분을 남기면 같은 성분 수에서 표본 위치의 제곱 오차를 최소화합니다 평균 거리와 시각적 품질은 그와 다른 지표입니다.

왼쪽은 원 32개의 위치 오차 오른쪽은 선택한 성분 수에서의 평균 오차입니다 밝은 부분일수록 위치 차이가 큽니다
FIG 04왼쪽은 원 32개의 위치 오차 오른쪽은 선택한 성분 수에서의 평균 오차입니다 밝은 부분일수록 위치 차이가 큽니다
원 개수평균 오차최대 오차
81.550%3.976%
320.232%1.314%
1280.025%0.275%

거리는 원본 윤곽 외접 사각형 대각선의 백분율이며 1024개 표본 위치에서 계산했습니다 고정 중심은 별도입니다

THE CODE

그림 아래에는 작은 아이디어가 있습니다

가로 좌표는 복소수의 실수부로 세로 좌표는 허수부로 표현합니다 갑자기 어려워 보이지만 두 좌표를 한 쌍으로 다루기 위한 편리한 방법입니다. 복소 지수는 회전을 간결하게 표현해 줍니다.

복원할 때는 각 순간에 선택한 회전 벡터들을 더하고 고정 중심을 다시 더합니다 아래는 계산의 핵심 부분이며 전체 그림 생성 프로그램은 아닙니다.

PYTHON / THE CORE IDEA
coefficients = np.fft.fft(points) / len(points)
frequencies = np.fft.fftfreq(len(points), d=1 / len(points))
selected = np.argsort(-np.abs(coefficients[1:]))[:32] + 1

rotations = coefficients[selected, None] * np.exp(
    2j * np.pi * frequencies[selected, None] * time[None, :]
)
path = coefficients[0] + rotations.sum(axis=0)
THE PERSPECTIVE

아름답지만 마법은 아닙니다

이것을 원 32개로 사진을 압축했다고 부르고 싶어질 수도 있습니다. 하지만 중요한 전제가 빠집니다 이 예제는 하나의 닫힌 윤곽을 다루고 수치 계수를 저장하며 실제 이미지 파일 크기를 비교하지 않습니다. JPEG나 SVG 또는 AI 이미지 모델을 대체하는 기술이 아닙니다.

유한한 표본으로 무한히 정밀한 다각형을 되살린 것도 아닙니다 모든 성분을 사용하면 1024개 표본 위치를 수치 정밀도 안에서 복원할 수 있습니다. 그 사이의 경로는 매끄러운 주기적 보간입니다.

제가 좋아하는 부분은 더 단순합니다 그림처럼 보이는 것을 정교하게 조합된 움직임으로 이해할 수 있다는 점입니다. 로켓은 어느 한 원 안에 숨어 있지 않았습니다. 원들이 함께 움직이는 방식 안에 있었습니다.

더 읽어 보기

NumPy · Discrete Fourier Transform ↗NumPy · numpy.fft.fft ↗

NumPy 문서에서 변환 규약과 FFT를 확인할 수 있습니다 위 그림은 본문에서 설명한 계산으로 만들었습니다

가져갈 생각 하나

복잡함은 단순한 것들이 잘 협력한 결과일 수 있습니다