【问题标题】:Colored Pixels Appearing When Trying to Compress Image (pics included)尝试压缩图像时出现彩色像素(包括图片)
【发布时间】:2012-03-29 02:17:36
【问题描述】:

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

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

感谢任何帮助。

谢谢,

贾斯蒂安

【问题讨论】:

  • 我不知道这个SVD库,我以前在C#中使用过,在Java中从未做过这种程序,但我想它可能只是压缩结果。您是否将您的结果与使用类似压缩方法的其他人进行了比较?
  • 白色像素会不会是上溢/下溢造成的?比如一个原本是黑色(0)的像素,由于有损压缩,变成-0.01,四舍五入到-1,然后在屏幕上变成255……

标签: java image-compression jama


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 2018-09-20
    • 1970-01-01
    • 2013-06-06
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-25
    • 2015-02-03
    相关资源
    最近更新 更多