Colored Pixels Appearing When Trying to Compress Image (pics included)

I'm trying to compress a given image using Singular Value Decomposition. I thought I had it, until I noticed that I keep getting garbage colored pixels appearing throughout the process.

垃圾像素

The number shown at the top right shows the number of iterations where 0 is the original image.

Is this a common error? Is there something I'm missing?

I figure it may have to do with my math, itself. I'm using JAMA, a java matrix package which handles this for me. Below is my implementation for each iteration:

for (int i = 0; i < k; i++) {    
    Matrix step = (uColumns[i].times(sValues[i])).times(vColumns[i].transpose());
    encoded = encoded.plus(step);
}

Essentially what I'm doing (or trying to do) is:

M = M + (s1*u1*v1^t)

Is there something obviously wrong with my implementation, or is the error possibly due to the way JAMA performs SVD? From what I've tested, the sign of the values in matrix U and V vary in some rows from those produced by Wolframalpha or Matlab.

Any help is appreciated.

Thanks,

Justian


This is your picture decomposed into prime colors:

Lena SVD分解为RGB

Apparently you are converting colors to numbers and numbers to colors in a wrong way. You are treating the int RGB pixel as a single numeric value and pass it through the SVD numeric procedure, but the information that it's actually RGB is lost.

Most lossy image compression methods are achieving compression by discarding low-significance bits. But when you have RGB in a single int , low-significance bits of each R, G and B are interleaved with high-significance bits. When passing the pixel as a single numeric value, this information is lost, and the SVD procedure effectively interpretes the low-significance R bits as more significant than high-significance G bits, and may attempt to discard all G and B bits completely because they are stored "after" R bits.

For example, a light gray pixel (192,192,192) has RGB value 0xC0C0C0. Compressing this value with 1% error can yield, for example, 0xC2AE32. From the compression algorithm's point of view, this value is only 1% larger than the original which is almost not noticeable. But converting this back to RGB gives (194,174,50). The R component is indeed almost the same but G and B are corrupt. This is the source of "garbage colors" in your program. The decomposed image shows that the R component is compressed correctly, the G component becomes random noise at high compression levels, and the B component is always random.

Another problem in your implementation is single bright pixels scattered in dark areas. These are apparently caused by numeric overflow and underflow. For example, a black pixel (0,0,0) is encoded as 0x000000 = 0; lossy compression can introduce a small error, which can be positive or negative, and can yield -1 = 0xFFFFFFFF; in RGB it becomes (255,255,255) which is white.

What to do?

If you are just testing the SVD image compression and it's enough to use grayscale images, then you should simply take the low byte from the RGB value, which is in range from 0 to 255. Correspondingly, when displaying the result or writing the output file, interpret this value as grayscale, or multiply by 0x010101 to get the full RGB value.

If you need to compress color images, you should run the SVD algorithm separately on R, G and B components. It's the simplest way to handle color, but not the most efficient one. To get higher compression and less noticeable artifacts, it's better to convert from RGB to Lab (luminance and two chrominance channels); chrominance can be compressed more, that's the way JPEG works.

When decompressing the image, after calculating values from SVD but before displaying them on the screen or writing to file, clamp all resulting values (R, G and B) in the range 0-255. This will eliminate scattered white dots.

链接地址: http://www.djcxy.com/p/49104.html

上一篇: JAVA中的大型稀疏矩阵特征分解

下一篇: 试图压缩图像时出现彩色像素(包括图片)