Saving optimized jpeg

I need to save an optimized jpeg (meaning minimal looses and maximal compression). I noticed there is no built-in save that can do that so I wrote some code to take the original image and using some logic I am trying to save the image at various compression levels and use SSIM to measure the amount of data lost until I find the minimal quality that is still SSIM value above a certain threshold. to calaculate the SSIM, I load all pixels using image.LoadPixels(image.Bounds) and then do some math on that to conver to grayscale, and calculate all the means and variances needed for the SSIM calculation. this takes about 1 second for a large image and in total I need about 3-5 attempts before I find the best quality. Are there any insights you can share on how to improve performance of this? Is there a faster way to read all the pixels? is there a faster way to get the image after being saved at quality Q besides doing something like

MemoryStream ms = new MemoryStream();
originalImage.Save(ms, options);
ms.Position = 0;
RasterImage savedImage = (RasterImage)RasterImage.Load(ms);
double ssim = CalculateSsim(originalImage, savedImage)

Hello, @DanAvni

  1. Speaking of

Much faster is to use
RasterImage.LoadArgb32Pixels instead.
Please, try it.

  1. You could try to call Image.Save with different JpegQuality in several threads (although I am not sure that can help). Something like
MemoryStream ms = new MemoryStream();
originalImage.Save(ms, options);
ms.Position = 0;
RasterImage savedImage = (RasterImage)RasterImage.Load(ms);
savedImage.CacheImage();
// Do some save with different quality in 3-4 threads. Save in different files, and than keep only the best of them.

I changed my code to use RasterImage.LoadArgb32Pixels although it might be faster the difference is not much. speed it still largly dominated by the save

Evaluating quality: 30
Save and Reload time: 1715
Image stats time: 261
SSIM time: 51
Evaluating quality: 15
Save and Reload time: 1083
Image stats time: 215
SSIM time: 53
Evaluating quality: 25
Save and Reload time: 1154
Image stats time: 187
SSIM time: 49
Final quality: 30
Evaluating quality: 30
Save and Reload time: 1128
Image stats time: 200
SSIM time: 50
Evaluating quality: 15
Save and Reload time: 1130
Image stats time: 226
SSIM time: 53
Evaluating quality: 25
Save and Reload time: 1165
Image stats time: 223
SSIM time: 50
Final quality: 30
Evaluating quality: 30
Save and Reload time: 1007
Image stats time: 206
SSIM time: 49
Evaluating quality: 60
Save and Reload time: 1052
Image stats time: 251
SSIM time: 50
Evaluating quality: 45
Save and Reload time: 1050
Image stats time: 212
SSIM time: 50
Evaluating quality: 35
Save and Reload time: 1047
Image stats time: 180
SSIM time: 50
Final quality: 35

Any ideas on how to make this save/load faster? using multiple threads is an option which I am going to explore but my only idea at the time is doing a ternary search or quad search instead of binary. I am thinking of attempting two threads at 30 and 60. then based on the third I need to use I will further devide it into 3 parts and so on. it should help but the main issue is the time it takes to save and reload so even if I do 2 attempts each with 2 threads I am still at 2-3 seconds of calculation time

I am afraid that I have no idea yet.
I may offer only not to test the quality values that lead to worse image quality, such as less than 60.

Hello @DanAvni

  • I suggest you do profiling to find the places that take up most of your time. After that, they could be optimized.
  • You can save and compare not the entire image, but only a part of it — for example, the central 256×256 pixels, or a percentage of the image size. This will give some margin of error, but it will be close enough to the truth. If this functionality is provided to end users, you can call this mode “Fast” and additionally provide access to the full comparison.