숫자로 그리기 (숫자가 아닌 프로그래밍 사용)


56

당신의 임무는 흑백 윤곽선 이미지를 가져 와서 컬러로 채우는 프로그램을 만드는 것입니다. 각 지역을 구분하는 방법과 채울 색상을 결정하는 것은 사용자에게 달려 있습니다 (RNG를 사용할 수도 있음).

예를 들면 다음과 같습니다.

예를 들어 출력 1

보시다시피 저는 MS Paint와 관련하여 뛰어난 칼리버의 예술가입니다.


채점

이것은 인기 경연 대회이므로 가장 많은 순 투표 수를 얻은 답이 이깁니다. 유권자들은 다음과 같이 답변을 판단하도록 권장됩니다

  • 입력 기준 : 흰색 / 밝은 회색 배경과 검은 색 / 진한 회색 윤곽선으로 구성된 모든 이미지
  • 채색이 얼마나 잘 이루어 졌습니까? 위와 달리 흰색이 거의 없거나 전혀없는 것을 의미합니다 (구름에 흰색을 사용하려는 경우가 아니라면)
  • 특정 섹션에 사용 된 색상의 사용자 정의
  • 시스템이 다양한 이미지에서 다양하게 작동하는 정도
  • 이미지 당 프로그램 소요 시간을 게시하십시오. 우리는 코드 골프를하지 않을 수도 있지만 더 짧고 빠르며 효율적인 코드는 더 나은 것으로 간주해야합니다
  • 새 이미지를 화면이나 파일로 출력해야합니다 (대답에 표시 될 수 있도록 2MB 이하).
  • 해당 이미지 유형으로 출력하기로 선택한 이유를 정당화하고 코드 작동을 설명 / 설명하십시오.
  • 적용되는 각 모양에 사용되는 색상의 적용 성 (실제 색상 구성, 즉 잔디는 녹색, 나무 울타리는 갈색 등)

    "나는 각 영역을 무작위로 채색 할 수 있지만,"울타리 "를 식별하고 유사하게 채색 할 수 있다면 공감할 가치가있는 것입니다. -나단 메릴

이 같은보고 되고 인기도 대회, 당신은 또한 선택적으로 판단 할 수있다 :

  • 전반적인 호소 (이미지가 얼마나 좋아 보이는지)
  • 예술적 감각; 음영 또는 수채화 스타일의 채색 등으로 프로그래밍 할 수있는 경우

일반적으로 금식 프로그램과 최고 대중 투표로 최고 품질의 가장 작은 출력 이미지 (파일 크기)가 이길 것입니다.

사용해야 할 다른 판단 사양이있는 경우이 게시물의 주석에서 권장하십시오.


나는 아무것도 소유하지 않는다. 모든 예제 이미지는 크리에이티브 커먼즈 라이센스입니다.

검정 / 흰색의 예 1 출처 : https://pixabay.com/ro/stejar-arbore-schi%C5%A3%C4%83-natura-303890/ 검정 / 흰색의 예 2 출처 : http://www.freestockphotos.biz/stockphoto/10665 검정 / 흰색의 예 3 출처 : http : / /crystal-rose1981.deviantart.com/art/Dragon-Tattoo-Outline-167320011 검정 / 흰색의 예 4 출처 : http://jaclynonacloudlines.deviantart.com/art/Gryphon-Lines-PF-273195317 검정 / 흰색의 예 5 출처 : http://captaincyprus.deviantart.com / art / Dragon-OutLine-331748686 검정 / 흰색의 예 6 출처 : http://electric-meat.deviantart.com/art/A-Heroes-Farewell-280271639 검정 / 백색의 예 7 출처 : http://movillefacepalmplz.deviantart.com/art/Background-The-Pumpkin -오래 된 농장 -342865938


편집 : 비 흑백 / 픽셀 및 흑백 / 회색 대신 회색을 포함 할 수있는 일부 이미지를 일으키는 선의 앤티 앨리어싱으로 인해 처리 할 수있는 보너스 과제가 있습니다. 내 의견으로는 충분히 쉬워야한다.


