내가 이미지를 편집하고 애니메이션화하는 데 Python을 사용하는 7가지 방법
만약 당신이 Python을 어느 정도 사용해봤다면, 아마 데이터 작업, 스크립팅, 혹은 어떤 자동화 용도로 사용했을 가능성이 높습니다—하지만 이미지 편집은 아마 염두에 두지 않았을 것입니다. 알고 보니 Python은 Photoshop이 하는 작업 중 꽤 많은 부분을 처리할 수 있으며, 예상보다 훨씬 적은 코드로 가능합니다. 여기에는 이미지 크기 조정이나 자르기, 배경 제거, 혹은 정지 이미지를 GIF로 애니메이션화하는 것도 포함됩니다. 제가 Python을 사용해 이미지를 편집하고 애니메이션화하는 일곱 가지 방법을 소개합니다. 또한 시작하는 데 도움이 될 코드 스니펫도 함께 공유합니다.
여기 나오는 대부분의 예제는 이미지 작업을 위한 파이썬 라이브러리인 Pillow를 사용합니다. 몇몇 섹션에서는 NumPy와 rembg를 사용하며, 거기에 도달하면 그것들을 설명하겠습니다. 필요한 라이브러리를 설치하려면 터미널에서 이 명령어를 실행하세요:
pip install Pillow numpy rembg
파이썬을 사용하여 이미지 크기 조정, 자르기 및 회전하기
모든 이미지 편집기가 반드시 해야 하는 세 가지 기본 작업
이것들은 이미지에 할 수 있는 가장 기본적인 것들이며, Pillow 라이브러리는 이를 거의 부끄러울 정도로 간단하게 만듭니다. 필요한 것은 Image 모듈을 불러오고 두 줄의 코드를 작성하는 것뿐이며, 그것으로 끝입니다. 코드에서 이것이 어떻게 보이는지에 대한 기본적인 아이디어는 다음과 같습니다:
from PIL import Image # Import the Image module from the Pillow library
img = Image.open("photo.jpg") # Load photo.jpg from disk into an Image object (original is untouched in memory)
# --- RESIZE ---
resized = img.resize((800, 600)) # Create a new Image object scaled to 800x600px (non-destructive, img is unchanged)
resized.save("resized.jpg") # Write the resized image to disk as resized.jpg
# --- CROP ---
cropped = img.crop((100, 100, 500, 400)) # Cut a rectangle from img: starts at (100,100), ends at (500,400) → gives a 400x300px image
cropped.save("cropped.jpg") # Write the cropped image to disk as cropped.jpg
# --- ROTATE ---
rotated = img.rotate(45) # Create a new Image rotated 45° counter-clockwise; corners are clipped and filled black (canvas size unchanged)
rotated.save("rotated.jpg") # Write the rotated image to disk as rotated.jpg
그냥 "photo.jpg"를 컴퓨터에 있는 아무 이미지의 경로로 바꾸세요.
Python을 사용하여 이미지에 텍스트와 도형 그리기
이미지에 프로그래밍 방식으로 주석을 달기
Pillow에는 본질적으로 이미지를 캔버스로 바꾸는 ImageDraw라는 모듈이 있습니다. 이 모듈을 사용하면 텍스트, 사각형, 원, 선—무엇이든—기존 픽셀 위에 원하는 위치에 직접 그릴 수 있습니다.
from PIL import Image, ImageDraw, ImageFont # Also import ImageFont to load a proper font
img = Image.open("photo.jpg")
draw = ImageDraw.Draw(img) # Draw object bound directly to img — modifications are in-place
# Draw a red rectangle
draw.rectangle([50, 50, 300, 150], outline="red", width=3) # Rectangle from (50,50) to (300,150), red border, 3px thick
# Load a proper font (change path/size to suit your needs)
font = ImageFont.truetype("arial.ttf", size=32) # Load a TTF font at 32px — use any .ttf file available on your system
# Add white text at position (60, 60)
draw.text((60, 60), "Hello, World!", fill="white", font=font) # Write text using the loaded font
img.save("annotated.jpg")
ImageDraw.Draw(img) 라인은 그리기 도구를 이미지에 연결하는 것입니다. 그 후, draw.rectangle() 또는 draw.text() 호출은 해당 좌표에 새로운 픽셀 값을 이미지에 실제로 쓰는 것입니다. 저장하면 이러한 변경 사항이 이미지에 반영됩니다.
텍스트가 보이지 않는 경우, 이는 시스템에 'arial.ttf' 글꼴이 로드되지 않았기 때문일 수 있습니다. 시스템에 있는 다른 글꼴로 교체하면 작동할 것입니다.
파이썬을 사용하여 픽셀을 직접 조작하기
이미지는 단지 1과 0의 격자일 뿐이라는 것을 상기시켜줍니다
이것은 약간의 사고 전환을 필요로 합니다. 컴퓨터에서 보는 이미지는 단지 숫자의 격자일 뿐입니다. 각 픽셀에는 세 가지 값이 있습니다: 빨강, 초록, 파랑 각각에 대해 하나씩 있으며, 값은 0에서 255 사이입니다. 완전히 빨간 픽셀은 [255, 0, 0]이고, 흰색 픽셀은 [255, 255, 255], 검은색은 [0, 0, 0]입니다.
이제 NumPy 라이브러리를 사용하면 이미지를 3차원 배열(높이 × 너비 × 색상 채널)로 불러와 그 숫자들에 대해 직접 수학 연산을 할 수 있습니다. 다음은 모든 픽셀 값을 255에서 빼서 이미지의 색상을 반전시키는 간단한 예제입니다.
from PIL import Image # Import Pillow's Image module for loading and saving images
import numpy as np # Import NumPy — allows treating the image as a grid of numbers for direct pixel math
img = Image.open("photo.jpg") # Load photo.jpg from disk into an Image object
pixels = np.array(img) # Convert the Image object into a NumPy array — each pixel becomes a number (0-255) representing its brightness/color value
# --- INVERT ---
inverted = 255 - pixels # Subtract every pixel value from 255 — this flips the colors (0 becomes 255, 255 becomes 0, etc.)
result = Image.fromarray(inverted.astype(np.uint8)) # Convert the NumPy array back into a Pillow Image object — astype(np.uint8) ensures values stay in the valid 0-255 range
result.save("inverted.jpg") # Write the inverted image to disk
이미지를 단지 0과 1로 생각하기 시작하면, 많은 이미지 편집 옵션이 열립니다—색조 변경, 밝기 조정, 흑백으로의 임계값 처리. 결국 그것들은 모두 숫자 그리드 위의 수학일 뿐입니다.
필터와 색상 조정을 적용하기 위해 Python 사용하기
여기서부터 사진 편집 같은 느낌이 나기 시작합니다
여기서부터는 실제 사진 편집과 조금 더 비슷하게 느껴지기 시작합니다. Pillow를 사용하면 흐림, 선명하게 하기, 흑백 변환을 적용할 수 있으며, 밝기와 대비를 조절할 수도 있습니다—이 모든 것은 두 개의 모듈인 ImageFilter와 ImageEnhance를 통해 가능합니다. 이 모든 작업을 NumPy를 사용하거나 픽셀을 수동으로 변경하지 않고 수행할 수 있습니다.
작동 방식에 대한 기본 개요는 다음과 같습니다:
이미지를 흐리게 하면 각 픽셀의 값이 주변 픽셀들의 평균 값으로 대체됩니다. 이렇게 하면 모든 것이 부드럽고 흐릿하게 보입니다.
선명하게 하는 것은 반대 효과를 냅니다. 그것은 인접한 픽셀 간의 대비를 증폭시킵니다.
마찬가지로, 그레이스케일은 색상 채널(빨강, 초록, 파랑)을 제거하고 이를 하나의 휘도 값으로 합칩니다—각 지점이 얼마나 밝은지 나타내며, 색상 정보는 남지 않습니다.
from PIL import Image, ImageFilter, ImageEnhance # Import Image for loading, ImageFilter for blur/sharpen effects, ImageEnhance for brightness/contrast adjustments
img = Image.open("photo.jpg") # Load photo.jpg from disk into an Image object (original stays unchanged throughout)
# --- GRAYSCALE ---
gray = img.convert("L") # Convert img to grayscale — "L" is Pillow's mode for 8-bit black & white; returns a new Image object
gray.save("grayscale.jpg") # Write the grayscale image to disk
# --- BLUR ---
blurred = img.filter(ImageFilter.BLUR) # Apply a simple box blur to img — returns a new Image object, img is unchanged
blurred.save("blurred.jpg") # Write the blurred image to disk
# --- SHARPEN ---
sharpened = img.filter(ImageFilter.SHARPEN) # Apply a sharpening filter to img — enhances edges; returns a new Image object
sharpened.save("sharpened.jpg") # Write the sharpened image to disk
# --- BRIGHTNESS ---
enhancer = ImageEnhance.Brightness(img) # Create a Brightness enhancer object bound to img — similar to ImageDraw, but read-only (non-destructive)
bright = enhancer.enhance(1.5) # Apply 1.5x brightness (1.0 = original, <1.0 = darker, >1.0 = brighter) — returns a new Image object
bright.save("brighter.jpg") # Write the brightened image to disk
위 코드에서 각 효과는 원본 이미지에 독립적으로 적용되므로 효과가 겹쳐지지 않습니다. 그러나 효과를 연속적으로 적용하고 싶다면 한 연산의 출력을 다음 연산의 입력으로 전달하면 됩니다.
파이썬을 사용하여 이미지에서 배경 제거하기
그것은 줄 수도 있고 빼앗을 수도 있다
이것은 작동 방식 면에서 유일하게 다른 하나입니다. 왜냐하면 순수한 기하학이나 수학이 아니라 내부적으로 작은 머신러닝 모델을 사용하기 때문입니다. 이 라이브러리는 rembg라고 불리며, 이미지를 받아서 주제와 배경을 구분한 후 배경이 투명으로 대체된 PNG를 반환합니다.
코드는 이 전체 기사에서 가장 간단하기도 합니다:
from rembg import remove # Import the remove function from rembg — a third-party library that uses an AI model (U2Net) to detect and remove image backgrounds
from PIL import Image # Import Pillow's Image module for loading and saving images
input_image = Image.open("photo.jpg") # Load photo.jpg from disk into an Image object
output_image = remove(input_image) # Pass the image through the AI model — detects the foreground subject, removes the background, returns a new Image object with a transparent background
output_image.save("no_background.png") # Save as PNG — must use PNG (not JPG) because JPG doesn't support transparency; the transparent areas would be lost
rembg 라이브러리는 처음 실행할 때 사전 학습된 세그멘테이션 모델을 다운로드합니다(그래서 첫 실행은 잠시 걸립니다). 그 이후에는 로컬에서 실행됩니다. 출력은 알파 채널이 있는 PNG 파일로, 배경이 완전히 투명하다는 의미입니다. 이를 모든 디자인 도구에 넣거나 이전 섹션의 방법을 사용하여 다른 이미지와 합성할 수 있습니다.
뚜렷한 주제와 비교적 분명한 배경이 있는 이미지에서 가장 잘 작동합니다. 사람, 물체 또는 동물의 사진은 대체로 잘 나옵니다. 그러나 매우 복잡한 배경이거나 주제가 주변 환경과 섞여 있는 이미지는 문제를 일으킬 수 있습니다.
여기서 오류가 발생할 수 있는데, 보통 “onnxruntime”이 설치되어 있지 않아서 그렇습니다. rembg가 자동으로 설치하지만, 설치되지 않은 경우 pip install onnxruntime를 실행하면 해당 오류가 해결됩니다.
파이썬을 사용하여 두 이미지를 합성하기
코드를 사용하여 레이어를 사용하는 방법입니다
합성(compositing)은 한 이미지를 다른 이미지 위에 놓는 것을 의미합니다. 포토샵의 레이어처럼 생각하면 됩니다—배경이 있고, 특정 위치에 무언가를 그 위에 붙이는 것입니다.
Pillow은 paste() 메서드로 이를 처리합니다. 오버레이 이미지에 투명도가 있는 경우(PNG의 알파 채널 포함), 이를 마스크로 전달할 수 있으므로 투명한 영역이 배경을 덮어쓰지 않습니다. 이것이 워터마킹, PIP(그림 속 그림), UI 목업 생성 등의 기초입니다.
from PIL import Image
background = Image.open("photo.jpg").convert("RGBA") # Convert to RGBA to support transparency
overlay = Image.open("logo.png").convert("RGBA") # Convert to RGBA — logos often have transparent areas
# Resize overlay to desired size before pasting
overlay = overlay.resize((200, 100)) # Scale the logo to 200x100px — adjust to suit your needs
# Paste the overlay at position (50, 50)
background.paste(overlay, (50, 50), mask=overlay) # mask=overlay uses the overlay's alpha channel to blend edges cleanly — without this, transparent areas paste as black
background.save("composited.png") # Save as PNG to preserve transparency
paste() 메서드에는 mask=image_name이라는 인수가 있습니다. 이것은 Pillow에게 오버레이 이미지의 알파 채널을 사용하여 어느 픽셀을 붙일지, 어느 픽셀을 투명하게 남길지 결정하도록 지시합니다. 이것이 없으면 투명성이 없는 딱딱한 직사각형 붙여넣기가 됩니다.
파이썬을 사용하여 단일 이미지를 GIF로 애니메이션하기
살아 있어…
기술적으로, 고양이가 일어나서 움직이기 시작하는 것과 같은 의미에서 단순히 Python만으로 이미지를 애니메이션화할 수는 없습니다. 그것은 불가능합니다. 그러나 가능한 것은 확대 효과를 추가하거나 한 이미지를 다른 이미지로 천천히 전환되게 하는 것입니다. Python은 이미지에 작은 점진적 변화를 적용하여 코드로 여러 프레임을 생성한 다음, 그 모든 프레임을 하나의 GIF 파일로 연결할 수 있습니다.
다음은 느린 줌인 효과를 만드는 예제입니다: 각 프레임마다 이미지를 조금씩 더 크게 조정한 후, 중앙에서 원래 크기로 다시 자르기 때문에 카메라가 앞으로 다가가는 것처럼 보입니다.
from PIL import Image
img = Image.open("photo.jpg").convert("RGBA") # Load image and convert to RGBA — needed for consistent pixel handling across frames
frames = [] # Empty list to store each frame of the animation
for i in range(20): # Loop 20 times — each iteration generates one frame of the zoom effect
scale = 1 + i * 0.02 # Calculate scale factor for this frame — starts at 1.0 (100%), increases by 2% each frame up to 1.38 (138%)
new_width = int(img.width * scale) # Calculate new width based on scale factor
new_height = int(img.height * scale) # Calculate new height based on scale factor
resized = img.resize((new_width, new_height)) # Resize the image to the new dimensions — makes it slightly larger each frame
# --- CROP BACK TO ORIGINAL SIZE FROM CENTER ---
left = (resized.width - img.width) // 2 # Calculate how many pixels to trim from the left to center the crop
top = (resized.height - img.height) // 2 # Calculate how many pixels to trim from the top to center the crop
frame = resized.crop((left, top, left + img.width, top + img.height)) # Crop the resized image back to the original dimensions from the center — this creates the zoom-in illusion
frames.append(frame) # Add the cropped frame to the frames list
# --- SAVE AS GIF ---
frames[0].save(
"zoom.gif", # Output filename
save_all=True, # Tell Pillow to save all frames, not just the first one
append_images=frames[1:], # Attach frames 2-20 after the first frame
duration=50, # Each frame displays for 50 milliseconds — lower = faster animation
loop=0 # 0 = loop forever; set to 1 for play-once, 2 for twice, etc.
)
루프는 20개의 프레임을 생성하며, 각 프레임은 이전 프레임보다 2% 더 확대됩니다. 그런 다음 save()에 save_all=True를 사용하면 Pillow가 모든 프레임을 하나의 애니메이션 GIF로 묶도록 합니다. 같은 원리는 팬(panning), 페이드(fading), 색상 변환(color cycling) 등 프레임마다 작은 변화를 나타낼 수 있는 모든 효과에 적용됩니다.
또한 만약 당신이 고양이가 움직이는 연속 촬영을 했다면, 기술적으로는 파이썬을 사용해 각 사진을 이어 붙여 고양이가 움직이는 거의 스톱모션 애니메이션을 만들 수 있다는 점도 언급해야 합니다.
파이썬은 엄청난 가능성을 열어줍니다
그래서 보시다시피, 코드로 이미지 편집을 하는 것이 실제로 가능하며, 게다가 그렇게 복잡하거나 코드가 많이 필요한 것도 아닙니다. 하지만, 왜 포토샵 대신 이것을 사용하겠습니까? 글쎄요, 코드를 사용하여 이미지를 조작할 수 있다는 것은 많은 자동화 가능성을 열어줍니다. 예를 들어, 저는 최근에 제 바탕화면 이미지 위에 하루 일과를 오버레이하는 자동화를 만들었습니다. 그것은 멋진 프로젝트였고, 프로그램을 이용한 이미지 조작 없이는 불가능했을 것입니다.












