Sepia滤镜反色

3

我在倒置_sepia_滤镜时遇到了问题。 倒置滤镜的结果并非预期。

我的逻辑如下: processed_pixel = np.dot(sepia_filter, original_pixel)

这意味着: original_pixel = np.dot(np.linalg.inv(sepia_filter), processed_pixel)

这是我尝试过的代码-我还尝试了其他一些方法,例如分别反转颜色,然后解决线性方程组,但得到相同的结果,因此我认为我不理解某些关键点。

要求:

import numpy as np
from PIL import Image, ImageDraw

棕褐色滤镜代码:

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

反转棕褐色代码:
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

函数执行:

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)  

原始图像

enter image description here

滤波后的图像

enter image description here

反转滤波后的图像

enter image description here


我知道由于我们要截取计算结果并将其四舍五入到整数,所以做到完美的反转是不可能的。但我希望反转后的图像能够接近于原始图像。 虽然我对图像处理并不熟悉,但在数学上,这个问题看起来是完全有效的。


你能具体说明一下吗?因为我们无法运行你的代码。你是否收到了错误信息或者结果不是你期望的? - mapf
1
如果将filtered_image输入到inverse_sepia函数中会发生什么? - mapf
我有一些新的见解。请看我的评论,位于David的回答下面。 - mapf
@mapf 是的,根据解释我理解也是这样。但我只是好奇结果会是什么。 - Stas Buzuluk
@dhanushka 谢谢提供的链接。我只是想详细了解过滤器的工作原理 - 我的问题背后没有真正的项目,只是学习。但我会知道如何处理这类问题的:) 另外,恢复看起来令人印象深刻。 - Stas Buzuluk
显示剩余8条评论
2个回答

4
一个有趣的问题。 答案可能有点令人失望:棕褐色滤镜在理论上或实践中是不可逆的。

理论

代码中使用的数字矩阵是:

0.393   0.769   0.189
0.349   0.686   0.168
0.272   0.534   0.131

相应的符号矩阵如下:

 x       y       z
mx      my      mz
nx      ny      nz

当你计算符号矩阵的行列式时,结果为零。因此该矩阵不可逆,相应的棕褐色滤镜也不可逆。
其中,x=0.393 y=0.769 z=0.189 m=0.89 n=0.69

数值矩阵的行列式非零仅是由于数值精度(三位数)的限制。计算数值矩阵的行列式结果为0.000000121,基本上等于0,再加上一些舍入误差。

顺带一提,将像素值乘以数值矩阵等同于以下计算:

R = 0.393*r + 0.769*g + 0.189*b
G = 0.89*R
B = 0.69*R

其中,“rgb”是原始像素值,“RGB”是棕褐色像素值。

实践

新牛津美国词典将棕褐色定义为“一种与19世纪和20世纪初的单色照片特别相关的红褐色”

关键词是单色。棕褐色编码的是图像中每个像素的表观亮度,并不保留原始图像的颜色信息。尽管棕褐色图像看起来有些颜色,但这可能令人感到违反直觉。

为了更好地理解,请在您的代码中尝试以下矩阵

0.291  0.569  0.140
0.291  0.569  0.140
0.291  0.569  0.140

这将把图像转换为灰度图像,也就是一张黑白图片。与棕褐色相似,灰度图像只编码了每个像素的表面亮度,并没有保留任何颜色信息。不同的是,灰度以灰色调作为基础颜色,而棕褐色使用棕色调作为基础颜色。你在棕褐色图像中看到的其他颜色,如橙色、桃红色、黄色和黑色,只是RGB色彩空间中棕色的不同亮度级别。

灰度和棕褐色之间的另一个区别是,棕褐色能够编码更多层次的亮度。灰度有256种色调。棕褐色有346个不同的像素值。原因在于剪裁。给定一个输入像素(255, 255, 255),对应的棕褐像素在剪裁前是(345, 307, 239),在剪裁后是(255, 255, 239)。棕褐像素的红色分量在剪裁前有346个可能的值。对于每个红色值,绿色和蓝色的值成比例变化(G=0.89*RB=0.69*R)。

这是棕褐色调色板(不包括最暗的四种色调):

enter image description here

因此,你面临的实际问题是原始彩色图像有1600万种颜色,而棕褐色图像只有346种颜色。无法完全重现原始图像,因为棕褐色图像中的一个像素对应于原始图像中大约48000种可能的颜色之一。


3

现在你修复了代码,羊肉看起来有点可辨认,但是有很多裁剪的问题。我认为问题在于乌贼墨滤镜虽然可逆,但几乎是奇异的。你可以在SVD中看到其中一个奇异值比其他值大得多。因此,对于获得整数值的截断等小改变(您可以尝试四舍五入,可能会更好),这些操作将被逆操作放大很多,从而导致重建结果不太准确。


听起来是个不错的解释。我已经用更简单的数据尝试过代码,而且它能够正常工作。因此真正的问题是,你如何使其正常工作? - mapf
@mapf 问题在于,棕褐色滤镜加上四舍五入是有损的,所以你不能真正地这样做。最好的方法可能是在棕褐色滤镜中添加小心的抖动,然后在反向滤镜之后添加模糊,但我们已经超出了我的专业领域。 - David Eisenstat
嗯,有趣。这给了我一个想法。 - mapf
好的,我太累了,无法亲自尝试,但基本上你要做的是,在将乌贼墨滤镜应用到像素后,将该像素与旧像素进行比较,以获取应用于其的“实际”矩阵,即产生新像素而不剪切的矩阵,然后将该信息存储在某个地方。最后,所有这些“实际”变换的反转应该给出乌贼墨滤镜的真正反转。 - mapf
无论如何,我现在也明白为什么这当然不是一件简单的事情。因为要么你不知道怎么使用棕褐色滤镜并且必须手动重新制作它,也就是图像修复,这就像是一个超级专业的工作(或者使用人工智能),要么你已经应用了滤镜。在这种情况下,你也有原始图像,所以不需要反向滤镜。 - mapf
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接