else/ImageFilters/imagefilters.py
2016-07-05 00:24:08 -07:00

116 lines
No EOL
3.8 KiB
Python

import PIL.Image
KERNEL_GAUSSIAN_BLUR = [
[1, 2, 1],
[2, 3, 2],
[1, 2, 1],
]
KERNEL_EDGE_DETECTION_H = [
[-2, 0, 2],
[-2, 0, 2],
[-2, 0, 2],
]
KERNEL_EDGE_DETECTION_V = [
[-2, -2, 2],
[0, 0, 0],
[2, 2, 2],
]
def index_to_xy(index, width):
(y, x) = divmod(index, width)
return (x, y)
def xy_to_index(x, y, width):
return (y * width) + x
def add(image_a, image_b):
pixels_a = image_a.getdata()
pixels_b = image_b.getdata()
assert len(pixels_a) == len(pixels_b)
pixels_c = [a + b for (a, b) in zip(pixels_a, pixels_b)]
new_image = PIL.Image.new('L', (image_a.size))
new_image.putdata(pixels_c, 1, 0)
return new_image
def apply_filter(old_image, kernel):
kernel_height = len(kernel)
kernel_width = len(kernel[0])
if (kernel_height % 2 != 1) or (kernel_width % 2 != 1):
raise ValueError('Kernel is not of odd size')
if any(len(segment) != kernel_width for segment in kernel):
raise ValueError('Kernel is of inconsistent size')
kernel_center = (kernel_width // 2, kernel_height // 2)
flat_kernel = list(flatten_list(kernel))
lower = min(flat_kernel)
lower = min(0, lower * 255)
upper = max(flat_kernel)
upper = max(255, upper * 255)
print(lower, upper)
(image_width, image_height) = old_image.size
old_pixels = old_image.getdata()
new_pixels = list(old_image.getdata())
for (index, old_pixel) in enumerate(old_pixels):
operation_sum = 0
operation_denominator = 0
(x, y) = index_to_xy(index, image_width)
#print(x, y, index)
for (kernel_y, kernel_row) in enumerate(kernel):
#print(kernel_row)
subject_y = y - (kernel_center[1] - kernel_y)
if subject_y < 0 or subject_y >= image_height:
continue
for (kernel_x, kernel_entry) in enumerate(kernel_row):
if kernel_entry == 0:
continue
subject_x = x - (kernel_center[0] - kernel_x)
if subject_x < 0 or subject_x >= image_width:
continue
subject = old_pixels[xy_to_index(subject_x, subject_y, image_width)]
#print(x, y, subject_x, subject_y, kernel_entry, subject)
operation_sum += kernel_entry * subject
operation_denominator += kernel_entry
operation_denominator = max(1, operation_denominator)
operation_avg = abs(operation_sum / operation_denominator)
#n_operation_avg = int(map_range(operation_avg, lower, upper, 0, 255))
if index % 4096 == 0:
#print(x, y, operation_sum, operation_denominator, operation_avg)
print(y, '/', image_height)
new_pixels[index] = operation_avg
#print(new_pixels)
new_image = PIL.Image.new('L', (old_image.size))
new_image.putdata(new_pixels, 1, 0)
#print(new_pixels)
#print(list(new_image.getdata()))
return new_image
def flatten_list(li):
for element in li:
if hasattr(element, '__iter__'):
yield from flatten_list(element)
else:
yield element
def map_range(x, old_low, old_high, new_low, new_high):
'''
Given a number x in range [old_low, old_high], return corresponding
number in range [new_low, new_high].
'''
if x > old_high or x < old_low:
raise ValueError('%d not in range [%d..%d]' % (x, old_low, old_high))
percentage = (x - old_low) / (old_high - old_low)
y = (percentage * (new_high - new_low)) + new_low
return y
if __name__ == '__main__':
i = PIL.Image.open('icon.jpg')
i = i.convert('L')
i = apply_filter(i, KERNEL_GAUSSIAN_BLUR)
a = apply_filter(i, KERNEL_EDGE_DETECTION_H)
b = apply_filter(i, KERNEL_EDGE_DETECTION_V)
i = add(a, b)
i.save('icon.png')