Peinture par numéros (programmation, pas de chiffres)

56

Votre tâche consiste à créer un programme qui prend une image avec contour en noir et blanc (les images ci-dessous sont illustrées ci-dessous) et la remplit de couleur. C'est à vous de choisir comment vous séparez chaque région et de quelle couleur le remplir (vous pouvez même utiliser un GNA).

Par exemple:

sortie par exemple 1

Comme vous pouvez le constater, je suis clairement un artiste d’un calibre supérieur en ce qui concerne MS Paint.


Notation

Ceci est un concours de popularité, donc la réponse avec le plus grand nombre de votes nets gagne. Les électeurs sont encouragés à juger les réponses par

  • Critère d'entrée: toute image composée d'un fond blanc / gris clair et de contours noirs / gris foncé
  • Comment bien la coloration est faite; signifiant que peu ou pas de zones sont blanches contrairement à ce qui précède (à moins que vous n'utilisiez manifestement le blanc, par exemple pour les nuages)
  • Personnalisabilité des couleurs utilisées dans certaines sections
  • Comment le système fonctionne-t-il sur une gamme d'images différentes (de détails variables)
  • Postez combien de temps votre programme prend par image. Nous ne jouons peut-être pas du code-golf, mais un code plus court, plus rapide et plus efficace devrait être considéré comme meilleur.
  • La nouvelle image doit-elle être affichée à l'écran ou dans un fichier (pas plus de 2 Mo pour pouvoir être affichée dans la réponse)
  • Veuillez justifier pourquoi vous avez choisi de générer ce type d'image et commenter / expliquer le fonctionnement de votre code
  • L'applicabilité de la couleur utilisée à la forme respective à laquelle elle est liée (palette de couleurs réaliste, c'est-à-dire que l'herbe est verte, les clôtures en bois sont marron, etc.)

    "Je pourrais colorier chaque zone de manière aléatoire, mais si je pouvais identifier la" barrière "et la rendre de la même couleur, alors c'est quelque chose qui mérite des upvotes." - NathanMerrill

Comme il s’agit d’ un concours de popularité, vous pouvez également en juger par:

  • Attrait général (qualité de l'image)
  • Flair artistique; si vous pouvez programmer une coloration d'ombrage ou d'aquarelle, etc.

En général, la plus petite image produite (taille de fichier) de la plus haute qualité, avec le programme à jeun et le vote du public le plus élevé, l'emportera.

Si vous pensez que d'autres spécifications de jugement devraient être utilisées, merci de les recommander dans les commentaires de ce message.


Exemples

Je ne possède rien; tous les exemples d'images sont d'une licence Creative Commons.

exemple 1 en noir / blanc Source: https://pixabay.com/ro/stejar-arbore-schi%C5%A3%C4%83-natura-303890/ exemple 2 en noir / blanc Source: http://www.freestockphotos.biz/stockphoto/10665 exemple 3 en noir / blanc Source: http: / /crystal-rose1981.deviantart.com/art/Dragon-Tattoo-Outline-167320011 exemple 4 en noir / blanc Source: http://jaclynonacloudlines.deviantart.com/art/Gryphon-Lines-PF-273195317 exemple 5 en noir / blanc Source: http://captaincyprus.deviantart.com / art / Dragon-OutLine-331748686 exemple 6 en noir / blanc Source: http://electric-meat.deviantart.com/art/A-Heroes-Farewell-280271639 exemple 7 en noir / blanc Source: http://movillefacepalmplz.deviantart.com/art/Background-The-Pumpkin -Fermes-de-bons-vieux-jours-342865938


EDIT: En raison de l’anti-aliasing sur les lignes générant des pixels non noirs / blancs et certaines images pouvant contenir du gris au lieu de noir / blanc, vous pouvez tenter de l’aborder en prime. Cela devrait être assez facile à mon avis.

OliverGriffin
la source
4
A tout le monde: s'il vous plait, ne fermez pas ceci comme un "concours d'art" - il y a plus que ça
edc65
16
Bienvenue chez PPCG! Je vous félicite d’avoir eu le courage non seulement de faire de votre premier message un défi, mais pas seulement un défi pop-con, mais également un défi artistique. Bonne chance, je vous souhaite le meilleur et si vous restez dans les parages, je pense que vous irez loin ici.
AdmBorkBork
4
@OliverGriffin Je vote contre la fermeture et j'ai également ajouté des images que vous avez liées pour vous. Vous pouvez supprimer les commentaires si vous le souhaitez.
Addison Crump
2
J'ai finalement trouvé une approche qui ne débordera probablement pas, mais elle fonctionne maintenant plutôt lentement.
SuperJedi224
4
J'ai voté pour rouvrir votre question et j'ai changé mon -1 en +1. Bon travail d'édition et l'ajout d'informations supplémentaires. En outre, je vous félicite d’être si réceptif aux critiques de la communauté. Bienvenue chez PPCG! Je espère que vous l'apprécierez.
Zach Gates

Réponses:

30

Aérographie spectrale (Python, PIL, Scipy)

Ceci utilise un algorithme mathématique sophistiqué pour produire un non-sens coloré. L'algorithme est lié à l'algorithme PageRank de Google, mais pour les pixels au lieu des pages Web.

J'ai choisi cette approche parce que je pensais que, contrairement aux méthodes basées sur le remplissage par inondation, elle pourrait peut-être gérer des images telles que le poulet et l'arbre, où certaines formes ne sont pas entièrement délimitées par des lignes noires. Comme vous pouvez le constater, cela fonctionne en quelque sorte, même s'il a également tendance à colorer différentes parties du ciel de différentes couleurs.

Pour les mathématiciens, il s’agit essentiellement de construire le graphe de contiguïté des pixels tout en image, puis de rechercher les 25 premiers vecteurs propres du graphe laplacien. (Sauf que ce n'est pas tout à fait parce que nous incluons les pixels sombres, nous donnons simplement un poids inférieur à leurs connexions. Cela aide à traiter l'antialiasing et semble également donner de meilleurs résultats en général.) Ayant trouvé les vecteurs propres, cela crée une combinaison linéaire aléatoire d'entre eux, pondérés par leurs valeurs propres inverses, pour former les composantes RVB de l'image de sortie.

Dans l'intérêt du temps de calcul, l'image est réduite avant de faire tout cela, puis redimensionnée, puis multipliée par l'image d'origine. Néanmoins, il ne fonctionne pas rapidement, prenant entre 2 et 10 minutes environ sur ma machine, en fonction de l'image d'entrée, bien que, pour une raison quelconque, le poulet ait pris 17 minutes.

En fait, il pourrait être possible de transformer cette idée en quelque chose d’utile en créant une application interactive permettant de contrôler la couleur et l’intensité de chacun des vecteurs propres. De cette façon, vous pouvez masquer celles qui divisent le ciel en différentes sections et créer des atténuations dans celles qui décrivent les caractéristiques pertinentes de l'image. Mais je n'ai pas l'intention de le faire moi-même :)

Voici les images de sortie:

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

(Cela n'a pas très bien fonctionné sur les citrouilles, alors je l'ai omis.)

Et voici le code:

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))
Nathaniel
la source
4
C'est vraiment cool. Probablement l'un de mes favoris jusqu'à présent. Vous avez fait un excellent travail de traitement de l'antialiasing et des zones ouvertes, et quelqu'un a enfin coloré dans Link! (Attendu que :-P sauver ensemble sur le bureau ) Je me demande ce que mon ancien professeur d' anglais aurait dit à ce sujet comme une image statique ... « Il montre les deux côtés de son cœur, d' un côté il y a la paix et sur la d’autre il ya le combat nécessaire pour obtenir cette paix ". Assez parlé de mon amour pour les jeux Legend of Zelda ... C'est vraiment dommage que cela prenne si longtemps. Quelle était la taille des fichiers résultants? Ps Love images 4 & 5
OliverGriffin
2
@donbright, un élève de 3e année capable de comprendre les vecteurs propres serait un enfant très brillant - je ne suis pas sûr qu'il me soit possible d'expliquer l'algorithme à ce niveau. Mais laissez-moi essayer quand même: imaginez que nous imprimions la photo sur une feuille de métal rigide. Ensuite, nous coupons soigneusement toutes les lignes noires et les remplaçons par quelque chose de beaucoup plus flexible, comme un élastique. Donc, les parties blanches sont des plaques de métal et les parties noires sont des tissus souples. Ensuite, nous suspendons le tout dans les airs avec une ficelle, ce qui permet de le déplacer librement. Maintenant, si nous tapotons les plaques de métal, elles vibreront ...
Nathaniel
2
@donbright (suite) ... Selon la manière dont vous frappez la plaque de métal, celle-ci vibre de différentes manières. Peut-être que parfois une seule des pièces métalliques va vibrer et pas les autres, mais d’autres fois (parce qu’elles sont reliées par un élastique), frapper une plaque en fera aussi bouger une autre. Ces différentes manières de vibrer s'appellent des modes vibratoires . Ce programme simule certains des modes de vibration de cette plaque métallique, mais au lieu de générer du son, il les utilise pour déterminer la couleur à dessiner.
Nathaniel
2
@donbright Vous pouvez également voir ici pour plus d'informations sur la visualisation des vibrations des plaques métalliques.
Nathaniel
2
@donbright (cette explication plus technique risque de vous perdre un peu, mais cette explication fonctionne, car les modes de vibration d'une plaque sont également calculés à l'aide d'un calcul de vecteur propre. pas vraiment sûr.)
Nathaniel
25

Python 2 + PIL aussi, mon premier livre de coloriage

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()

J'ai fait à peu près la même chose que CarpetPython, sauf que je remplis la région de "dégradés" et utilise un cycle de couleur différent.

Mes plus beaux coloriages: entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Temps de calcul sur ma machine:

  • image 1 (dragon chinois): utilisateurs réels de 0m2.862s 0m2.801s sys 0m0.061s

  • image 2 (gryffon): real 0m0.991s 0m0.963s sys 0m0.029s sys

  • image 3 (dragon unicornish): vrais utilisateurs 0m2.260s 0m2.239s sys 0m0.021s

dieter
la source
De jolis gradients! Lorsque vous collez une boucle for dans une boucle for sans autre élément dans la première, n'avez-vous pas besoin d'indenter davantage?
OliverGriffin
bien sûr que vous faites! c'était un problème de copier / coller ...
dieter
23

Python 2 et PIL: des mondes psychédéliques

J'ai utilisé un algorithme simple pour remplir chaque zone blanche d'une couleur provenant d'une palette de cycles. Le résultat est très coloré, mais pas très réaliste.

Notez que les parties "blanches" de ces images ne sont pas très blanches. Vous devrez également tester les nuances de gris.

Code en Python 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)

