5

我正在尝试使用奇异值分解来压缩给定的图像。我以为我拥有它,直到我注意到在整个过程中不断出现垃圾彩色像素。

垃圾像素

右上角显示的数字显示了迭代次数,其中 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 生成的值不同。

任何帮助表示赞赏。

谢谢,

贾斯蒂安

4

1 回答 1

3

这是你的图片分解成原色:

Lena SVD 分解为 RGB

显然,您以错误的方式将颜色转换为数字和数字。您将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 范围内。这将消除分散的白点。

于 2012-11-20T10:15:07.600 回答