4
모두에게 : "예술 경연 대회"로
공감

16
PPCG에 오신 것을 환영합니다! 첫 번째 게시물이 도전이자 팝콘 도전 일뿐만 아니라 예술적 도전이되기위한 용기를 가져 주셔서 감사합니다. 행운을 빕니다, 당신에게 최선을 다하고 싶습니다.
AdmBorkBork

4
@OliverGriffin 폐쇄 에 반대 투표 하고 당신을 위해 링크 된 이미지에 추가했습니다. 원하는 경우 주석을 제거 할 수 있습니다.
Addison Crump

2
마침내 오버플로가 스택되지 않는 접근법을 찾았지만 이제는 천천히 실행됩니다.
SuperJedi224

4
귀하의 질문을 다시 개설하기로 결정했으며 -1을 +1로 변경했습니다. 작업 편집 및 추가 정보 추가 또한 저는 지역 사회 비판에 대해 매우 수용적인 것에 대해 박수를 보냅니다. PPCG에 오신 것을 환영합니다! 즐기 셨으면 좋겠습니다.
Zach Gates

답변:


30

스펙트럼 에어 브러싱 (Python, PIL, scipy)

이것은 정교한 수학적 알고리즘을 사용하여 다채로운 넌센스를 생성합니다. 이 알고리즘은 Google의 PageRank 알고리즘과 관련이 있지만 웹 페이지 대신 픽셀에 적용됩니다.

홍수 접근 기반 방법과 달리 닭과 나무와 같은 이미지에 완전히 대처할 수 없을 것이라고 생각했기 때문에이 접근법을 취했습니다. 검은 선으로 완전히 둘러싸이지 않은 모양이 있습니다. 보시다시피, 그것은 하늘의 다른 부분에서 다른 색상으로 착색되는 경향이 있지만 일종의 작품입니다.

수학적으로 생각하는 것 : 그것이하는 일은 본질적으로 이미지의 while 픽셀의 인접 그래프를 구성 한 다음 그래프 Laplacian의 상위 25 개의 고유 벡터를 찾는 것입니다. (어둡지 않은 픽셀을 포함하기 때문에 연결의 가중치를 줄입니다. 앤티 앨리어싱을 처리하는 데 도움이되고 일반적으로 더 나은 결과를 제공하는 것처럼 보입니다.) 고유 벡터를 발견하면 역 고유 값으로 가중치를 부여하여 출력 이미지의 RGB 구성 요소를 형성하는 임의의 선형 조합.

계산 시간을 고려하여 이미지를 모두 축소하기 전에 축소 한 다음 다시 확대 한 다음 원래 이미지를 곱합니다. 그래도 입력 이미지에 따라 내 컴퓨터에서 약 2 분에서 10 분 정도 걸리지 만 어떤 이유로 닭은 17 분이 걸렸습니다.

실제로 각 고유 벡터의 색상과 강도를 제어 할 수있는 대화식 앱을 만들어이 아이디어를 유용한 것으로 바꿀 수 있습니다. 이렇게하면 하늘을 여러 섹션으로 나누고 이미지의 관련 기능을 선택하는 섹션을 페이드 아웃 할 수 있습니다. 그러나 나는 이것을 직접 할 계획이 없다 :)

출력 이미지는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

(호박에서는 잘 작동하지 않았으므로 생략합니다.)

그리고 여기 코드가 있습니다 :

import sys
from PIL import Image
import numpy as np
import scipy.sparse as sp
import scipy.sparse.linalg as spl
import os
import time

start_time = time.time()

filename = sys.argv[1]
img = Image.open(filename)
orig_w, orig_h = img.size

# convert to monochrome and remove any alpha channel
# (quite a few of the inputs are transparent pngs)
img = img.convert('LA')
pix = img.load()
for x in range(orig_w):
    for y in range(orig_h):
        l, a = pix[x,y]
        l = (255-a) + a*l/255
        a = 255
        pix[x,y] = l,a