Exemple d'images:

Un dragon coloré

Citrouilles sur LSD

Logic Knight
la source
3
La partie effrayante est que les couleurs semblent réellement fonctionner. Combien de temps avez-vous mis à colorier chaque image et quelle était la taille des fichiers?
OliverGriffin
1
Le programme colorie chaque image en environ 2 secondes. Les dimensions de l'image de sortie sont les mêmes que celles des fichiers d'entrée. La taille des fichiers est généralement inférieure de 10% à 40% à celle des originaux (probablement parce que différents paramètres de compression JPEG sont utilisés).
Logic Knight le
3
Je suis vraiment impressionné par la brièveté du code! J'aime aussi la façon dont vous limitez efficacement les couleurs disponibles, tout en conservant une palette définie. En fait, je les aime vraiment, ça donne une sorte de grunge (est-ce le bon mot? Je ne suis pas un artiste).
OliverGriffin
@ OliverGriffin, je suis heureux que cela vous plaise. Je visais une palette sans couleurs vives ou sombres, mais avec un peu de contraste. Cette gamme de couleurs semblait avoir les résultats les plus agréables.
Logic Knight
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);

Nous utilisons l’espace colorimétrique HSV et choisissons chaque teinte des régions en fonction de sa taille relative entre les régions blanches. La plus grande région sera bleue ( Hue = 0.7) et la plus petite, violette ( Hue = 0.8). Les régions situées entre ces deux tailles se voient attribuer des teintes dans la plage 0.7 -> 1=0 -> 0.8. La teinte de la plage est sélectionnée linéairement par rapport à la fonction area^0.15. La saturation et la valeur sont toujours de 1 pour chaque pixel non noir.

