我尝试使用奇异值分解来压缩给定的图像。我以为我拥有它,直到我注意到我在整个过程中一直出现垃圾色像素。
右上角显示的数字表示迭代次数,其中0是原始图像。
这是常见错误吗?我有什么遗失的吗?
我认为这可能与我的数学本身有关。我正在使用JAMA,一个java矩阵包,它为我处理这个问题。下面是我每次迭代的实现:
for (int i = 0; i < k; i++) {
Matrix step = (uColumns[i].times(sValues[i])).times(vColumns[i].transpose());
encoded = encoded.plus(step);
}
基本上我正在做(或尝试做)的是:
M = M + (s1*u1*v1^t)
我的实现是否有明显错误,或者错误可能是由于JAMA执行SVD的方式?根据我测试的结果,矩阵U和V中的值的符号在某些行中与Wolframalpha或Matlab生成的符号不同。
感谢任何帮助。
谢谢,
瑞斯蒂昂
答案 0 :(得分:3)
这是你的照片被分解为原色:
显然,您正在以错误的方式将颜色转换为数字,将数字转换为颜色。您将 int RGB像素视为单个数值并将其传递给SVD数字过程,但实际上RGB的信息将丢失。
大多数有损图像压缩方法都是通过丢弃低有效位来实现压缩。但是当你在单个 int 中有RGB时,每个R,G和B的低有效位与高有效位交织。当将像素作为单个数值传递时,此信息将丢失,并且SVD过程有效地将低有效R位解释为比高有效G位更重要,并且可能尝试完全丢弃所有G和B位,因为它们存储在“R”位之后。
例如,浅灰色像素(192,192,192)具有RGB值0xC0C0C0。以1%的误差压缩该值可以产生例如0xC2AE32。从压缩算法的角度来看,该值仅比原始值大1%,几乎不可察觉。但将其转换回RGB会产生(194,174,50)。 R分量确实几乎相同,但G和B都是腐败的。这是程序中“垃圾颜色”的来源。分解后的图像显示R分量被正确压缩,G分量在高压缩水平下变成随机噪声,B分量总是随机的。
您实施中的另一个问题是散布在黑暗区域的单个明亮像素。这些显然是由数字溢出和下溢引起的。例如,黑色像素(0,0,0)被编码为0x000000 = 0;有损压缩会引入一个小的误差,可以是正的也可以是负的,并且可以产生-1 = 0xFFFFFFFF;在RGB中它变为(255,255,255),这是白色的。
怎么做?
如果您只是测试SVD图像压缩并且足以使用灰度图像,那么您应该从RGB值中取出低字节,范围从0到255.相应地,当显示结果或写入时输出文件,将此值解释为灰度,或乘以0x010101以获得完整的RGB值。
如果需要压缩彩色图像,则应分别在R,G和B组件上运行SVD算法。这是处理颜色最简单的方法,但不是最有效的方法。为了获得更高的压缩率和不太明显的伪像,最好将RGB转换为Lab(亮度和两个色度通道);色度可以被压缩得更多,这就是JPEG的工作方式。
解压缩图像时,在计算SVD值但在屏幕上显示或写入文件之前,将所有结果值(R,G和B)钳制在0-255范围内。这将消除散乱的白点。