img = img.convert('L')

orig_img = img.copy()

# resize to 300 pixels wide - you can get better results by increasing this,
# but it takes ages to run
orig_w, orig_h = img.size
print "original size:", str(orig_w)+ ', ' + str(orig_h)
new_w = 300
img = img.resize((new_w, orig_h*new_w/orig_w), Image.ANTIALIAS)

pix = img.load()
w, h = img.size
print "resizing to", str(w)+', '+str(h)

def coords_to_index(x, y):
    return x*h+y

def index_to_coords(i):
    return (int(i/h), i%h)

print "creating matrix"

A = sp.lil_matrix((w*h,w*h))

def setlink(p1x, p1y, p2x, p2y):
    i = coords_to_index(p1x,p1y)
    j = coords_to_index(p2x,p2y)
    ci = pix[p1x,p1y]/255.
    cj = pix[p2x,p2y]/255.
    if ci*cj > 0.9:
        c = 1
    else:
        c =  0.01
    A[i,j] = c
    return c

for x in range(w):
    for y in range(h):
        d = 0.
        if x>0:
            d += setlink(x,y,x-1,y)
        if x<w-1:
            d += setlink(x,y,x+1,y)
        if y>0:
            d += setlink(x,y,x,y-1)
        if y<h-1:
            d += setlink(x,y,x,y+1)
        i = coords_to_index(x,y)
        A[i,i] = -d

A = A.tocsr()

# the greater this number, the more details it will pick up on. But it increases
# execution time, and after a while increasing it won't make much difference
n_eigs = 25

print "finding eigenvectors (this may take a while)"
L, V = spl.eigsh(A, k=n_eigs, tol=1e-12, which='LA')

print "found eigenvalues", L

out = Image.new("RGB", (w, h), "white")
out_pix = out.load()

print "painting picutre"

V = np.real(V)
n = np.size(V,0)
R = np.zeros(n)
G = np.zeros(n)
B = np.zeros(n)

for k in range(n_eigs-1):
    weight = 1./L[k]
    R = R + V[:,k]*np.random.randn()*weight
    G = G + V[:,k]*np.random.randn()*weight
    B = B + V[:,k]*np.random.randn()*weight

R -= np.min(R)
G -= np.min(G)
B -= np.min(B)
R /= np.max(R)
G /= np.max(G)
B /= np.max(B)

for x in range(w):
    for y in range(h):
        i = coords_to_index(x,y)
        r = R[i]
        g = G[i]
        b = B[i]
        pixval = tuple(int(v*256) for v in (r,g,b))
        out_pix[x,y] = pixval

out = out.resize((orig_w, orig_h), Image.ANTIALIAS)
out_pix = out.load()
orig_pix = orig_img.load()

for x in range(orig_w):
    for y in range(orig_h):
        r,g,b = out_pix[x,y]
        i = orig_pix[x,y]/255.
        out_pix[x,y] = tuple(int(v*i) for v in (r,g,b))

fname, extension = os.path.splitext(filename)
out.save('out_' + fname + '.png')

print("completed in %s seconds" % (time.time() - start_time))

4
정말 멋지다. 아마 지금까지 내가 가장 좋아하는 것 중 하나입니다. 앤티 앨리어싱 및 개방형 영역을 처리하는 훌륭한 작업을 수행했으며 누군가 Link에서 마지막으로 채색되었습니다! (그것을 기다렸다가 :-P save set to desktop ) 나는 나의 오래된 영어 선생님이 정적 이미지로서 그것에 대해 무엇을 말했는지 궁금합니다 ... "그의 마음의 양면, 평화와 다른 것은 그 평화를 얻기 위해 필요한 싸움이 있습니다. " 젤다의 전설 게임에 대한 나의 사랑에 대해 충분히 ... 너무 오래 걸리는 것은 부끄러운 일입니다. 결과 파일이 얼마나 컸습니까? Ps Love 이미지 4 & 5
OliverGriffin