Il faut moins d’une seconde pour colorer une image.

Les 3 images avec les régions fermées où l'algorithme fonctionne correctement:

dragon

un autre dragon

peut-être un autre dragon

Et le reste des images:

dragon

un autre dragon

peut-être un autre dragon

Sur ces images, il y a de grandes régions connectées blanches qui devraient idéalement être colorées par plusieurs couleurs (ce problème a été joliment résolu dans la solution de Nathaniel .

randomra
la source
Code sympa et court pour de jolis résultats de couleurs coordonnées! J'aime la façon dont vous avez utilisé la zone pour aider à déterminer la teinte. Combien de temps a pris le traitement de l'image moyenne et pourquoi cela n'a-t-il pas fonctionné avec certaines des images les plus détaillées? Les zones étaient-elles trop petites?
OliverGriffin
1
@OliverGriffin Anwered dans mon post et a ajouté le reste des images.
randomra
7

Python 3 avec oreiller

Le code est un peu long à inclure dans cette réponse, mais voici l'essentiel .

  1. Prenez l'image d'entrée et, si elle possède un canal alpha, composez-la sur un fond blanc. (Nécessaire au moins pour l'image de poulet, car toute l'image était en noir et se distinguait uniquement par la transparence. Il n'était donc pas utile de supprimer l'alpha.)
  2. Convertir le résultat en niveaux de gris; nous ne voulons pas que des artefacts de compression ou d'anti-crénelage, ou des lignes grises qui ne sont pas tout à fait grises, nous gâchent.
  3. Créez une copie à deux niveaux (noir et blanc) du résultat. Les nuances de gris sont converties en noir ou en blanc en fonction d'un seuil de coupure configurable entre le blanc et la nuance la plus sombre de l'image.
  4. Remplissez chaque zone blanche de l'image. Les couleurs sont choisies au hasard, en utilisant une palette sélectionnable qui prend en compte l'emplacement du point de départ pour l'opération de remplissage.
  5. Remplissez les lignes noires avec les couleurs de leur voisin le plus proche. Cela nous aide à réintroduire l'anti-aliasing, en empêchant chaque région colorée d'être bordée de noir.
  6. Prenez l’image en niveaux de gris de l’étape 2 et créez-en un masque alpha: la couleur la plus sombre est totalement opaque, la couleur la plus claire est totalement transparente.
  7. Composez l'image en niveaux de gris sur l'image colorée de l'étape 5 à l'aide de ce masque alpha.

Malheureusement, ces dernières étapes n’ont toujours pas permis d’éliminer les «halos» plus clairs qui sont visibles dans les régions de couleur plus foncée, mais ils ont fait une différence notable, au moins. Le traitement d'images n'a jamais été mon domaine d'étude, donc je sais qu'il existe des algorithmes plus performants et plus efficaces pour faire ce que j'ai essayé de faire ici ... mais bon.

Jusqu'à présent, il n'y a que deux palettes sélectionnables pour l'étape 4: une palette purement aléatoire et une palette très "naturelle" qui essaie d'associer la couleur du ciel aux coins supérieurs, la couleur de l'herbe aux coins inférieurs, le brun (roches ou bois). ) couleurs au milieu de chaque côté et couleurs variées au centre. Le succès a été ... limité.


Usage:

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

Échantillons:

paint_by_prog.py -t 0.7 Gryphon-Lines.png Grain de couleur

paint_by_prog.py Dragon-Tattoo-Outline.jpg Dragon de couleur

paint_by_prog.py -t 0.85 -p natural The-Pumpkin-Farm-of-Good-old-Days.jpg Scène de ferme colorée

paint_by_prog.py -t 0.7 Dragon-OutLine.jpg Dragon de couleur grunge

paint_by_prog.py stejar-arbore-schiţă-natura.png Arbre coloré, très ressemblant à un drapeau

Le poulet n'a pas l'air très beau et mon dernier résultat pour l'image de Link n'est pas le meilleur; celui qui provenait d'une version précédente du code était en grande partie jaune pâle et avait une atmosphère de désert intéressante à ce sujet ...


Performance:

Chaque image prend quelques secondes à traiter avec les paramètres par défaut, ce qui signifie qu'un algorithme approximatif du plus proche voisin est utilisé pour l'étape 5. Le vrai voisin le plus proche est nettement plus lent, prenant peut-être une demi-minute (je ne l'ai pas encore chronométré).

Tim Pederick
la source
La première image est fantastique, surtout cet œil brun. Bon travail. Je vous félicite également d’avoir de l’herbe verte, des champs de citrouilles bruns et des nuages ​​pourpres.
OliverGriffin
3

Java

Sélection aléatoire des couleurs parmi votre choix de palette.

Avertissement: La région trouve actuellement très lente, à moins que les régions blanches soient inhabituellement petites.

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"));
    }
}

Requiert deux entrées: le nom de fichier et l'ID de palette. Inclut une correction d'anticrénelage, mais n'inclut pas de logique pour les pixels transparents.

Les palettes suivantes sont actuellement reconnues:

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)

Résultats:

Dragon, palette Game Boy:

entrez la description de l'image ici

L'autre dragon, palette bleu + vert:

entrez la description de l'image ici

GOL Nature morte Mona Lisa (telle que rendue par ce programme ), palette tricolore:

entrez la description de l'image ici

SuperJedi224
la source
+1 pour votre personnalisation de couleur! :) si vous pouviez résoudre le problème d'antialiasing, cela aurait l'air encore mieux. Combien de temps vous a-t-il fallu pour produire ces images?
OliverGriffin