summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc')
-rw-r--r--third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc340
1 files changed, 192 insertions, 148 deletions
diff --git a/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc b/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc
index 66dde9afb1..2e06d79eba 100644
--- a/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc
+++ b/third_party/jpeg-xl/lib/jxl/butteraugli/butteraugli.cc
@@ -28,11 +28,12 @@
#include <string.h>
#include <algorithm>
-#include <array>
#include <cmath>
-#include <new>
+#include <memory>
#include <vector>
+#include "lib/jxl/image.h"
+
#undef HWY_TARGET_INCLUDE
#define HWY_TARGET_INCLUDE "lib/jxl/butteraugli/butteraugli.cc"
#include <hwy/foreach_target.h>
@@ -222,8 +223,8 @@ void ConvolutionWithTranspose(const ImageF& in,
// We retain a special case for 5x5 kernels (even faster than gauss_blur),
// optionally use gauss_blur followed by fixup of the borders for large images,
// or fall back to the previous truncated FIR followed by a transpose.
-void Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
- BlurTemp* temp, ImageF* out) {
+Status Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
+ BlurTemp* temp, ImageF* out) {
std::vector<float> kernel = ComputeKernel(sigma);
// Separable5 does an in-place convolution, so this fast path is not safe if
// in aliases out.
@@ -241,12 +242,14 @@ void Blur(const ImageF& in, float sigma, const ButteraugliParams& params,
{HWY_REP4(w0), HWY_REP4(w1), HWY_REP4(w2)},
};
Separable5(in, Rect(in), weights, /*pool=*/nullptr, out);
- return;
+ return true;
}
- ImageF* JXL_RESTRICT temp_t = temp->GetTransposed(in);
+ ImageF* temp_t;
+ JXL_RETURN_IF_ERROR(temp->GetTransposed(in, &temp_t));
ConvolutionWithTranspose(in, kernel, temp_t);
ConvolutionWithTranspose(*temp_t, kernel, out);
+ return true;
}
// Allows PaddedMaltaUnit to call either function via overloading.
@@ -386,29 +389,32 @@ void Subtract(const ImageF& a, const ImageF& b, ImageF* c) {
}
}
-void SeparateLFAndMF(const ButteraugliParams& params, const Image3F& xyb,
- Image3F* lf, Image3F* mf, BlurTemp* blur_temp) {
+Status SeparateLFAndMF(const ButteraugliParams& params, const Image3F& xyb,
+ Image3F* lf, Image3F* mf, BlurTemp* blur_temp) {
static const double kSigmaLf = 7.15593339443;
for (int i = 0; i < 3; ++i) {
// Extract lf ...
- Blur(xyb.Plane(i), kSigmaLf, params, blur_temp, &lf->Plane(i));
+ JXL_RETURN_IF_ERROR(
+ Blur(xyb.Plane(i), kSigmaLf, params, blur_temp, &lf->Plane(i)));
// ... and keep everything else in mf.
Subtract(xyb.Plane(i), lf->Plane(i), &mf->Plane(i));
}
XybLowFreqToVals(lf);
+ return true;
}
-void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
- BlurTemp* blur_temp) {
+Status SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
+ BlurTemp* blur_temp) {
const HWY_FULL(float) d;
static const double kSigmaHf = 3.22489901262;
const size_t xsize = mf->xsize();
const size_t ysize = mf->ysize();
- hf[0] = ImageF(xsize, ysize);
- hf[1] = ImageF(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(hf[0], ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(hf[1], ImageF::Create(xsize, ysize));
for (int i = 0; i < 3; ++i) {
if (i == 2) {
- Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i));
+ JXL_RETURN_IF_ERROR(
+ Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i)));
break;
}
for (size_t y = 0; y < ysize; ++y) {
@@ -418,7 +424,8 @@ void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
Store(Load(d, row_mf + x), d, row_hf + x);
}
}
- Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i));
+ JXL_RETURN_IF_ERROR(
+ Blur(mf->Plane(i), kSigmaHf, params, blur_temp, &mf->Plane(i)));
static const double kRemoveMfRange = 0.29;
static const double kAddMfRange = 0.1;
if (i == 0) {
@@ -450,16 +457,17 @@ void SeparateMFAndHF(const ButteraugliParams& params, Image3F* mf, ImageF* hf,
}
// Suppress red-green by intensity change in the high freq channels.
SuppressXByY(hf[1], &hf[0]);
+ return true;
}
-void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
- BlurTemp* blur_temp) {
+Status SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf,
+ ImageF* uhf, BlurTemp* blur_temp) {
const HWY_FULL(float) d;
const size_t xsize = hf[0].xsize();
const size_t ysize = hf[0].ysize();
static const double kSigmaUhf = 1.56416327805;
- uhf[0] = ImageF(xsize, ysize);
- uhf[1] = ImageF(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(uhf[0], ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(uhf[1], ImageF::Create(xsize, ysize));
for (int i = 0; i < 2; ++i) {
// Divide hf into hf and uhf.
for (size_t y = 0; y < ysize; ++y) {
@@ -469,7 +477,7 @@ void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
row_uhf[x] = row_hf[x];
}
}
- Blur(hf[i], kSigmaUhf, params, blur_temp, &hf[i]);
+ JXL_RETURN_IF_ERROR(Blur(hf[i], kSigmaUhf, params, blur_temp, &hf[i]));
static const double kRemoveHfRange = 1.5;
static const double kAddHfRange = 0.132;
static const double kRemoveUhfRange = 0.04;
@@ -510,6 +518,7 @@ void SeparateHFAndUHF(const ButteraugliParams& params, ImageF* hf, ImageF* uhf,
}
}
}
+ return true;
}
void DeallocateHFAndUHF(ImageF* hf, ImageF* uhf) {
@@ -519,15 +528,16 @@ void DeallocateHFAndUHF(ImageF* hf, ImageF* uhf) {
}
}
-static void SeparateFrequencies(size_t xsize, size_t ysize,
- const ButteraugliParams& params,
- BlurTemp* blur_temp, const Image3F& xyb,
- PsychoImage& ps) {
- ps.lf = Image3F(xyb.xsize(), xyb.ysize());
- ps.mf = Image3F(xyb.xsize(), xyb.ysize());
- SeparateLFAndMF(params, xyb, &ps.lf, &ps.mf, blur_temp);
- SeparateMFAndHF(params, &ps.mf, &ps.hf[0], blur_temp);
- SeparateHFAndUHF(params, &ps.hf[0], &ps.uhf[0], blur_temp);
+Status SeparateFrequencies(size_t xsize, size_t ysize,
+ const ButteraugliParams& params, BlurTemp* blur_temp,
+ const Image3F& xyb, PsychoImage& ps) {
+ JXL_ASSIGN_OR_RETURN(ps.lf, Image3F::Create(xyb.xsize(), xyb.ysize()));
+ JXL_ASSIGN_OR_RETURN(ps.mf, Image3F::Create(xyb.xsize(), xyb.ysize()));
+ JXL_RETURN_IF_ERROR(SeparateLFAndMF(params, xyb, &ps.lf, &ps.mf, blur_temp));
+ JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &ps.mf, &ps.hf[0], blur_temp));
+ JXL_RETURN_IF_ERROR(
+ SeparateHFAndUHF(params, &ps.hf[0], &ps.uhf[0], blur_temp));
+ return true;
}
namespace {
@@ -1024,7 +1034,7 @@ static void MaltaDiffMapT(const Tag tag, const ImageF& lum0, const ImageF& lum1,
}
const HWY_FULL(float) df;
- const size_t aligned_x = std::max(size_t(4), Lanes(df));
+ const size_t aligned_x = std::max(static_cast<size_t>(4), Lanes(df));
const intptr_t stride = diffs->PixelsPerRow();
// Middle
@@ -1097,7 +1107,7 @@ void CombineChannelsForMasking(const ImageF* hf, const ImageF* uhf,
float xdiff = (row_x_uhf[x] + row_x_hf[x]) * muls[0];
float ydiff = row_y_uhf[x] * muls[1] + row_y_hf[x] * muls[2];
row[x] = xdiff * xdiff + ydiff * ydiff;
- row[x] = sqrt(row[x]);
+ row[x] = std::sqrt(row[x]);
}
}
}
@@ -1106,13 +1116,13 @@ void DiffPrecompute(const ImageF& xyb, float mul, float bias_arg, ImageF* out) {
const size_t xsize = xyb.xsize();
const size_t ysize = xyb.ysize();
const float bias = mul * bias_arg;
- const float sqrt_bias = sqrt(bias);
+ const float sqrt_bias = std::sqrt(bias);
for (size_t y = 0; y < ysize; ++y) {
const float* BUTTERAUGLI_RESTRICT row_in = xyb.Row(y);
float* BUTTERAUGLI_RESTRICT row_out = out->Row(y);
for (size_t x = 0; x < xsize; ++x) {
// kBias makes sqrt behave more linearly.
- row_out[x] = sqrt(mul * std::abs(row_in[x]) + bias) - sqrt_bias;
+ row_out[x] = std::sqrt(mul * std::abs(row_in[x]) + bias) - sqrt_bias;
}
}
}
@@ -1188,25 +1198,25 @@ void FuzzyErosion(const ImageF& from, ImageF* to) {
// Compute values of local frequency and dc masking based on the activity
// in the two images. img_diff_ac may be null.
-void Mask(const ImageF& mask0, const ImageF& mask1,
- const ButteraugliParams& params, BlurTemp* blur_temp,
- ImageF* BUTTERAUGLI_RESTRICT mask,
- ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
+Status Mask(const ImageF& mask0, const ImageF& mask1,
+ const ButteraugliParams& params, BlurTemp* blur_temp,
+ ImageF* BUTTERAUGLI_RESTRICT mask,
+ ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
const size_t xsize = mask0.xsize();
const size_t ysize = mask0.ysize();
- *mask = ImageF(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(*mask, ImageF::Create(xsize, ysize));
static const float kMul = 6.19424080439;
static const float kBias = 12.61050594197;
static const float kRadius = 2.7;
- ImageF diff0(xsize, ysize);
- ImageF diff1(xsize, ysize);
- ImageF blurred0(xsize, ysize);
- ImageF blurred1(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF diff0, ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(ImageF diff1, ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(ImageF blurred0, ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(ImageF blurred1, ImageF::Create(xsize, ysize));
DiffPrecompute(mask0, kMul, kBias, &diff0);
DiffPrecompute(mask1, kMul, kBias, &diff1);
- Blur(diff0, kRadius, params, blur_temp, &blurred0);
+ JXL_RETURN_IF_ERROR(Blur(diff0, kRadius, params, blur_temp, &blurred0));
FuzzyErosion(blurred0, &diff0);
- Blur(diff1, kRadius, params, blur_temp, &blurred1);
+ JXL_RETURN_IF_ERROR(Blur(diff1, kRadius, params, blur_temp, &blurred1));
for (size_t y = 0; y < ysize; ++y) {
for (size_t x = 0; x < xsize; ++x) {
mask->Row(y)[x] = diff0.Row(y)[x];
@@ -1217,19 +1227,21 @@ void Mask(const ImageF& mask0, const ImageF& mask1,
}
}
}
+ return true;
}
// `diff_ac` may be null.
-void MaskPsychoImage(const PsychoImage& pi0, const PsychoImage& pi1,
- const size_t xsize, const size_t ysize,
- const ButteraugliParams& params, BlurTemp* blur_temp,
- ImageF* BUTTERAUGLI_RESTRICT mask,
- ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
- ImageF mask0(xsize, ysize);
- ImageF mask1(xsize, ysize);
+Status MaskPsychoImage(const PsychoImage& pi0, const PsychoImage& pi1,
+ const size_t xsize, const size_t ysize,
+ const ButteraugliParams& params, BlurTemp* blur_temp,
+ ImageF* BUTTERAUGLI_RESTRICT mask,
+ ImageF* BUTTERAUGLI_RESTRICT diff_ac) {
+ JXL_ASSIGN_OR_RETURN(ImageF mask0, ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(ImageF mask1, ImageF::Create(xsize, ysize));
CombineChannelsForMasking(&pi0.hf[0], &pi0.uhf[0], &mask0);
CombineChannelsForMasking(&pi1.hf[0], &pi1.uhf[0], &mask1);
- Mask(mask0, mask1, params, blur_temp, mask, diff_ac);
+ JXL_RETURN_IF_ERROR(Mask(mask0, mask1, params, blur_temp, mask, diff_ac));
+ return true;
}
double MaskY(double delta) {
@@ -1275,8 +1287,8 @@ void CombineChannelsToDiffmap(const ImageF& mask, const Image3F& block_diff_dc,
}
diff_ac[0] *= xmul;
diff_dc[0] *= xmul;
- row_out[x] =
- sqrt(MaskColor(diff_dc, dc_maskval) + MaskColor(diff_ac, maskval));
+ row_out[x] = std::sqrt(MaskColor(diff_dc, dc_maskval) +
+ MaskColor(diff_ac, maskval));
}
}
}
@@ -1430,12 +1442,15 @@ BUTTERAUGLI_INLINE void OpsinAbsorbance(const DF df, const V& in0, const V& in1,
}
// `blurred` is a temporary image used inside this function and not returned.
-void OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
- Image3F* blurred, BlurTemp* blur_temp, Image3F* xyb) {
+Status OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
+ Image3F* blurred, BlurTemp* blur_temp, Image3F* xyb) {
const double kSigma = 1.2;
- Blur(rgb.Plane(0), kSigma, params, blur_temp, &blurred->Plane(0));
- Blur(rgb.Plane(1), kSigma, params, blur_temp, &blurred->Plane(1));
- Blur(rgb.Plane(2), kSigma, params, blur_temp, &blurred->Plane(2));
+ JXL_RETURN_IF_ERROR(
+ Blur(rgb.Plane(0), kSigma, params, blur_temp, &blurred->Plane(0)));
+ JXL_RETURN_IF_ERROR(
+ Blur(rgb.Plane(1), kSigma, params, blur_temp, &blurred->Plane(1)));
+ JXL_RETURN_IF_ERROR(
+ Blur(rgb.Plane(2), kSigma, params, blur_temp, &blurred->Plane(2)));
const HWY_FULL(float) df;
const auto intensity_target_multiplier = Set(df, params.intensity_target);
for (size_t y = 0; y < rgb.ysize(); ++y) {
@@ -1497,31 +1512,36 @@ void OpsinDynamicsImage(const Image3F& rgb, const ButteraugliParams& params,
Store(cur_mixed2, df, row_out_b + x);
}
}
+ return true;
}
-void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
- const ButteraugliParams& params,
- ImageF& diffmap) {
+Status ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
+ const ButteraugliParams& params,
+ ImageF& diffmap) {
// image0 and image1 are in linear sRGB color space
const size_t xsize = image0.xsize();
const size_t ysize = image0.ysize();
BlurTemp blur_temp;
{
// Convert image0 and image1 to XYB in-place
- Image3F temp(xsize, ysize);
- OpsinDynamicsImage(image0, params, &temp, &blur_temp, &image0);
- OpsinDynamicsImage(image1, params, &temp, &blur_temp, &image1);
+ JXL_ASSIGN_OR_RETURN(Image3F temp, Image3F::Create(xsize, ysize));
+ JXL_RETURN_IF_ERROR(
+ OpsinDynamicsImage(image0, params, &temp, &blur_temp, &image0));
+ JXL_RETURN_IF_ERROR(
+ OpsinDynamicsImage(image1, params, &temp, &blur_temp, &image1));
}
// image0 and image1 are in XYB color space
- ImageF block_diff_dc(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF block_diff_dc, ImageF::Create(xsize, ysize));
ZeroFillImage(&block_diff_dc);
{
// separate out LF components from image0 and image1 and compute the dc
// diff image from them
- Image3F lf0 = Image3F(xsize, ysize);
- Image3F lf1 = Image3F(xsize, ysize);
- SeparateLFAndMF(params, image0, &lf0, &image0, &blur_temp);
- SeparateLFAndMF(params, image1, &lf1, &image1, &blur_temp);
+ JXL_ASSIGN_OR_RETURN(Image3F lf0, Image3F::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(Image3F lf1, Image3F::Create(xsize, ysize));
+ JXL_RETURN_IF_ERROR(
+ SeparateLFAndMF(params, image0, &lf0, &image0, &blur_temp));
+ JXL_RETURN_IF_ERROR(
+ SeparateLFAndMF(params, image1, &lf1, &image1, &blur_temp));
for (size_t c = 0; c < 3; ++c) {
L2Diff(lf0.Plane(c), lf1.Plane(c), wmul[6 + c], &block_diff_dc);
}
@@ -1529,15 +1549,15 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
// image0 and image1 are MF residuals (before blurring) in XYB color space
ImageF hf0[2];
ImageF hf1[2];
- SeparateMFAndHF(params, &image0, &hf0[0], &blur_temp);
- SeparateMFAndHF(params, &image1, &hf1[0], &blur_temp);
+ JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &image0, &hf0[0], &blur_temp));
+ JXL_RETURN_IF_ERROR(SeparateMFAndHF(params, &image1, &hf1[0], &blur_temp));
// image0 and image1 are MF-images in XYB color space
- ImageF block_diff_ac(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF block_diff_ac, ImageF::Create(xsize, ysize));
ZeroFillImage(&block_diff_ac);
// start accumulating ac diff image from MF images
{
- ImageF diffs(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize, ysize));
MaltaDiffMapLF(image0.Plane(1), image1.Plane(1), wMfMalta, wMfMalta,
norm1Mf, &diffs, &block_diff_ac);
MaltaDiffMapLF(image0.Plane(0), image1.Plane(0), wMfMaltaX, wMfMaltaX,
@@ -1553,13 +1573,13 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
ImageF uhf0[2];
ImageF uhf1[2];
- SeparateHFAndUHF(params, &hf0[0], &uhf0[0], &blur_temp);
- SeparateHFAndUHF(params, &hf1[0], &uhf1[0], &blur_temp);
+ JXL_RETURN_IF_ERROR(SeparateHFAndUHF(params, &hf0[0], &uhf0[0], &blur_temp));
+ JXL_RETURN_IF_ERROR(SeparateHFAndUHF(params, &hf1[0], &uhf1[0], &blur_temp));
// continue accumulating ac diff image from HF and UHF images
const float hf_asymmetry = params.hf_asymmetry;
{
- ImageF diffs(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize, ysize));
MaltaDiffMap(uhf0[1], uhf1[1], wUhfMalta * hf_asymmetry,
wUhfMalta / hf_asymmetry, norm1Uhf, &diffs, &block_diff_ac);
MaltaDiffMap(uhf0[0], uhf1[0], wUhfMaltaX * hf_asymmetry,
@@ -1577,19 +1597,20 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
}
// compute mask image from HF and UHF X and Y images
- ImageF mask(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF mask, ImageF::Create(xsize, ysize));
{
- ImageF mask0(xsize, ysize);
- ImageF mask1(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(ImageF mask0, ImageF::Create(xsize, ysize));
+ JXL_ASSIGN_OR_RETURN(ImageF mask1, ImageF::Create(xsize, ysize));
CombineChannelsForMasking(&hf0[0], &uhf0[0], &mask0);
CombineChannelsForMasking(&hf1[0], &uhf1[0], &mask1);
DeallocateHFAndUHF(&hf1[0], &uhf1[0]);
DeallocateHFAndUHF(&hf0[0], &uhf0[0]);
- Mask(mask0, mask1, params, &blur_temp, &mask, &block_diff_ac);
+ JXL_RETURN_IF_ERROR(
+ Mask(mask0, mask1, params, &blur_temp, &mask, &block_diff_ac));
}
// compute final diffmap from mask image and ac and dc diff images
- diffmap = ImageF(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(diffmap, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < ysize; ++y) {
const float* row_dc = block_diff_dc.Row(y);
const float* row_ac = block_diff_ac.Row(y);
@@ -1599,6 +1620,7 @@ void ButteraugliDiffmapInPlace(Image3F& image0, Image3F& image1,
row_out[x] = sqrt(row_dc[x] * MaskDcY(val) + row_ac[x] * MaskY(val));
}
}
+ return true;
}
// NOLINTNEXTLINE(google-readability-namespace-comments)
@@ -1669,10 +1691,10 @@ static inline void CheckImage(const ImageF& image, const char* name) {
// Calculate a 2x2 subsampled image for purposes of recursive butteraugli at
// multiresolution.
-static Image3F SubSample2x(const Image3F& in) {
+static StatusOr<Image3F> SubSample2x(const Image3F& in) {
size_t xs = (in.xsize() + 1) / 2;
size_t ys = (in.ysize() + 1) / 2;
- Image3F retval(xs, ys);
+ JXL_ASSIGN_OR_RETURN(Image3F retval, Image3F::Create(xs, ys));
for (size_t c = 0; c < 3; ++c) {
for (size_t y = 0; y < ys; ++y) {
for (size_t x = 0; x < xs; ++x) {
@@ -1724,69 +1746,86 @@ Image3F* ButteraugliComparator::Temp() const {
void ButteraugliComparator::ReleaseTemp() const { temp_in_use_.clear(); }
-ButteraugliComparator::ButteraugliComparator(const Image3F& rgb0,
+ButteraugliComparator::ButteraugliComparator(size_t xsize, size_t ysize,
const ButteraugliParams& params)
- : xsize_(rgb0.xsize()),
- ysize_(rgb0.ysize()),
- params_(params),
- temp_(xsize_, ysize_) {
- if (xsize_ < 8 || ysize_ < 8) {
- return;
+ : xsize_(xsize), ysize_(ysize), params_(params) {}
+
+StatusOr<std::unique_ptr<ButteraugliComparator>> ButteraugliComparator::Make(
+ const Image3F& rgb0, const ButteraugliParams& params) {
+ size_t xsize = rgb0.xsize();
+ size_t ysize = rgb0.ysize();
+ std::unique_ptr<ButteraugliComparator> result =
+ std::unique_ptr<ButteraugliComparator>(
+ new ButteraugliComparator(xsize, ysize, params));
+ JXL_ASSIGN_OR_RETURN(result->temp_, Image3F::Create(xsize, ysize));
+
+ if (xsize < 8 || ysize < 8) {
+ return result;
}
- Image3F xyb0(xsize_, ysize_);
- HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
- (rgb0, params, Temp(), &blur_temp_, &xyb0);
- ReleaseTemp();
- HWY_DYNAMIC_DISPATCH(SeparateFrequencies)
- (xsize_, ysize_, params_, &blur_temp_, xyb0, pi0_);
+ JXL_ASSIGN_OR_RETURN(Image3F xyb0, Image3F::Create(xsize, ysize));
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
+ rgb0, params, result->Temp(), &result->blur_temp_, &xyb0));
+ result->ReleaseTemp();
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(SeparateFrequencies)(
+ xsize, ysize, params, &result->blur_temp_, xyb0, result->pi0_));
// Awful recursive construction of samples of different resolution.
// This is an after-thought and possibly somewhat parallel in
// functionality with the PsychoImage multi-resolution approach.
- sub_.reset(new ButteraugliComparator(SubSample2x(rgb0), params));
+ JXL_ASSIGN_OR_RETURN(Image3F subsampledRgb0, SubSample2x(rgb0));
+ StatusOr<std::unique_ptr<ButteraugliComparator>> sub =
+ ButteraugliComparator::Make(subsampledRgb0, params);
+ if (!sub.ok()) return sub.status();
+ result->sub_ = std::move(sub).value();
+
+ return result;
}
-void ButteraugliComparator::Mask(ImageF* BUTTERAUGLI_RESTRICT mask) const {
- HWY_DYNAMIC_DISPATCH(MaskPsychoImage)
- (pi0_, pi0_, xsize_, ysize_, params_, &blur_temp_, mask, nullptr);
+Status ButteraugliComparator::Mask(ImageF* BUTTERAUGLI_RESTRICT mask) const {
+ return HWY_DYNAMIC_DISPATCH(MaskPsychoImage)(
+ pi0_, pi0_, xsize_, ysize_, params_, &blur_temp_, mask, nullptr);
}
-void ButteraugliComparator::Diffmap(const Image3F& rgb1, ImageF& result) const {
+Status ButteraugliComparator::Diffmap(const Image3F& rgb1,
+ ImageF& result) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&result);
- return;
+ return true;
}
- Image3F xyb1(xsize_, ysize_);
- HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
- (rgb1, params_, Temp(), &blur_temp_, &xyb1);
+ JXL_ASSIGN_OR_RETURN(Image3F xyb1, Image3F::Create(xsize_, ysize_));
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
+ rgb1, params_, Temp(), &blur_temp_, &xyb1));
ReleaseTemp();
- DiffmapOpsinDynamicsImage(xyb1, result);
+ JXL_RETURN_IF_ERROR(DiffmapOpsinDynamicsImage(xyb1, result));
if (sub_) {
if (sub_->xsize_ < 8 || sub_->ysize_ < 8) {
- return;
+ return true;
}
- Image3F sub_xyb(sub_->xsize_, sub_->ysize_);
- HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)
- (SubSample2x(rgb1), params_, sub_->Temp(), &sub_->blur_temp_, &sub_xyb);
+ JXL_ASSIGN_OR_RETURN(Image3F sub_xyb,
+ Image3F::Create(sub_->xsize_, sub_->ysize_));
+ JXL_ASSIGN_OR_RETURN(Image3F subsampledRgb1, SubSample2x(rgb1));
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(OpsinDynamicsImage)(
+ subsampledRgb1, params_, sub_->Temp(), &sub_->blur_temp_, &sub_xyb));
sub_->ReleaseTemp();
ImageF subresult;
- sub_->DiffmapOpsinDynamicsImage(sub_xyb, subresult);
+ JXL_RETURN_IF_ERROR(sub_->DiffmapOpsinDynamicsImage(sub_xyb, subresult));
AddSupersampled2x(subresult, 0.5, result);
}
+ return true;
}
-void ButteraugliComparator::DiffmapOpsinDynamicsImage(const Image3F& xyb1,
- ImageF& result) const {
+Status ButteraugliComparator::DiffmapOpsinDynamicsImage(const Image3F& xyb1,
+ ImageF& result) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&result);
- return;
+ return true;
}
PsychoImage pi1;
- HWY_DYNAMIC_DISPATCH(SeparateFrequencies)
- (xsize_, ysize_, params_, &blur_temp_, xyb1, pi1);
- result = ImageF(xsize_, ysize_);
- DiffmapPsychoImage(pi1, result);
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(SeparateFrequencies)(
+ xsize_, ysize_, params_, &blur_temp_, xyb1, pi1));
+ JXL_ASSIGN_OR_RETURN(result, ImageF::Create(xsize_, ysize_));
+ return DiffmapPsychoImage(pi1, result);
}
namespace {
@@ -1809,18 +1848,18 @@ void MaltaDiffMapLF(const ImageF& lum0, const ImageF& lum1, const double w_0gt1,
} // namespace
-void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
- ImageF& diffmap) const {
+Status ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
+ ImageF& diffmap) const {
if (xsize_ < 8 || ysize_ < 8) {
ZeroFillImage(&diffmap);
- return;
+ return true;
}
const float hf_asymmetry_ = params_.hf_asymmetry;
const float xmul_ = params_.xmul;
- ImageF diffs(xsize_, ysize_);
- Image3F block_diff_ac(xsize_, ysize_);
+ JXL_ASSIGN_OR_RETURN(ImageF diffs, ImageF::Create(xsize_, ysize_));
+ JXL_ASSIGN_OR_RETURN(Image3F block_diff_ac, Image3F::Create(xsize_, ysize_));
ZeroFillImage(&block_diff_ac);
MaltaDiffMap(pi0_.uhf[1], pi1.uhf[1], wUhfMalta * hf_asymmetry_,
wUhfMalta / hf_asymmetry_, norm1Uhf, &diffs, &block_diff_ac, 1);
@@ -1838,7 +1877,7 @@ void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
MaltaDiffMapLF(pi0_.mf.Plane(0), pi1.mf.Plane(0), wMfMaltaX, wMfMaltaX,
norm1MfX, &diffs, &block_diff_ac, 0);
- Image3F block_diff_dc(xsize_, ysize_);
+ JXL_ASSIGN_OR_RETURN(Image3F block_diff_dc, Image3F::Create(xsize_, ysize_));
for (size_t c = 0; c < 3; ++c) {
if (c < 2) { // No blue channel error accumulated at HF.
HWY_DYNAMIC_DISPATCH(L2DiffAsymmetric)
@@ -1852,12 +1891,13 @@ void ButteraugliComparator::DiffmapPsychoImage(const PsychoImage& pi1,
}
ImageF mask;
- HWY_DYNAMIC_DISPATCH(MaskPsychoImage)
- (pi0_, pi1, xsize_, ysize_, params_, &blur_temp_, &mask,
- &block_diff_ac.Plane(1));
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(MaskPsychoImage)(
+ pi0_, pi1, xsize_, ysize_, params_, &blur_temp_, &mask,
+ &block_diff_ac.Plane(1)));
HWY_DYNAMIC_DISPATCH(CombineChannelsToDiffmap)
(mask, block_diff_dc, block_diff_ac, xmul_, &diffmap);
+ return true;
}
double ButteraugliScoreFromDiffmap(const ImageF& diffmap,
@@ -1872,8 +1912,8 @@ double ButteraugliScoreFromDiffmap(const ImageF& diffmap,
return retval;
}
-bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
- double hf_asymmetry, double xmul, ImageF& diffmap) {
+Status ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
+ double hf_asymmetry, double xmul, ImageF& diffmap) {
ButteraugliParams params;
params.hf_asymmetry = hf_asymmetry;
params.xmul = xmul;
@@ -1893,8 +1933,8 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
size_t yborder = ysize < kMax ? (kMax - ysize) / 2 : 0;
size_t xscaled = std::max<size_t>(kMax, xsize);
size_t yscaled = std::max<size_t>(kMax, ysize);
- Image3F scaled0(xscaled, yscaled);
- Image3F scaled1(xscaled, yscaled);
+ JXL_ASSIGN_OR_RETURN(Image3F scaled0, Image3F::Create(xscaled, yscaled));
+ JXL_ASSIGN_OR_RETURN(Image3F scaled1, Image3F::Create(xscaled, yscaled));
for (int i = 0; i < 3; ++i) {
for (size_t y = 0; y < yscaled; ++y) {
for (size_t x = 0; x < xscaled; ++x) {
@@ -1907,7 +1947,7 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
}
ImageF diffmap_scaled;
const bool ok = ButteraugliDiffmap(scaled0, scaled1, params, diffmap_scaled);
- diffmap = ImageF(xsize, ysize);
+ JXL_ASSIGN_OR_RETURN(diffmap, ImageF::Create(xsize, ysize));
for (size_t y = 0; y < ysize; ++y) {
for (size_t x = 0; x < xsize; ++x) {
diffmap.Row(y)[x] = diffmap_scaled.Row(y + yborder)[x + xborder];
@@ -1916,8 +1956,8 @@ bool ButteraugliDiffmapSmall(const Image3F& rgb0, const Image3F& rgb1,
return ok;
}
-bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
- const ButteraugliParams& params, ImageF& diffmap) {
+Status ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
+ const ButteraugliParams& params, ImageF& diffmap) {
const size_t xsize = rgb0.xsize();
const size_t ysize = rgb0.ysize();
if (xsize < 1 || ysize < 1) {
@@ -1930,8 +1970,9 @@ bool ButteraugliDiffmap(const Image3F& rgb0, const Image3F& rgb1,
if (xsize < kMax || ysize < kMax) {
return ButteraugliDiffmapSmall<kMax>(rgb0, rgb1, params, diffmap);
}
- ButteraugliComparator butteraugli(rgb0, params);
- butteraugli.Diffmap(rgb1, diffmap);
+ JXL_ASSIGN_OR_RETURN(std::unique_ptr<ButteraugliComparator> butteraugli,
+ ButteraugliComparator::Make(rgb0, params));
+ JXL_RETURN_IF_ERROR(butteraugli->Diffmap(rgb1, diffmap));
return true;
}
@@ -1954,9 +1995,9 @@ bool ButteraugliInterface(const Image3F& rgb0, const Image3F& rgb1,
return true;
}
-bool ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
- const ButteraugliParams& params,
- ImageF& diffmap, double& diffvalue) {
+Status ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
+ const ButteraugliParams& params,
+ ImageF& diffmap, double& diffvalue) {
const size_t xsize = rgb0.xsize();
const size_t ysize = rgb0.ysize();
if (xsize < 1 || ysize < 1) {
@@ -1973,12 +2014,13 @@ bool ButteraugliInterfaceInPlace(Image3F&& rgb0, Image3F&& rgb1,
}
ImageF subdiffmap;
if (xsize >= 15 && ysize >= 15) {
- Image3F rgb0_sub = SubSample2x(rgb0);
- Image3F rgb1_sub = SubSample2x(rgb1);
- HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)
- (rgb0_sub, rgb1_sub, params, subdiffmap);
+ JXL_ASSIGN_OR_RETURN(Image3F rgb0_sub, SubSample2x(rgb0));
+ JXL_ASSIGN_OR_RETURN(Image3F rgb1_sub, SubSample2x(rgb1));
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(
+ rgb0_sub, rgb1_sub, params, subdiffmap));
}
- HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(rgb0, rgb1, params, diffmap);
+ JXL_RETURN_IF_ERROR(HWY_DYNAMIC_DISPATCH(ButteraugliDiffmapInPlace)(
+ rgb0, rgb1, params, diffmap));
if (xsize >= 15 && ysize >= 15) {
AddSupersampled2x(subdiffmap, 0.5, diffmap);
}
@@ -2066,9 +2108,11 @@ void ScoreToRgb(double score, double good_threshold, double bad_threshold,
} // namespace
-Image3F CreateHeatMapImage(const ImageF& distmap, double good_threshold,
- double bad_threshold) {
- Image3F heatmap(distmap.xsize(), distmap.ysize());
+StatusOr<Image3F> CreateHeatMapImage(const ImageF& distmap,
+ double good_threshold,
+ double bad_threshold) {
+ JXL_ASSIGN_OR_RETURN(Image3F heatmap,
+ Image3F::Create(distmap.xsize(), distmap.ysize()));
for (size_t y = 0; y < distmap.ysize(); ++y) {
const float* BUTTERAUGLI_RESTRICT row_distmap = distmap.ConstRow(y);
float* BUTTERAUGLI_RESTRICT row_h0 = heatmap.PlaneRow(0, y);