# Image Compression

GROUPS:
 Hi!!I need a code (or pseudocode) of mathematica to compress a picture of  n x m pixels.Input a Jpegcompress the jpegand export jpeg then and before compressedPlease help me.Thanks!!
4 years ago
7 Replies
 Grisha Kirilin 4 Votes Hi,you can use JPEG itself! Here is my code, but I make no efforts to optimize it thus it can be really slow. First of all, you need define RGB to YCbCr transform. I found very nice code here via Mr.Wizard (up to some small correction): With[{v1 = DeveloperToPackedArray@{16, 128, 128},    m1 = DeveloperToPackedArray@{{65.481, 128.553,        24.966}, {-37.797, -74.203, 112}, {112, -93.786, -18.214}}},  RGBtoYCbCr[a : {_, _, _}?VectorQ] := v1 + m1.a;  RGBtoYCbCr[img_Image] := RGBtoYCbCr@ImageData[img(*,"Byte"*)];  RGBtoYCbCr[a_ /; MatchQ[Dimensions@a, {_, 3}]] :=    Transpose[v1 + m1.Transpose[a]];  RGBtoYCbCr[a_ /; MatchQ[Dimensions@a, {_, _, 3}]] :=    Transpose[v1 + m1.Transpose[a, {2, 3, 1}], {3, 1, 2}];]Inverse transform: With[{v1 = DeveloperToPackedArray@{-16, -128, -128},    m1 = DeveloperToPackedArray@     Inverse@{{65.481, 128.553, 24.966}, {-37.797, -74.203,         112}, {112, -93.786, -18.214}}},  YCbCrtoRGB[a : {_, _, _}?VectorQ] := m1.(a + v1);  YCbCrtoRGB[a_ /; MatchQ[Dimensions@a, {_, 3}]] :=    Transpose[m1.(Transpose[a] + v1)];  YCbCrtoRGB[a_ /; MatchQ[Dimensions@a, {_, _, 3}]] :=    Transpose[m1.(Transpose[a, {2, 3, 1}] + v1), {3, 1, 2}];]Then it is necessary to define the Fourier discrete cosine transform.fnorm = DeveloperToPackedArray@   Normal@SparseArray[{{1, 1} -> 1, {i_, i_} -> Sqrt[2]}, {8, 8}];bnorm = DeveloperToPackedArray@   Normal@SparseArray[{{1, 1} -> 1, {i_, i_} -> 1/Sqrt[2]}, {8, 8}];ForwardDCT[matrix_] := fnorm.FourierDCT[matrix - 128, 2].fnorm;BackwardDCT[matrix_] := 128 + FourierDCT[bnorm.matrix.bnorm, 3];Please, notice the JPEG uses DCT in slightly different way than Wolfram Mathematica. Next step is to define the quntization tabels for all channels: DQT["luma"] =    DeveloperToPackedArray@{{16, 11, 10, 16, 24, 40, 51, 61}, {12, 12,       14, 19, 26, 58, 60, 55}, {14, 13, 16, 24, 40, 57, 69, 56}, {14,       17, 22, 29, 51, 87, 80, 62}, {18, 22, 37, 56, 68, 109, 103,       77}, {24, 35, 55, 64, 81, 104, 113, 92}, {49, 64, 78, 87, 103,       121, 120, 101}, {72, 92, 95, 98, 112, 100, 103, 99}};  DQT["chroma"] =    DeveloperToPackedArray@{{17, 18, 24, 47, 99, 99, 99, 99}, {18, 21,      26, 66, 99, 99, 99, 99}, {24, 26, 56, 99, 99, 99, 99, 99}, {47,      66, 99, 99, 99, 99, 99, 99}, {99, 99, 99, 99, 99, 99, 99,      99}, {99, 99, 99, 99, 99, 99, 99, 99}, {99, 99, 99, 99, 99, 99,      99, 99}, {99, 99, 99, 99, 99, 99, 99, 99}};The last step is the quntization itself:Quantization[channel_, block_, quality_] :=   BackwardDCT[   quality DQT[channel] Round[     ForwardDCT[block]/(quality DQT[channel])]];Now, we can start. Import an image and divide it into 8*8 blocks:horse = Import["http://i.stack.imgur.com/ZhYwB.jpg"]blocks = Partition[#, {8, 8}] & /@    Transpose[RGBtoYCbCr@horse, {2, 3, 1}];Then we need to choose the quality of the output.quality = 2;Notice that the quality should be large than 1 and quality=1 reduces the size of the output file by factor 1.8. Thus we put a really terrible quality. The next step is quantization of each channel: luminance[1] =    Join @@ (Join @@@ Transpose[#, {2, 1, 3}] & /@       Map[Quantization["luma", #, quality] &, blocks[[1]], {2}]); chrominance[1] =    Join @@ (Join @@@ Transpose[#, {2, 1, 3}] & /@       Map[Quantization["chroma", #, quality] &, blocks[[2]], {2}]); chrominance[2] =    Join @@ (Join @@@ Transpose[#, {2, 1, 3}] & /@       Map[Quantization["chroma", #, quality] &, blocks[[3]], {2}]);This part works really slow, hence please try to optimize it. The last step is to convert to RGB and save to disk:SetDirectory[NotebookDirectory[]];Export["horse.jpg", Image[YCbCrtoRGB@   Transpose[{luminance[1], chrominance[1], chrominance[2]}, {3, 1,      2}]]]The size of the output file is 2.2 times smaler then initial one. The Mathematica file is attached to this post. Attachments:
4 years ago
 Alexey Popkov 1 Vote Hi Grisha, thank you for the code!I think that it is worth to point out that Export to "JPG" uses lossy compression with "CompressionLevel" -> 0.25 by default. So just Importing and then Exporting the image I get 34% smaller JPG file. It would be very interesting to see the results of your compression algorithm without this additional lossy compression by Export. I have tried to Export with  "CompressionLevel" -> 0 but it gives a file which is larger than the original. It raises the question: it is possible in Mathematica to Import a JPG file as Image object and then re-create original file from this Image object (assuming that original file contains no EXIF information)?
4 years ago
 Grisha Kirilin 2 Votes Hi Alexey,I think it is not possible in a general case. The problem is that different programs, devices and cameras use their own quantization tables (DQT). It is even possible to recognize camera producer by DQT used (DQT is a part of JPEG file). For example Adobe Photoshop uses 12 unique different quantization tables for each channel, e.g., for the luminance they look as follows:It seems that Mathematica's Import does not take into account (or store) DQTs. Of course, Mathematica uses its own DQT, thus the result will be always differnt from the original, with only one exception — the original picture was created by Mathematica:SetDirectory[NotebookDirectory[]]Export["test.jpg", Import["http://i.stack.imgur.com/ZhYwB.jpg"]]Export["test1.jpg", Import["test.jpg"]]The sizes of test.jpg and test1.jpg are equal.
4 years ago
 I do not understand the first and the second part of the code: RGB to YCbCr and Inverse transformMy level of mathematica is too bad...Is not there an easier way?Thanks!