ssimulacra2_main.cc (3452B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include <stdio.h> 7 8 #include <utility> 9 10 #include "lib/extras/codec.h" 11 // TODO(eustas): we should, but we can't? 12 // #include "lib/jxl/base/span.h" 13 #include "tools/file_io.h" 14 #include "tools/ssimulacra2.h" 15 16 int PrintUsage(char** argv) { 17 fprintf(stderr, "Usage: %s orig.png distorted.png\n", argv[0]); 18 fprintf(stderr, 19 "Returns a score in range -inf..100, which correlates to subjective " 20 "visual quality:\n"); 21 fprintf(stderr, 22 " 30 = low quality (p10 worst output of mozjpeg -quality 30)\n"); 23 fprintf(stderr, 24 " 50 = medium quality (average output of cjxl -q 40 or mozjpeg " 25 "-quality 40,\n"); 26 fprintf(stderr, 27 " p10 output of cjxl -q 50 or mozjpeg " 28 "-quality 60)\n"); 29 fprintf(stderr, 30 " 70 = high quality (average output of cjxl -q 70 or mozjpeg " 31 "-quality 70,\n"); 32 fprintf(stderr, 33 " p10 output of cjxl -q 75 or mozjpeg " 34 "-quality 80)\n"); 35 fprintf(stderr, 36 " 90 = very high quality (impossible to distinguish from " 37 "original at 1:1,\n"); 38 fprintf(stderr, 39 " average output of cjxl -q 90 or " 40 "mozjpeg -quality 90)\n"); 41 return 1; 42 } 43 44 int main(int argc, char** argv) { 45 if (argc != 3) return PrintUsage(argv); 46 47 jxl::CodecInOut io[2]; 48 const char* purpose[] = {"original", "distorted"}; 49 for (size_t i = 0; i < 2; ++i) { 50 std::vector<uint8_t> encoded; 51 if (!jpegxl::tools::ReadFile(argv[1 + i], &encoded)) { 52 fprintf(stderr, "Could not load %s image: %s\n", purpose[i], argv[1 + i]); 53 return 1; 54 } 55 if (!jxl::SetFromBytes(jxl::Bytes(encoded), jxl::extras::ColorHints(), 56 &io[i])) { 57 fprintf(stderr, "Could not decode %s image: %s\n", purpose[i], 58 argv[1 + i]); 59 return 1; 60 } 61 if (io[i].xsize() < 8 || io[i].ysize() < 8) { 62 fprintf(stderr, "Minimum image size is 8x8 pixels\n"); 63 return 1; 64 } 65 } 66 jxl::CodecInOut& io1 = io[0]; 67 jxl::CodecInOut& io2 = io[1]; 68 69 if (io1.xsize() != io2.xsize() || io1.ysize() != io2.ysize()) { 70 fprintf(stderr, "Image size mismatch\n"); 71 return 1; 72 } 73 74 if (!io1.Main().HasAlpha()) { 75 jxl::StatusOr<Msssim> msssim_or = 76 ComputeSSIMULACRA2(io1.Main(), io2.Main()); 77 if (!msssim_or.ok()) { 78 fprintf(stderr, "ComputeSSIMULACRA2 failed\n"); 79 return 1; 80 } 81 Msssim msssim = std::move(msssim_or).value(); 82 printf("%.8f\n", msssim.Score()); 83 } else { 84 // in case of alpha transparency: blend against dark and bright backgrounds 85 // and return the worst of both scores 86 jxl::StatusOr<Msssim> msssim0_or = 87 ComputeSSIMULACRA2(io1.Main(), io2.Main(), 0.1f); 88 if (!msssim0_or.ok()) { 89 fprintf(stderr, "ComputeSSIMULACRA2 failed\n"); 90 return 1; 91 } 92 Msssim msssim0 = std::move(msssim0_or).value(); 93 jxl::StatusOr<Msssim> msssim1_or = 94 ComputeSSIMULACRA2(io1.Main(), io2.Main(), 0.9f); 95 if (!msssim1_or.ok()) { 96 fprintf(stderr, "ComputeSSIMULACRA2 failed\n"); 97 return 1; 98 } 99 Msssim msssim1 = std::move(msssim1_or).value(); 100 printf("%.8f\n", std::min(msssim0.Score(), msssim1.Score())); 101 } 102 return 0; 103 }