2
@donbright 고유 벡터를 이해할 수있는 3 학년 학생은 실제로 매우 밝은 아이가 될 것입니다. 그 수준에서 알고리즘을 설명 할 수 있는지 잘 모르겠습니다. 그러나 어쨌든 시도해 봅시다. 그림을 딱딱한 금속판에 인쇄한다고 상상해보십시오. 그런 다음 모든 검은 선을 조심스럽게 잘라 내고 탄성과 같이 훨씬 유연한 것으로 바꿉니다. 따라서 흰색 부분은 금속판이고 검은 부분은 유연한 직물입니다. 다음으로 우리는 모든 것을 현에서 공중에 매달아 자유롭게 움직입니다. 이제 금속판을 두드리면 진동이 발생합니다.
Nathaniel

2
@donbright (계속) ... 금속판을 치는 방법에 따라 다른 방식으로 진동합니다. 때로는 금속 부품 중 하나만 진동하고 다른 부품은 진동하지 않지만 다른 경우 (탄성으로 연결되어 있기 때문에) 한 판에 부딪 치면 다른 판이 움직이기 시작합니다. 이러한 다양한 진동 방식을 진동 모드 라고 합니다 . 이 프로그램은이 금속판의 일부 진동 모드를 시뮬레이션하지만 사운드를 생성하는 대신 어떤 색상을 그릴 지 결정하는 데 사용합니다.
Nathaniel

2
@donbright 금속판의 진동 시각화에 대한 자세한 내용은 여기 를 참조 하십시오 .
Nathaniel

2
@donbright (이 기술적 인 설명은 약간 잃을 수도 있지만 플레이트의 진동 모드도 고유 벡터 계산을 사용하여 계산되기 때문에이 설명이 효과가 있습니다. 가능하지만 내 코드와 동일한 계산은 아닙니다. 확실하지 않습니다.)
Nathaniel

25

파이썬 2 + PIL도, 나의 첫 색칠 공부

import sys, random
from PIL import Image

def is_whitish(color):
    return sum(color)>500

def get_zone(image, point, mask):
    pixels = image.load()
    w, h = image.size
    s = [point]
    while s:
        x, y = current = s.pop()
        mask[current] = 255
        yield current
        s+=[(i,j) for (i,j) in [(x,y-1),(x,y+1),(x-1,y),(x+1,y)] if 0<=i<w and 0<=j<h and mask[i,j]==0 and is_whitish(pixels[i,j])]

def get_zones(image):
    pixels = I.load()
    mask = Image.new('1',image.size).load()
    w,h = image.size
    for y in range(h):
        for x in range(w):
            p = x,y
            if mask[p]==0 and is_whitish(pixels[p]):
                yield get_zone(image, p, mask)



def apply_gradient(image, mincolor, maxcolor, points):
    minx = min([x for x,y in points])
    maxx = max([x for x,y in points])
    miny = min([y for x,y in points])
    maxy = max([y for x,y in points])
    if minx == maxx or miny==maxy:
        return
    diffx, diffy = (maxx - minx), (maxy-miny)
    stepr = (maxcolor[0] - mincolor[0] * 1.0) / diffy
    stepg = (maxcolor[1] - mincolor[1] * 1.0) / diffy
    stepb = (maxcolor[2] - mincolor[2] * 1.0) / diffy
    r,g,b = mincolor
    w, h = (abs(diffx+1),abs(diffy+1))
    tmp = Image.new('RGB', (w,h))
    tmppixels = tmp.load()
    for y in range(h):
        for x in range(w):
            tmppixels[x,y] = int(r), int(g), int(b)
        r+=stepr; g+=stepg; b+=stepb
    pixels = image.load()
    minx, miny = abs(minx), abs(miny)
    for x,y in points:
        try:
        pixels[x,y] = tmppixels[x-minx, y-miny]
    except Exception, e:
            pass

def colors_seq():
   yield (0,255,255)
   c = [(255,0,0),(0,255,0),(0,0,139)]
   i=0
   while True:i%=len(c);yield c[i];i+=1

