import PIL.Image as Image import PIL.ImageDraw as ImageDraw import PIL.ImageFilter as ImageFilter import numpy import math block_size = 15 def make_kernel(axis1, axis2, func1 = math.cos, func2 = math.cos, total_r = block_size // 2): '''Makes a scaled sinc kernel with the size and alignment from axis1 and axis2. For example, axis1 = (6,0) and axis2 = (0,3) gives the first zero at the border of an ellipse 12 pixels wide and 6 pixels high. ''' len1 = math.sqrt(numpy.dot(axis1, axis1)) len2 = math.sqrt(numpy.dot(axis2, axis2)) axis1 = numpy.asarray(axis1) / len1 axis2 = numpy.asarray(axis2) / len2 halfsize = block_size // 2 result = numpy.zeros((block_size, block_size)) for x in range(block_size): for y in range(block_size): pos = (x - halfsize, y - halfsize) pos1 = numpy.dot(axis1, pos) / len1 pos2 = numpy.dot(axis2, pos) / len2 r = math.sqrt(numpy.dot(pos, pos)) / total_r if r < 1.0: scaling = math.cos(r * math.pi / 2) # Fall to zero at edges else: scaling = 0.0 value = func1(pos1 * math.pi / 2) * func2(pos2 * math.pi / 2) result[y,x] = value * scaling # Normalize sum and maximum result -= result.sum() / result.size result /= abs(result).max() return result def kernel_to_image(kernel): array = (kernel * 128 + 127).clip(0, 255).astype(numpy.uint8) return Image.fromarray(array) # n pixel round kernels round_kernels = [ make_kernel((0, 1), (1,0)), make_kernel((0, 2), (2,0)), make_kernel((0, 3), (3,0)), make_kernel((0, 5), (5,0)), make_kernel((0, 5), (1,0)), make_kernel((0, 1), (5,0)), make_kernel((0, 1), (1,0), total_r = 3), make_kernel((0, 2), (2,0), total_r = 5) ] # 4x40 pixel directional kernels directional_kernels_1 = [] directional_kernels_2 = [] for angle in range(0, 180, 30): a = angle * math.pi / 180. directional_kernels_1.append(make_kernel( (math.cos(a) * 3, math.sin(a) * 3), (math.sin(a) * 20, math.cos(a) * 20) )) directional_kernels_2.append(make_kernel( (math.cos(a) * 5, math.sin(a) * 5), (math.sin(a) * 20, math.cos(a) * 20), math.sin, math.cos )) kernel_to_image(round_kernels[0]).save('round0.png') kernel_to_image(round_kernels[1]).save('round1.png') kernel_to_image(round_kernels[2]).save('round2.png') kernel_to_image(directional_kernels_1[0]).save('dir0.png') kernel_to_image(directional_kernels_2[0]).save('dir1.png') def get_sample(image, x, y): halfsize = block_size // 2 if x < halfsize: x = halfsize if y < halfsize: y = halfsize if x >= image.size[0] - halfsize: x = image.size[0] - halfsize - 1 if y >= image.size[1] - halfsize: y = image.size[1] - halfsize - 1 tile = image.crop((x - halfsize, y - halfsize, x + halfsize + 1, y + halfsize + 1)).convert('L') array = numpy.asarray(tile) / 255. features = [] for kernel in round_kernels: features.append(abs((kernel * array).sum())) # maxval = 0.0 # for kernel in directional_kernels_1: # maxval = max(maxval, abs((kernel * array).sum())) # features.append(maxval) # maxval = 0.0 # for kernel in directional_kernels_2: # maxval = max(maxval, abs((kernel * array).sum())) # features.append(maxval) return features if __name__ == '__main__': import sys image = Image.open(sys.argv[1]).convert('L') sample_len = len(get_sample(image, 0, 0)) outimages = [Image.new('L', image.size) for i in range(sample_len)] outdraws = [ImageDraw.Draw(img) for img in outimages] step = 4 for x in range(0, image.size[0] - block_size, step): for y in range(0, image.size[1] - block_size, step): features = get_sample(image, x, y) for i, value in enumerate(features): outdraws[i].rectangle((x,y,x + step, y + step), fill = int(value * 255)) for i, img in enumerate(outimages): img.save('texture%02d.png' % i)