22from PIL import Image
33import numpy as np
44
5+ from . import brick
6+
7+
58class ProceduralTextures :
69 def improved_noise (self , baseFrequency , cellSize , octaves , persistance , lacunarity , coords ):
710 totalNoise = 0
@@ -29,7 +32,8 @@ def normalize(arr):
2932 scale = 1
3033 width = img_size [0 ]
3134 height = img_size [1 ]
32- opensimplex .seed (100 )
35+ rand_int = np .random .randint (0 , 2 ** 32 )
36+ opensimplex .seed (rand_int )
3337 result = np .zeros ((width , height ))
3438
3539 for y in range (width ):
@@ -45,38 +49,94 @@ def normalize(arr):
4549
4650 return noise_2d
4751
48- def noise_texture (self , img_size , baseFrequency , cellSize , octaves , persistance , lacunarity ):
49- noise_array = self .generate_noise (img_size , baseFrequency , cellSize , octaves , persistance , lacunarity )
52+ def noise_texture (self , img_size , colours , thresholds , noise_params ):
53+ noise_array = self .generate_noise (img_size ,
54+ noise_params ['base_frequency' ],
55+ noise_params ['cell_size' ],
56+ noise_params ['noise_octaves' ],
57+ noise_params ['noise_persistance' ],
58+ noise_params ['noise_lacunarity' ])
5059
5160 width = img_size [0 ]
5261 height = img_size [1 ]
5362
54- brown = np .array ([165 , 42 , 42 ]) / 255.0 # RGB for brown
55- green = np .array ([0 , 255 , 0 ]) / 255.0 # RGB for green
63+ new_colours = np .array (colours ) / 255.0
64+
65+ thresholds = np .sort (np .array (thresholds ))
5666
5767 color_noise = np .zeros ((* (width , height ), 3 ))
5868 for i in range (3 ):
59- color_noise [:,:,i ] = noise_array * ( green [ i ] - brown [ i ]) + brown [ i ]
69+ color_noise [:,:,i ] = np . interp ( noise_array , thresholds , new_colours [:, i ])
6070
61- #pic = np.array(noise_2d)
62- #pic = (pic - pic.min()) / (pic.max() - pic.min())
6371 pic = (color_noise * 255 ).astype (np .uint8 )
6472
6573 return Image .fromarray (pic , mode = "RGB" )
74+
75+ def apply_linear_gradient (self , noise_array , stop_point_x , stop_point_y , direction = 'horizontal' ):
76+ rows , cols = noise_array .shape
77+ if direction in ['horizontal' , 'horizontal_rev' ]:
78+ if direction == 'horizontal' :
79+ gradient = np .linspace (0 , stop_point_x , cols )
80+ gradient = np .tile (gradient , (rows , 1 ))
81+ else :
82+ gradient = np .linspace (stop_point_x , 0 , cols )
83+ gradient = np .tile (gradient , (rows , 1 ))
84+ elif direction in ['vertical' , 'vertical_rev' ]:
85+ if direction == 'vertical' :
86+ gradient = np .linspace (0 , stop_point_y , rows )
87+ gradient = np .tile (gradient , (cols , 1 )).T
88+ else :
89+ gradient = np .linspace (stop_point_y , 0 , rows )
90+ gradient = np .tile (gradient , (cols , 1 )).T
91+ elif direction in ['diagonal_tl' , 'diagonal_tr' , 'diagonal_bl' , 'diagonal_br' ]:
92+ x = np .linspace (0 , stop_point_x , cols )
93+ y = np .linspace (0 , stop_point_y , rows )
94+ xx , yy = np .meshgrid (x , y )
95+ if direction == 'diagonal_tl' :
96+ gradient = (xx + yy ) / 2
97+ elif direction == 'diagonal_tr' :
98+ gradient = (1 - xx + yy ) / 2
99+ elif direction == 'diagonal_bl' :
100+ gradient = (xx + 1 - yy ) / 2
101+ else : # diagonal_br
102+ gradient = (2 - xx - yy ) / 2
103+ else :
104+ raise ValueError ("Direction must be 'horizontal' or 'vertical'" )
105+
106+ return noise_array * gradient
107+
66108 def noiseify_image (self , img , baseFrequency , cellSize , octaves , persistance , lacunarity ):
67- img = img .convert ('RGB ' )
68- width , height = img . size
109+ img = img .convert ('RGBA ' )
110+ img_array = np . array ( img )
69111
70- new_width = round ( width / 8 )
71- new_height = round ( height / 8 )
112+ noise_array = self . generate_noise ([ 200 , 200 ], baseFrequency , cellSize , octaves , persistance , lacunarity )
113+ noise_array = self . apply_linear_gradient ( noise_array )
72114
73- noise_array = self .generate_noise ([new_width , new_height ], baseFrequency , cellSize , octaves , persistance , lacunarity )
74115
75- img_array = np .array (img )
116+ scaled_noise = Image .fromarray ((noise_array * 255 ).astype (np .uint8 ))
117+ scaled_noise = scaled_noise .resize (img .size , Image .LANCZOS )
118+ scaled_noise = np .array (scaled_noise ) / 255.0
119+
120+ alpha_mask = (scaled_noise > 0.3 ).astype (float )
121+ img_array [:, :, 3 ] = img_array [:, :, 3 ] * alpha_mask
122+
123+
124+ return Image .fromarray (img_array .astype ('uint8' ))
76125
77- for i in range (height - 1 ):
78- for j in range (width - 1 ):
79- if noise_array [round (i / 8 )][round (j / 8 )] < 0.5 :
80- img_array [i , j ] = (0 ,0 ,0 )
81126
82- return Image .fromarray (img_array .astype ('uint8' ))
127+ def generate_brick_texture (self , img_size , colours , noise_params , brick_size , mortar_size , mortar_colour , threshold ):
128+ colours = np .array (colours )
129+ colours = np .append (colours , np .full ((colours .shape [0 ], 1 ), 255 ), axis = 1 )
130+ noise_array = self .generate_noise (img_size ,
131+ noise_params ['base_frequency' ],
132+ noise_params ['cell_size' ],
133+ noise_params ['noise_octaves' ],
134+ noise_params ['noise_persistance' ],
135+ noise_params ['noise_lacunarity' ])
136+ return brick .create_brick_texture (img_size ,
137+ colours ,
138+ noise_array ,
139+ brick_size ,
140+ mortar_size ,
141+ mortar_colour ,
142+ threshold )
0 commit comments