def colorize(image):
    out = image.copy()
        COLORS = colors_seq()
    counter = 0
    for z in get_zones(image):
        c1 = COLORS.next()
        c2 = (0,0,0) if counter == 0 else (255,255,255)
        if counter % 2 == 1:
            c2, c1 = c1, c2
        apply_gradient(out, c1, c2, list(z))
        counter +=1
    return out

if __name__ == '__main__':
    I = Image.open(sys.argv[-1]).convert('RGB')
    colorize(I).show()

나는 지역을 '그라데이션'으로 채우고 다른 색주기를 사용한다는 점을 제외하고는 CarpetPython과 거의 동일했습니다.

나의 가장 장엄한 채색 : 여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오

내 컴퓨터의 계산 시간 :

  • 이미지 1 (중국 용) : 실제 0m2.862s 사용자 0m2.801s sys 0m0.061s

  • 이미지 2 (그리폰) : 실제 0m0.991s 사용자 0m0.963s sys 0m0.029s

  • 이미지 3 (유니콘 드래곤) : 실제 0m2.260s 사용자 0m2.239s 시스템 0m0.021s


멋진 그라디언트! for 루프 안에 for 루프를 넣을 때 첫 번째 루프 안에 다른 것이 없으면 더 들여 쓰기 할 필요가 없습니까?
OliverGriffin

물론 할 수있다 ! 복사 / 붙여 넣기 문제였습니다 ...
dieter

23

파이썬 2와 PIL : 사이키델릭 월드

간단한 알고리즘을 사용하여 하얀색 영역을 순환 팔레트의 색상으로 채 웁니다. 결과는 매우 화려하지만 실제와는 다릅니다.

이 그림에서 "흰색"부분은 흰색이 아닙니다. 회색 음영도 테스트해야합니다.

파이썬 2.7의 코드 :

import sys
from PIL import Image

WHITE = 200 * 3
cs = [60, 90, 120, 150, 180]
palette = [(199,199,199)] + [(R,G,B) for R in cs for G in cs for B in cs]

def fill(p, color):
    perim = {p}
    while perim:
        p = perim.pop()
        pix[p] = color
        x,y = p
        for u,v in [(x+dx, y+dy) for dx,dy in [(-1,0), (1,0), (0,1), (0,-1)]]:
            if 0 <= u < W and 0 <= v < H and sum(pix[(u,v)]) >= WHITE:
                perim.add((u,v))

for fname in sys.argv[1:]:
    print 'Processing', fname
    im = Image.open(fname)
    W,H = im.size
    pix = im.load()
    colornum = 0
    for y in range(H):
        for x in range(W):
            if sum(pix[(x,y)]) >= WHITE:
                thiscolor = palette[colornum % len(palette)]
                fill((x,y), thiscolor)
                colornum += 1
    im.save('out_' + fname)

사진 예 :

화려한 용

LSD의 호박


3
무서운 부분은 색상이 실제로 작동하는 것 같습니다. 각 이미지를 색칠하는 데 시간이 얼마나 걸렸으며 파일 크기는 얼마나 되었습니까?
OliverGriffin

1
이 프로그램은 각 이미지를 약 2 초 안에 채색합니다. 출력 이미지 크기는 입력 파일과 동일합니다. 파일 크기는 대부분 원본보다 10 % ~ 40 % 작습니다 (아마도 다른 JPEG 압축 설정이 사용되기 때문일 수 있습니다).
논리 기사

3
코드가 얼마나 짧은 지 완전히 감명 받았습니다! 또한 사용 가능한 색상을 효과적으로 제한하여 세트 팔레트에 보관하는 방법도 좋아합니다. 나는 실제로 그것을 정말로 좋아한다. 그런 종류의 그런지 (그것이 올바른 단어인가? 나는 예술가가 아니다) 분위기를 준다.
OliverGriffin

@OliverGriffin, 나는 당신이 그것을 좋아해서 기쁘다. 나는 밝거나 어두운 색상이없는 팔레트를 목표로했지만 여전히 약간의 대비가 있습니다. 이 색상 범위가 가장 만족 스러웠습니다.
논리 기사

