I stacked with inverting sepia filter. The result of inverting the filter is not as expected.
My logic is the following: processed_pixel = np.dot(sepia_filter, original_pixel)
It means that: original_pixel = np.dot(np.inverse(sepia_filter), processed_pixel)
Here's code I've tried - I've also tried a couple of other approaches, such as reversing colours individually and then solving a system of linear equations but get the same result, so I assume that I don't understand something crucial.
Requirements:
import numpy as np
from PIL import Image, ImageDraw
Sepia filter code:
def get_pixel_after_sepia(source, pixel, sepia_filter):
colors = np.array(source.getpixel(pixel))
colors_new = tuple(map(int, np.dot(sepia_filter,colors))) + (255,) # apply filter, transform results to ints, cut to 255
return colors_new
def sepia(source, result_name):
result = Image.new('RGB', source.size)
sepia_filter = np.array([[0.393,0.769,0.189], [0.349,0.686,0.168], [0.272,0.534,0.131]])
# for every pixel
for x in range(source.size[0]):
for y in range(source.size[1]):
new_pixel = get_pixel_after_sepia(source, (x,y), sepia_filter)
result.putpixel((x, y),new_pixel)
result.save(result_name, "JPEG")
return result
Inverted sepia code:
def get_pixel_before_sepia(source, pixel, inversed_sepia_filter):
colors = np.array(source.getpixel(pixel))
colors_new = tuple(map(int, np.dot(inversed_sepia_filter, colors)))+ (255,)
return colors_new
def inverse_sepia(image_with_sepia, result_file):
result = Image.new('RGB', image_with_sepia.size)
sepia_filter = np.array([[0.393,0.769,0.189], [0.349,0.686,0.168], [0.272,0.534,0.131]])
inverse_sepia_filter = np.linalg.inv(sepia_filter)
for x in range(image_with_sepia.size[0]):
for y in range(image_with_sepia.size[1]):
new_pixel = get_pixel_before_sepia(image_with_sepia, (x,y), inverse_sepia_filter)
result.putpixel((x, y),new_pixel)
result.save(result_file, "JPEG")
return result
Functions execution:
image = Image.open("original_image.jpg")
filtered_image = sepia(image, "filtered.jpg") # result_pixel = dot_product(Filter, origin_pixel)
image_after_filter_reversing = inverse_sepia(filtered_image,'restored.jpg' ) # result_pixel = dot_product(Filter^(-1), filtering_result_pixel)
Original image
Filtered_image
Image_after_filter_reversing
I understand that it's impossible to make perfect reverse since we are cutting results of calculation and rounding them to int. But I expect the image after reversing to be quite close to the original. I'm a novice in image processing, but mathematically problem looks perfectly valid for me.



