enc_gaborish.cc (2846B)
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 "lib/jxl/enc_gaborish.h" 7 8 #include <stddef.h> 9 10 #include <hwy/base.h> 11 12 #include "lib/jxl/base/status.h" 13 #include "lib/jxl/convolve.h" 14 #include "lib/jxl/image_ops.h" 15 16 namespace jxl { 17 18 Status GaborishInverse(Image3F* in_out, const Rect& rect, const float mul[3], 19 ThreadPool* pool) { 20 WeightsSymmetric5 weights[3]; 21 // Only an approximation. One or even two 3x3, and rank-1 (separable) 5x5 22 // are insufficient. The numbers here have been obtained by butteraugli 23 // based optimizing the whole system and the errors produced are likely 24 // more favorable for good rate-distortion compromises rather than 25 // just using mathematical optimization to find the inverse. 26 static const float kGaborish[5] = { 27 -0.090881924078487886f, -0.043663953593472138f, 0.01392497846646211f, 28 0.0036189602184591141f, 0.0030557936884763499f}; 29 for (int i = 0; i < 3; ++i) { 30 double sum = 1.0 + mul[i] * 4 * 31 (kGaborish[0] + kGaborish[1] + kGaborish[2] + 32 kGaborish[4] + 2 * kGaborish[3]); 33 if (sum < 1e-5) { 34 sum = 1e-5; 35 } 36 const float normalize = static_cast<float>(1.0 / sum); 37 const float normalize_mul = mul[i] * normalize; 38 weights[i] = WeightsSymmetric5{{HWY_REP4(normalize)}, 39 {HWY_REP4(normalize_mul * kGaborish[0])}, 40 {HWY_REP4(normalize_mul * kGaborish[2])}, 41 {HWY_REP4(normalize_mul * kGaborish[1])}, 42 {HWY_REP4(normalize_mul * kGaborish[4])}, 43 {HWY_REP4(normalize_mul * kGaborish[3])}}; 44 } 45 // Reduce memory footprint by only allocating a single plane and swapping it 46 // into the output Image3F. Better still would be tiling. 47 // Note that we cannot *allocate* a plane, as doing so might cause Image3F to 48 // have planes of different stride. Instead, we copy one plane in a temporary 49 // image and reuse the existing planes of the in/out image. 50 ImageF temp; 51 JXL_ASSIGN_OR_RETURN( 52 temp, ImageF::Create(in_out->Plane(2).xsize(), in_out->Plane(2).ysize())); 53 CopyImageTo(in_out->Plane(2), &temp); 54 Rect xrect = rect.Extend(3, Rect(*in_out)); 55 Symmetric5(in_out->Plane(0), xrect, weights[0], pool, &in_out->Plane(2), 56 xrect); 57 Symmetric5(in_out->Plane(1), xrect, weights[1], pool, &in_out->Plane(0), 58 xrect); 59 Symmetric5(temp, xrect, weights[2], pool, &in_out->Plane(1), xrect); 60 // Now planes are 1, 2, 0. 61 in_out->Plane(0).Swap(in_out->Plane(1)); 62 // 2 1 0 63 in_out->Plane(0).Swap(in_out->Plane(2)); 64 return true; 65 } 66 67 } // namespace jxl