11

MATLAB

function [output_image] = m3(input_file_name)
a=imread(input_file_name);
b=im2bw(a,0.85);
c=bwlabel(b);
h=vision.BlobAnalysis;
h.MaximumCount=10000;
ar=power(double(step(h,b)),0.15);
ar=[ar(1:max(max(c))),0];
f=cat(3,mod((ar(c+(c==0))-min(ar(1:end-1)))/ ...
    (max(ar(1:end-1))-min(ar(1:end-1)))*0.9+0.8,1),c*0+1,c*0+1);
g=hsv2rgb(f);
output_image=g.*cat(3,c~=0,c~=0,c~=0);

우리는 HSV 색 공간을 사용하고 흰색 영역 사이의 상대적인 크기에 따라 각 영역 색조를 선택합니다. 가장 큰 지역은 파란색 ( Hue = 0.7)이고 가장 작은 지역은 보라색 ( Hue = 0.8)입니다. 이 두 크기 사이의 영역에는 색조가 표시됩니다 0.7 -> 1=0 -> 0.8. 범위의 색조는 기능과 관련하여 선형으로 선택됩니다 area^0.15. 검은 색이 아닌 픽셀마다 채도와 값이 항상 1입니다.

이미지를 색칠하는 데 1 초도 걸리지 않습니다.

알고리즘이 제대로 작동하는 닫힌 영역이있는 3 개의 그림 :

용

다른 용

아마 다른 용

그리고 나머지 이미지들 :

용

다른 용

아마 다른 용

이 이미지에는 큰 흰색 연결 영역이 있으며 여러 색상으로 이상적으로 색칠해야합니다 (이 문제는 Nathaniel의 솔루션 에서 잘 해결되었습니다 .


예쁜 색상 조정 결과를위한 멋지고 짧은 코드! 이 영역을 사용하여 색조를 결정하는 방법을 좋아합니다. 평균 이미지를 처리하는 데 시간이 얼마나 걸렸으며 더 자세한 이미지에서 작동하지 않는 이유는 무엇입니까? 지역이 너무 작습니까?
OliverGriffin

1
@OliverGriffin 내 게시물에 올랐고 나머지 이미지를 추가했습니다.
randomra

7

베개와 파이썬 3

이 답변에는 코드가 약간 길지만 여기에 요점이 있습니다 .

  1. 입력 이미지를 가져와 알파 채널이 있으면 흰색 배경에 합성하십시오. (전체 이미지는 검은 색이고 투명성만으로 구분되기 때문에 최소한 닭고기 이미지에는 필요하므로 알파를 삭제하는 것은 도움이되지 않았습니다.)
  2. 결과를 그레이 스케일로 변환합니다. 우리는 압축이나 앤티 앨리어싱 아티팩트, 또는 회색 라인이 그다지 엉망이 아닌 것을 원치 않습니다.
  3. 결과의 2 단계 (흑백) 사본을 만듭니다. 회색 음영은 이미지에서 흰색과 가장 어두운 음영 사이의 구성 가능한 컷오프 임계 값에 따라 검은 색 또는 흰색으로 변환됩니다.
  4. 이미지의 모든 흰색 영역을 홍수로 채 웁니다. 플러드 필 작업의 시작점 위치를 고려한 선택 가능한 팔레트를 사용하여 색상을 임의로 선택합니다.
  5. 가장 가까운 이웃 색상으로 검은 선을 채우십시오. 이것은 모든 유색 영역이 칙칙한 검은 색으로 경계하지 않도록하여 앤티 앨리어싱을 다시 도입하는 데 도움이됩니다.
  6. 2 단계에서 회색조 이미지를 가져 와서 알파 마스크를 만듭니다. 가장 어두운 색상은 완전히 불투명하고 가장 밝은 색상은 완전히 투명합니다.
  7. 이 알파 마스크를 사용하여 단계 5의 컬러 이미지에 그레이 스케일 이미지를 합성합니다.

불행히도, 마지막 몇 단계는 여전히 어두운 색 영역에서 볼 수있는 더 밝은 "후광"을 제거하지는 않았지만 적어도 눈에 띄는 차이를 만들었습니다. 이미지 처리는 결코 내 연구 분야가 아니 었으므로 내가 여기서 시도한 것을 수행하는 데 더 성공적이고 효율적인 알고리즘이 있다는 것을 알고 있습니다.

지금까지 4 단계에서 선택할 수있는 팔레트는 두 가지뿐입니다. 순전히 임의의 팔레트와 매우 거친 "자연적인"팔레트는 상단 모서리에 하늘색, 하단 모서리에 잔디 색, 갈색 (바위 또는 나무)을 지정하려고합니다. )의 색상은 각면의 중간에 표시되고 가운데의 색상은 다양합니다. 성공은 ... 제한적입니다.


