AI 탐구노트

speck : 라인을 이용한 이미지 렌더링 도구 본문

DIY 테스트

speck : 라인을 이용한 이미지 렌더링 도구

42morrow 2024. 12. 17. 10:26

 

 

speck은 이미지를 연속적인 선으로 렌더링하여 각 가로(또는 세로) 픽셀 라인을 표현하는 파이썬 기반의 라인 아트 이미지 렌더러입니다. 이번 글에서는 speck이 제공하는 기능과 이를 이용한 간단한 테스트를 진행해 보겠습니다. 

 

1.주요 기능:

제공되는 주요 기능은 다음과 같은 것들이 있습니다. 

  • 선 두께 조절: 픽셀의 그레이스케일 값에 따라 선의 두께를 조절할 수 있습니다.
  • 노이즈 프로필 추가: 랜덤성을 부여하기 위해 다양한 노이즈 프로필을 적용할 수 있습니다.
  • 색상 프로필 추가: 선의 색상을 다양하게 표현하기 위해 색상 프로필을 적용할 수 있습니다.
  • 인터랙티브 조정: ipywidget을 사용하여 출력 결과를 실시간으로 조정할 수 있습니다.

 

대략 아래와 같은 이미지를 생성할 수 있다고 생각하시면 됩니다. 

그림 : speck을 이용해 초상화 사진을 라인아트로 표현한 예시 (출처: speck Github)

 

 

 

2.테스트 

2.1.설치 방법

설치는 아래의 명령어만으로 간단하게 진행됩니다. 

pip install git+https://github.com/lucashadfield/speck.git

 

 

2.2.사용 방법

speck 객체 생성자에서 지원되는 옵션은 다음과 같습니다. 기본적으로 from_url, from_path 등의 메소드를 이용합니다. 

옵션 설명 역할/기능
image 입력 이미지의 URL 또는 PATH를 설정합니다. 
speck.SpeckPlot.from_url(), speck.SpeckPlot.from_path()를 이용합니다.
라인 아트로 변환할 이미지를 지정합니다.
upscale 픽셀 스케일링 계수, 각 입력 픽셀은 업스케일 출력 픽셀에 매핑됩니다(기본값: 10)  
horizontal 수평선을 사용하여 이미지를 렌더링합니다(기본값: True) 라인 아트에서 라인의 방향을 지정합니다. True 수평선, False 수직선
resize 크기를 조정할 치수 또는 긴 모서리를 설정할 단일 값 및 입력 종횡비 유지(기본값: 없음)  

 

draw 메소드의 옵션 가운데 일부를 소개하면 다음과 같습니다. (대략 gradio 앱에 반영된 것으로 골랐습니다 ^^;)

옵션 설명 역할/기능
weights 선 두께의 가중치를 설정합니다. (예: weights=(0.2, 0.6)) 이미지의 그레이스케일 값에 따라 선의 두께를 비율로 조절합니다.
noise 노이즈 패턴을 설정합니다. (예: SineNoise(scale=0.7)) 랜덤성을 부여하기 위해 선에 노이즈를 추가하며, 다양한 패턴을 제공합니다.
colour 선의 색상 프로필을 설정합니다. (예: CmapColour('Oranges')) 선의 색상을 표현하며, Matplotlib의 컬러맵 또는 고유의 색상을 사용할 수 있습니다.
background 배경 색상을 설정합니다. 0~1 범위를 가지는 rgba list 형태로 입력을 받습니다. (예: [1,0,0,1]) 출력 이미지의 배경색을 설정하여 라인 아트와 대비를 강조하거나 특정 스타일을 연출합니다.

 

 

2.3.실행 예제 코드 (심플 버전)

speck를 이용하는 간단한 코드는 다음과 같습니다. 읽고 그리고 저장하고... 단 4줄... 간단하죠? 

from speck import SpeckPlot, SineNoise, CmapColour

# 기본 설정
s = SpeckPlot.from_path(path='path_to_image.jpg', resize=100)
s.draw(weights=(0.3, 0.7), noise=SineNoise(scale=0.5), colour=CmapColour('Blues'), line_spacing=3, invert=True)
s.save(path='output_image.png')

 

 

2.4.테스트 데이터

테스트에 사용한 얼굴 이미지 데이터는 Unsplash에서 가져와 봤습니다. 아무래도 평범한 얼굴보다는 윤곽이 뚜렷한 쪽이 좋을 것 같아서 선택했는데 결과만 보면 어떤 얼굴을 이용해야 결과물이 좋게 나올 지 아직은 잘 모르겠습니다. 

