97 lines
No EOL
3.2 KiB
Python
97 lines
No EOL
3.2 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],
|
|
]
|
|
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 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):
|
|
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('ear.jpg')
|
|
i = i.convert('L')
|
|
i = apply_filter(apply_filter(i, KERNEL_GAUSSIAN_BLUR), KERNEL_EDGE_DETECTION_H)
|
|
i.save('ear.png') |