J'ai un code pour tracer des dégradés radiaux avec numpy. Jusqu'à présent, cela ressemble à ceci:

import numpy as np
import matplotlib.pyplot as plt

arr = np.zeros((256,256,3), dtype=np.uint8)
imgsize = arr.shape[:2]
innerColor = (0, 0, 0)
outerColor = (255, 255, 255)
for y in range(imgsize[1]):
    for x in range(imgsize[0]):
        #Find the distance to the center
        distanceToCenter = np.sqrt((x - imgsize[0]//2) ** 2 + (y - imgsize[1]//2) ** 2)

        #Make it on a scale from 0 to 1innerColor
        distanceToCenter = distanceToCenter / (np.sqrt(2) * imgsize[0]/2)

        #Calculate r, g, and b values
        r = outerColor[0] * distanceToCenter + innerColor[0] * (1 - distanceToCenter)
        g = outerColor[1] * distanceToCenter + innerColor[1] * (1 - distanceToCenter)
        b = outerColor[2] * distanceToCenter + innerColor[2] * (1 - distanceToCenter)
        # print r, g, b
        arr[y, x] = (int(r), int(g), int(b))

plt.imshow(arr, cmap='gray')
plt.show()

Existe-t-il un moyen d'optimiser ce code avec des fonctions numpy et d'améliorer la vitesse ? Cela devrait ressembler à ceci après: Dégradé circulaire

4
bunkus 14 mars 2019 à 12:29

2 réponses

Meilleure réponse

Vous pouvez utiliser la vectorisation pour calculer très efficacement la distance sans avoir besoin d'une boucle for:

x_axis = np.linspace(-1, 1, 256)[:, None]
y_axis = np.linspace(-1, 1, 256)[None, :]

arr = np.sqrt(x_axis ** 2 + y_axis ** 2)

Ou vous pouvez utiliser un maillage:

x_axis = np.linspace(-1, 1, 256)
y_axis = np.linspace(-1, 1, 256)

xx, yy = np.meshgrid(x_axis, y_axis)
arr = np.sqrt(xx ** 2 + yy ** 2)

Et interpoler entre inner et outer couleurs en utilisant à nouveau la diffusion

inner = np.array([0, 0, 0])[None, None, :]
outer = np.array([1, 1, 1])[None, None, :]

arr /= arr.max()
arr = arr[:, :, None]
arr = arr * outer + (1 - arr) * inner
5
Nils Werner 14 mars 2019 à 10:50

En raison de la symétrie, il suffit en fait de calculer un quart de l'image 256 * 256, soit 64 * 64, puis de la faire pivoter de 90 degrés pièce par pièce et de les combiner. De cette façon, le temps total est 1/4 fois supérieur au calcul de 256 * 256 pixels.

Ce qui suit est un exemple.

import numpy as np
import matplotlib.pyplot as plt

##Just calculate 64*64
arr = np.zeros((64,64,3), dtype=np.uint8)
imgsize = arr.shape[:2]
innerColor = (0, 0, 0)
outerColor = (255, 255, 255)
for y in range(imgsize[1]):
    for x in range(imgsize[0]):
        #Find the distance to the corner
        distanceToCenter = np.sqrt((x) ** 2 + (y - imgsize[1]) ** 2)

        #Make it on a scale from 0 to 1innerColor
        distanceToCenter = distanceToCenter / (np.sqrt(2) * imgsize[0])

        #Calculate r, g, and b values
        r = outerColor[0] * distanceToCenter + innerColor[0] * (1 - distanceToCenter)
        g = outerColor[1] * distanceToCenter + innerColor[1] * (1 - distanceToCenter)
        b = outerColor[2] * distanceToCenter + innerColor[2] * (1 - distanceToCenter)
        # print r, g, b
        arr[y, x] = (int(r), int(g), int(b))
#rotate and combine
arr1=arr
arr2=arr[::-1,:,:]
arr3=arr[::-1,::-1,:]
arr4=arr[::,::-1,:]
arr5=np.vstack([arr1,arr2])
arr6=np.vstack([arr4,arr3])
arr7=np.hstack([arr6,arr5])
plt.imshow(arr7, cmap='gray')
plt.show()
1
Gary Yu 14 mars 2019 à 10:22