사진 : 테스트에 사용한 사진 (출처:  Unsplash 의 )

 

2.5.테스트 코드 (Gradio 버전)

앞서의 간단 코드에 웹 기반 gradio 코드를 입혀서 만들어 봤습니다. 

import gradio as gr
from speck import SpeckPlot, SineNoise, CmapColour
from matplotlib.colors import to_rgba


# Parse the RGBA string
def rgba_to_hex(rgba):
    rgba = rgba.replace("rgba(", "").replace(")", "")
    r, g, b, a = map(float, rgba.split(","))
    return [r/255, g/255, b/255, a]

def generate_line_art(image, resize, weights_min, weights_max, noise_scale, colour_map, line_direction, skip, background):
    # Speck 인스턴스 생성
    speck = SpeckPlot.from_path(
        path=image, 
        resize=resize,
        horizontal=(line_direction == '가로')
    )

    # 옵션 적용
    weights = (weights_min, weights_max)
    noise = SineNoise(scale=noise_scale)
    colour = CmapColour(colour_map)

    # 라인 아트 생성
    speck.draw(
        weights=weights,
        noise=noise,
        colour=colour,
        skip=skip,
        background=rgba_to_hex(background)
    )

    # 이미지 저장 및 반환
    output_path = "output_image.png"
    speck.save(path=output_path)
    return output_path

# Gradio 인터페이스 구성
with gr.Blocks() as app:
    with gr.Row():
        gr.Markdown("## Speck 라인 아트 생성기")

    with gr.Row():
        with gr.Column():
            input_image = gr.Image(label="입력 이미지", type="filepath")
        with gr.Column():
            output_image = gr.Image(label="결과 이미지")

    with gr.Row():
        resize = gr.Slider(50, 500, value=100, step=10, label="이미지 크기 조정 (resize)")

    with gr.Row():
        weights_min = gr.Slider(0.0, 1.0, value=0.2, step=0.1, label="선 두께 최소값 (weights_min)")
        weights_max = gr.Slider(0.0, 1.0, value=0.6, step=0.1, label="선 두께 최대값 (weights_max)")

    with gr.Row():
        noise_scale = gr.Slider(0.0, 2.0, value=0.7, step=0.1, label="노이즈 크기 (noise_scale)")

    with gr.Row():
        colour_map = gr.Dropdown(choices=["Oranges", "Blues", "Greens", "Reds", "Purples"], value="Oranges", label="색상 맵 (colour_map)")
        line_direction = gr.Radio(["가로", "세로"], value="가로", label="라인 방향 (line_direction)")

    with gr.Row():
        skip = gr.Slider(0, 10, value=0, step=1, label="라인 건너뛰기 간격 (skip)")
        background = gr.ColorPicker(value="#FFFFFF", label="배경 색상 (background)")

    with gr.Row():
        generate_button = gr.Button("라인 아트 생성")

    # Gradio 이벤트 연결
    generate_button.click(
        generate_line_art,
        inputs=[input_image, resize, weights_min, weights_max, noise_scale, colour_map, line_direction, skip, background],
        outputs=output_image
    )

# Gradio 앱 실행
app.launch()

 

2.6.실행 화면

실행되면 아래와 같은 화면이 보이며, 조정 가능한 입력 인자는 다음과 같습니다.

  • 이미지 크기 (resize)
  • 선 두께 최소/최대값 (weights_min, weights_max)
  • 노이즈 크기 (noise_scale)
  • 색상 맵 (colour_map)
  • 라인 방향 (line_direction)
  • 라인 건너뛰기 간격 (skip)
  • 배경 색상 (background)

그림 : gradio 앱의 화면

 

 

2.7.테스트 결과

앞서 언급한 노인 이미지는 가로 방향으로 생성해 봤고, 추가로 체게바라 얼굴을 이용한 것은 세로 방향으로 생성해 봤습니다. 색상맵은 제가 좋아하는 것으로 고정해서 했는데 원하는대로 바꿔서 하시면 됩니다. 

그림 : Unsplash에 올라온 노인의 얼굴 사진으 이용한 예시

 

그림 : 체게바라 안면 사진을 이용한 예시

 


 

3.참고자료

  • 코드 (Github)
 

GitHub - lucashadfield/speck: line art image renderer

line art image renderer. Contribute to lucashadfield/speck development by creating an account on GitHub.

github.com

  • 데모 (Colab)
 

speck/speck_colab.ipynb at master · lucashadfield/speck

line art image renderer. Contribute to lucashadfield/speck development by creating an account on GitHub.

github.com