용법:

usage: paint_by_prog.py [-h] [-p PALETTE] [-t THRESHOLD] [-f | -F] [-d]
                        FILE [FILE ...]

Paint one or more line-art images.

positional arguments:
  FILE                  one or more image filenames

optional arguments:
  -h, --help            show this help message and exit
  -p PALETTE, --palette PALETTE
                        a palette from which to choose colours; one of
                        "random" (the default) or "natural"
  -t THRESHOLD, --threshold THRESHOLD
                        the lightness threshold between outlines and paintable
                        areas (a proportion from 0 to 1)
  -f, --proper-fill     fill under black lines with proper nearest-neighbour
                        searching (slow)
  -F, ---no-proper-fill
                        fill under black lines with approximate nearest-
                        neighbour searching (fast)
  -d, --debug           output debugging information

시료:

paint_by_prog.py -t 0.7 Gryphon-Lines.png 컬러 그리폰

paint_by_prog.py Dragon-Tattoo-Outline.jpg 컬러 만화 용

paint_by_prog.py -t 0.85 -p natural The-Pumpkin-Farm-of-Good-old-Days.jpg 컬러 농장 현장

paint_by_prog.py -t 0.7 Dragon-OutLine.jpg 착 색 된 그런 지 용

paint_by_prog.py stejar-arbore-schiţă-natura.png 매우 깃발 모양의 색깔의 나무

치킨은 잘 보이지 않으며 링크 이미지에 대한 가장 최근의 결과는 최고가 아닙니다. 이전 버전의 코드에서 나온 코드는 대체로 옅은 노란색이며 흥미로운 사막 분위기가 있습니다 ...


공연:

각 이미지는 기본 설정으로 처리하는 데 몇 초가 걸립니다. 이는 대략적인 가장 가까운 이웃 알고리즘이 5 단계에 사용됨을 의미합니다. 가장 가까운 이웃은 상당히 느려서 0.5 분 정도 걸립니다 (실제로 시간을 정하지는 않았습니다).


첫 번째 이미지는 특히 갈색 눈으로 환상적으로 보입니다. 잘 했어. 나는 또한 푸른 잔디, 호박의 갈색 들판과 자주색 구름을 얻는 것에 박수를 보냅니다.
OliverGriffin

3

자바

선택한 팔레트에서 원하는 색상을 선택하십시오.

경고 : 흰색 영역이 비정상적으로 작지 않으면 영역 검색이 현재 매우 느립니다.

import java.awt.Color;
import java.awt.image.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Random;
import java.util.Scanner;
import java.util.function.Supplier;

import javax.imageio.ImageIO;


public class Colorer{
    public static boolean isProbablyWhite(int x,int y){
        Color c=new Color(image.getRGB(x, y));
        if(c.getRed()<240)return false;
        if(c.getBlue()<240)return false;
        if(c.getGreen()<240)return false;
        return true;
    }
    static class Point{
        int x,y;
        public boolean equals(Object o){
            if(o instanceof Point){
                Point p=(Point)o;
                return x==p.x&&y==p.y;
            }
            return false;
        }
        public Point(int x,int y){
            this.x=x;
            this.y=y;
        }
    }
    static BufferedImage image;
    static int W,H;
    public static void check(Point p,List<Point>l1,List<Point>l2,List<Point>l3){
        if(!isProbablyWhite(p.x,p.y))return;
        if(l1.contains(p))return;
        if(l2.contains(p))return;
        if(l3.contains(p))return;
        l1.add(p);
    }
    public static void process(int x,int y,Color c){
        List<Point>plist=new LinkedList<>();
        int rgb=c.getRGB();
        plist.add(new Point(x,y));
        List<Point>l3=new LinkedList<>();
        int k=0;
        for(int i=0;i<W*H;i++){
            System.out.println(k=l3.size());
            List<Point>l2=new LinkedList<>();
            for(Point p:plist){
                int x1=p.x;
                int y1=p.y;
                if(x1>0){
                    check(new Point(x1-1,y1),l2,plist,l3);
                }
                if(y1>0){
                    check(new Point(x1,y1-1),l2,plist,l3);
                }
                if(x1<W-1){
                    check(new Point(x1+1,y1),l2,plist,l3);
                }
                if(y1<H-1){
                    check(new Point(x1,y1+1),l2,plist,l3);
                }
            }
            while(!plist.isEmpty()){
                l3.add(plist.remove(0));
            }
            if(l3.size()==k)break;
            plist=l2;
        }
        plist=l3;
        for(Point p:plist){
            image.setRGB(p.x,p.y,rgb);
        }
    }
    public static void main(String[]args) throws Exception{
        Random rand=new Random();
        List<Supplier<Color>>colgen=new ArrayList<>();
        colgen.add(()->{return new Color(rand.nextInt(20),50+rand.nextInt(200),70+rand.nextInt(180));});
        colgen.add(()->{return new Color(rand.nextInt(20),rand.nextInt(40),70+rand.nextInt(180));});
        colgen.add(()->{return new Color(150+rand.nextInt(90),10+rand.nextInt(120),rand.nextInt(5));});
        colgen.add(()->{int r=rand.nextInt(200);return new Color(r,r,r);});
        colgen.add(()->{return Arrays.asList(new Color(255,0,0),new Color(0,255,0),new Color(0,0,255)).get(rand.nextInt(3));});
        colgen.add(()->{return Arrays.asList(new Color(156,189,15),new Color(140,173,15),new Color(48,98,48),new Color(15,56,15)).get(rand.nextInt(4));});
        Scanner in=new Scanner(System.in);
        image=ImageIO.read(new File(in.nextLine()));
        final Supplier<Color>sup=colgen.get(in.nextInt());
        W=image.getWidth();
        H=image.getHeight();
        for(int x=0;x<W;x++){
            for(int y=0;y<H;y++){
                if(isProbablyWhite(x,y))process(x,y,sup.get());
            }
        }
        ImageIO.write(image,"png",new File("out.png"));
    }
}

파일 이름과 팔레트 ID라는 두 가지 입력이 필요합니다. 앤티 앨리어싱 보정을 포함하지만 투명 픽셀에 대한 로직은 포함하지 않습니다.

다음과 같은 팔레트가 현재 인식됩니다.

0: Blue and greeen
1: Blue
2: Red
3: Greyscale
4: Three-color Red, Green, and Blue
5: Classic Game Boy pallette (four shades of green)

결과 :

드래곤, 게임 보이 팔레트 :

여기에 이미지 설명을 입력하십시오

다른 용, 파랑 + 녹색 팔레트 :

여기에 이미지 설명을 입력하십시오

GOL 정물 모나리자 ( 이 프로그램 으로 렌더링 됨 ), 3 색 팔레트 :

여기에 이미지 설명을 입력하십시오


색상 맞춤 설정 가능 +1! :) 앤티 앨리어싱 문제를 해결할 수 있으면 훨씬 더 나아질 것입니다. 이 이미지들을 출력하는데 시간이 얼마나 걸렸습니까?
OliverGriffin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.