mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-19 20:08:28 +01:00
mv SharpYuvEstimate420Risk to extras/
There's no need for this in libsharpyuv currently. This avoids an ABI bump and library size increase. Change-Id: I3e4c79052fdb4d628a2d36491547233dd0b6dc34
This commit is contained in:
parent
e78e924f84
commit
5efd6300dc
@ -42,7 +42,6 @@ sharpyuv_srcs := \
|
|||||||
sharpyuv/sharpyuv_dsp.c \
|
sharpyuv/sharpyuv_dsp.c \
|
||||||
sharpyuv/sharpyuv_gamma.c \
|
sharpyuv/sharpyuv_gamma.c \
|
||||||
sharpyuv/sharpyuv_neon.$(NEON) \
|
sharpyuv/sharpyuv_neon.$(NEON) \
|
||||||
sharpyuv/sharpyuv_risk_table.c \
|
|
||||||
sharpyuv/sharpyuv_sse2.c \
|
sharpyuv/sharpyuv_sse2.c \
|
||||||
|
|
||||||
dec_srcs := \
|
dec_srcs := \
|
||||||
|
@ -185,7 +185,6 @@ SHARPYUV_OBJS = \
|
|||||||
$(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
|
$(DIROBJ)\sharpyuv\sharpyuv_dsp.obj \
|
||||||
$(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
|
$(DIROBJ)\sharpyuv\sharpyuv_gamma.obj \
|
||||||
$(DIROBJ)\sharpyuv\sharpyuv_neon.obj \
|
$(DIROBJ)\sharpyuv\sharpyuv_neon.obj \
|
||||||
$(DIROBJ)\sharpyuv\sharpyuv_risk_table.obj \
|
|
||||||
$(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \
|
$(DIROBJ)\sharpyuv\sharpyuv_sse2.obj \
|
||||||
|
|
||||||
DEC_OBJS = \
|
DEC_OBJS = \
|
||||||
@ -322,6 +321,7 @@ ENC_OBJS = \
|
|||||||
EXTRAS_OBJS = \
|
EXTRAS_OBJS = \
|
||||||
$(DIROBJ)\extras\extras.obj \
|
$(DIROBJ)\extras\extras.obj \
|
||||||
$(DIROBJ)\extras\quality_estimate.obj \
|
$(DIROBJ)\extras\quality_estimate.obj \
|
||||||
|
$(DIROBJ)\extras\sharpyuv_risk_table.obj \
|
||||||
|
|
||||||
IMAGEIO_UTIL_OBJS = \
|
IMAGEIO_UTIL_OBJS = \
|
||||||
$(DIROBJ)\imageio\imageio_util.obj \
|
$(DIROBJ)\imageio\imageio_util.obj \
|
||||||
|
@ -112,7 +112,6 @@ model {
|
|||||||
include "sharpyuv_dsp.c"
|
include "sharpyuv_dsp.c"
|
||||||
include "sharpyuv_gamma.c"
|
include "sharpyuv_gamma.c"
|
||||||
include "sharpyuv_neon.c"
|
include "sharpyuv_neon.c"
|
||||||
include "sharpyuv_risk_table.c"
|
|
||||||
include "sharpyuv_sse2.c"
|
include "sharpyuv_sse2.c"
|
||||||
srcDir "src/dec"
|
srcDir "src/dec"
|
||||||
include "alpha_dec.c"
|
include "alpha_dec.c"
|
||||||
|
@ -7,6 +7,7 @@ noinst_HEADERS += ../src/webp/types.h
|
|||||||
|
|
||||||
libwebpextras_la_SOURCES =
|
libwebpextras_la_SOURCES =
|
||||||
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
|
libwebpextras_la_SOURCES += extras.c extras.h quality_estimate.c
|
||||||
|
libwebpextras_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
|
||||||
|
|
||||||
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
|
libwebpextras_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
libwebpextras_la_LDFLAGS = -lm
|
libwebpextras_la_LDFLAGS = -lm
|
||||||
|
166
extras/extras.c
166
extras/extras.c
@ -11,12 +11,18 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "extras/extras.h"
|
#include "extras/extras.h"
|
||||||
#include "webp/format_constants.h"
|
|
||||||
#include "src/dsp/dsp.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "extras/sharpyuv_risk_table.h"
|
||||||
|
#include "sharpyuv/sharpyuv.h"
|
||||||
|
#include "src/dsp/dsp.h"
|
||||||
|
#include "src/utils/utils.h"
|
||||||
|
#include "webp/format_constants.h"
|
||||||
|
#include "webp/types.h"
|
||||||
|
|
||||||
#define XTRA_MAJ_VERSION 1
|
#define XTRA_MAJ_VERSION 1
|
||||||
#define XTRA_MIN_VERSION 3
|
#define XTRA_MIN_VERSION 3
|
||||||
#define XTRA_REV_VERSION 2
|
#define XTRA_REV_VERSION 2
|
||||||
@ -160,3 +166,159 @@ int WebPUnmultiplyARGB(WebPPicture* pic) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
// 420 risk metric
|
||||||
|
|
||||||
|
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
|
||||||
|
static const int kYuvHalf = 1 << (YUV_FIX - 1);
|
||||||
|
|
||||||
|
// Maps a value in [0, (256 << YUV_FIX) - 1] to [0,
|
||||||
|
// precomputed_scores_table_sampling - 1]. It is important that the extremal
|
||||||
|
// values are preserved and 1:1 mapped:
|
||||||
|
// ConvertValue(0) = 0
|
||||||
|
// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1
|
||||||
|
static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) {
|
||||||
|
v = (v + kYuvHalf) >> YUV_FIX;
|
||||||
|
v = (v < 0) ? 0 : (v > 255) ? 255 : v;
|
||||||
|
return (v * (rgb_sampling_size - 1)) / 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef YUV_FIX
|
||||||
|
|
||||||
|
// For each pixel, computes the index to look up that color in a precomputed
|
||||||
|
// risk score table where the YUV space is subsampled to a size of
|
||||||
|
// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h)
|
||||||
|
static int SharpYuvConvertToYuvSharpnessIndex(
|
||||||
|
int r, int g, int b, const SharpYuvConversionMatrix* matrix,
|
||||||
|
int precomputed_scores_table_sampling) {
|
||||||
|
const int y = SharpYuvConvertValueToSampledIdx(
|
||||||
|
matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g +
|
||||||
|
matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3],
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
const int u = SharpYuvConvertValueToSampledIdx(
|
||||||
|
matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g +
|
||||||
|
matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3],
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
const int v = SharpYuvConvertValueToSampledIdx(
|
||||||
|
matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g +
|
||||||
|
matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3],
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
return y + u * precomputed_scores_table_sampling +
|
||||||
|
v * precomputed_scores_table_sampling *
|
||||||
|
precomputed_scores_table_sampling;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SharpYuvRowToYuvSharpnessIndex(
|
||||||
|
const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
|
||||||
|
int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
|
||||||
|
const SharpYuvConversionMatrix* matrix,
|
||||||
|
int precomputed_scores_table_sampling) {
|
||||||
|
int i;
|
||||||
|
assert(rgb_bit_depth == 8);
|
||||||
|
(void)rgb_bit_depth; // Unused for now.
|
||||||
|
for (i = 0; i < width;
|
||||||
|
++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) {
|
||||||
|
dst[i] =
|
||||||
|
SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix,
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((uint64_t)(W) * (H), sizeof(T)))
|
||||||
|
|
||||||
|
static int DoEstimateRisk(const uint8_t* r_ptr, const uint8_t* g_ptr,
|
||||||
|
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
|
||||||
|
int rgb_bit_depth, int width, int height,
|
||||||
|
const SharpYuvOptions* options,
|
||||||
|
const uint8_t precomputed_scores_table[],
|
||||||
|
int precomputed_scores_table_sampling,
|
||||||
|
float* score_out) {
|
||||||
|
const int sampling3 = precomputed_scores_table_sampling *
|
||||||
|
precomputed_scores_table_sampling *
|
||||||
|
precomputed_scores_table_sampling;
|
||||||
|
const int kNoiseLevel = 4;
|
||||||
|
double total_score = 0;
|
||||||
|
double count = 0;
|
||||||
|
// Rows of indices in
|
||||||
|
uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t);
|
||||||
|
uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t);
|
||||||
|
uint16_t* tmp;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (row1 == NULL || row2 == NULL) {
|
||||||
|
WebPFree(row1);
|
||||||
|
WebPFree(row2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the first row ahead.
|
||||||
|
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
||||||
|
width, row2, options->yuv_matrix,
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
|
||||||
|
for (j = 1; j < height; ++j) {
|
||||||
|
r_ptr += rgb_stride;
|
||||||
|
g_ptr += rgb_stride;
|
||||||
|
b_ptr += rgb_stride;
|
||||||
|
// Swap row 1 and row 2.
|
||||||
|
tmp = row1;
|
||||||
|
row1 = row2;
|
||||||
|
row2 = tmp;
|
||||||
|
// Convert the row below.
|
||||||
|
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
||||||
|
width, row2, options->yuv_matrix,
|
||||||
|
precomputed_scores_table_sampling);
|
||||||
|
for (i = 0; i < width - 1; ++i) {
|
||||||
|
const int idx0 = row1[i + 0];
|
||||||
|
const int idx1 = row1[i + 1];
|
||||||
|
const int idx2 = row2[i + 0];
|
||||||
|
const int score = precomputed_scores_table[idx0 + sampling3 * idx1] +
|
||||||
|
precomputed_scores_table[idx0 + sampling3 * idx2] +
|
||||||
|
precomputed_scores_table[idx1 + sampling3 * idx2];
|
||||||
|
if (score > kNoiseLevel) {
|
||||||
|
total_score += score;
|
||||||
|
count += 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count > 0.) total_score /= count;
|
||||||
|
|
||||||
|
// If less than 1% of pixels were evaluated -> below noise level.
|
||||||
|
if (100. * count / (width * height) < 1.) total_score = 0.;
|
||||||
|
|
||||||
|
// Rescale to [0:100]
|
||||||
|
total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.;
|
||||||
|
|
||||||
|
WebPFree(row1);
|
||||||
|
WebPFree(row2);
|
||||||
|
|
||||||
|
*score_out = (float)total_score;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SAFE_ALLOC
|
||||||
|
|
||||||
|
int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr,
|
||||||
|
const void* b_ptr, int rgb_step, int rgb_stride,
|
||||||
|
int rgb_bit_depth, int width, int height,
|
||||||
|
const SharpYuvOptions* options, float* score) {
|
||||||
|
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
|
||||||
|
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL ||
|
||||||
|
score == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (rgb_bit_depth != 8) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 4 || height <= 4) {
|
||||||
|
*score = 0.0f; // too small, no real risk.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoEstimateRisk(
|
||||||
|
(const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
|
||||||
|
rgb_step, rgb_stride, rgb_bit_depth, width, height, options,
|
||||||
|
kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score);
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
@ -17,9 +17,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "sharpyuv/sharpyuv.h"
|
||||||
#include "webp/encode.h"
|
#include "webp/encode.h"
|
||||||
|
|
||||||
#define WEBP_EXTRAS_ABI_VERSION 0x0002 // MAJOR(8b) + MINOR(8b)
|
#define WEBP_EXTRAS_ABI_VERSION 0x0003 // MAJOR(8b) + MINOR(8b)
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -70,6 +71,38 @@ WEBP_EXTERN int VP8EstimateQuality(const uint8_t* const data, size_t size);
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Computes a score between 0 and 100 which represents the risk of having visual
|
||||||
|
// quality loss from converting an RGB image to YUV420.
|
||||||
|
// A low score, typically < 40, means there is a low risk of artifacts from
|
||||||
|
// chroma subsampling and a simple averaging algorithm can be used instead of
|
||||||
|
// the more expensive SharpYuvConvert function.
|
||||||
|
// A medium score, typically >= 40 and < 70, means that simple chroma
|
||||||
|
// subsampling will produce artifacts and it may be advisable to use the more
|
||||||
|
// costly SharpYuvConvert for YUV420 conversion.
|
||||||
|
// A high score, typically >= 70, means there is a very high risk of artifacts
|
||||||
|
// from chroma subsampling even with SharpYuvConvert, and best results might be
|
||||||
|
// achieved by using YUV444.
|
||||||
|
// If not using SharpYuvConvert, a threshold of about 50 can be used to decide
|
||||||
|
// between (simple averaging) 420 and 444.
|
||||||
|
// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
|
||||||
|
// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
|
||||||
|
// rgb_step: distance in bytes between two horizontally adjacent pixels on the
|
||||||
|
// r, g and b channels. If rgb_bit_depth is > 8, it should be a
|
||||||
|
// multiple of 2.
|
||||||
|
// rgb_stride: distance in bytes between two vertically adjacent pixels on the
|
||||||
|
// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
|
||||||
|
// multiple of 2.
|
||||||
|
// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is
|
||||||
|
// currently supported.
|
||||||
|
// width, height: width and height of the image in pixels
|
||||||
|
// Returns 0 on failure.
|
||||||
|
WEBP_EXTERN int SharpYuvEstimate420Risk(
|
||||||
|
const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
|
||||||
|
int rgb_stride, int rgb_bit_depth, int width, int height,
|
||||||
|
const SharpYuvOptions* options, float* score);
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
//
|
//
|
||||||
// Precomputed data for 420 risk estimation.
|
// Precomputed data for 420 risk estimation.
|
||||||
|
|
||||||
#ifndef WEBP_SHARPYUV_SHARPYUV_RISK_TABLE_H_
|
#ifndef WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
||||||
#define WEBP_SHARPYUV_SHARPYUV_RISK_TABLE_H_
|
#define WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
||||||
|
|
||||||
#include "src/webp/types.h"
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
@ -24,4 +24,4 @@ extern const int kSharpYuvPrecomputedRiskYuvSampling;
|
|||||||
// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB
|
// Table size: kSharpYuvPrecomputedRiskYuvSampling^6 bytes or 114 KiB
|
||||||
extern const uint8_t kSharpYuvPrecomputedRisk[];
|
extern const uint8_t kSharpYuvPrecomputedRisk[];
|
||||||
|
|
||||||
#endif // WEBP_SHARPYUV_SHARPYUV_RISK_TABLE_H_
|
#endif // WEBP_EXTRAS_SHARPYUV_RISK_TABLE_H_
|
@ -133,7 +133,6 @@ SHARPYUV_OBJS = \
|
|||||||
sharpyuv/sharpyuv_dsp.o \
|
sharpyuv/sharpyuv_dsp.o \
|
||||||
sharpyuv/sharpyuv_gamma.o \
|
sharpyuv/sharpyuv_gamma.o \
|
||||||
sharpyuv/sharpyuv_neon.o \
|
sharpyuv/sharpyuv_neon.o \
|
||||||
sharpyuv/sharpyuv_risk_table.o \
|
|
||||||
sharpyuv/sharpyuv_sse2.o \
|
sharpyuv/sharpyuv_sse2.o \
|
||||||
|
|
||||||
DEC_OBJS = \
|
DEC_OBJS = \
|
||||||
@ -292,6 +291,7 @@ UTILS_ENC_OBJS = \
|
|||||||
EXTRA_OBJS = \
|
EXTRA_OBJS = \
|
||||||
extras/extras.o \
|
extras/extras.o \
|
||||||
extras/quality_estimate.o \
|
extras/quality_estimate.o \
|
||||||
|
extras/sharpyuv_risk_table.o \
|
||||||
|
|
||||||
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
LIBWEBPDECODER_OBJS = $(DEC_OBJS) $(DSP_DEC_OBJS) $(UTILS_DEC_OBJS)
|
||||||
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
|
LIBWEBP_OBJS = $(LIBWEBPDECODER_OBJS) $(ENC_OBJS) \
|
||||||
|
@ -30,7 +30,6 @@ libsharpyuv_la_SOURCES += sharpyuv_cpu.c sharpyuv_cpu.h
|
|||||||
libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
|
libsharpyuv_la_SOURCES += sharpyuv_csp.c sharpyuv_csp.h
|
||||||
libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
|
libsharpyuv_la_SOURCES += sharpyuv_dsp.c sharpyuv_dsp.h
|
||||||
libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
|
libsharpyuv_la_SOURCES += sharpyuv_gamma.c sharpyuv_gamma.h
|
||||||
libsharpyuv_la_SOURCES += sharpyuv_risk_table.c sharpyuv_risk_table.h
|
|
||||||
libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
|
libsharpyuv_la_SOURCES += sharpyuv.c sharpyuv.h
|
||||||
|
|
||||||
libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
|
libsharpyuv_la_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "sharpyuv/sharpyuv_cpu.h"
|
#include "sharpyuv/sharpyuv_cpu.h"
|
||||||
#include "sharpyuv/sharpyuv_dsp.h"
|
#include "sharpyuv/sharpyuv_dsp.h"
|
||||||
#include "sharpyuv/sharpyuv_gamma.h"
|
#include "sharpyuv/sharpyuv_gamma.h"
|
||||||
#include "sharpyuv/sharpyuv_risk_table.h"
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -436,6 +435,8 @@ static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef SAFE_ALLOC
|
||||||
|
|
||||||
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
|
#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
|
||||||
#include <pthread.h> // NOLINT
|
#include <pthread.h> // NOLINT
|
||||||
|
|
||||||
@ -571,105 +572,3 @@ int SharpYuvConvertWithOptions(const void* r_ptr, const void* g_ptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// 420 risk metric
|
|
||||||
|
|
||||||
static int DoEstimateRisk(const uint8_t* r_ptr, const uint8_t* g_ptr,
|
|
||||||
const uint8_t* b_ptr, int rgb_step, int rgb_stride,
|
|
||||||
int rgb_bit_depth, int width, int height,
|
|
||||||
const SharpYuvOptions* options,
|
|
||||||
const uint8_t precomputed_scores_table[],
|
|
||||||
int precomputed_scores_table_sampling,
|
|
||||||
float* score_out) {
|
|
||||||
const int sampling3 = precomputed_scores_table_sampling *
|
|
||||||
precomputed_scores_table_sampling *
|
|
||||||
precomputed_scores_table_sampling;
|
|
||||||
const int kNoiseLevel = 4;
|
|
||||||
double total_score = 0;
|
|
||||||
double count = 0;
|
|
||||||
// Rows of indices in
|
|
||||||
uint16_t* row1 = SAFE_ALLOC(width, 1, uint16_t);
|
|
||||||
uint16_t* row2 = SAFE_ALLOC(width, 1, uint16_t);
|
|
||||||
uint16_t* tmp;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if (row1 == NULL || row2 == NULL) {
|
|
||||||
free(row1);
|
|
||||||
free(row2);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert the first row ahead.
|
|
||||||
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
|
||||||
width, row2, options->yuv_matrix,
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
|
|
||||||
for (j = 1; j < height; ++j) {
|
|
||||||
r_ptr += rgb_stride;
|
|
||||||
g_ptr += rgb_stride;
|
|
||||||
b_ptr += rgb_stride;
|
|
||||||
// Swap row 1 and row 2.
|
|
||||||
tmp = row1;
|
|
||||||
row1 = row2;
|
|
||||||
row2 = tmp;
|
|
||||||
// Convert the row below.
|
|
||||||
SharpYuvRowToYuvSharpnessIndex(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth,
|
|
||||||
width, row2, options->yuv_matrix,
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
for (i = 0; i < width - 1; ++i) {
|
|
||||||
const int idx0 = row1[i + 0];
|
|
||||||
const int idx1 = row1[i + 1];
|
|
||||||
const int idx2 = row2[i + 0];
|
|
||||||
const int score = precomputed_scores_table[idx0 + sampling3 * idx1] +
|
|
||||||
precomputed_scores_table[idx0 + sampling3 * idx2] +
|
|
||||||
precomputed_scores_table[idx1 + sampling3 * idx2];
|
|
||||||
if (score > kNoiseLevel) {
|
|
||||||
total_score += score;
|
|
||||||
count += 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count > 0.) total_score /= count;
|
|
||||||
|
|
||||||
// If less than 1% of pixels were evaluated -> below noise level.
|
|
||||||
if (100. * count / (width * height) < 1.) total_score = 0.;
|
|
||||||
|
|
||||||
// Rescale to [0:100]
|
|
||||||
total_score = (total_score > 25.) ? 100. : total_score * 100. / 25.;
|
|
||||||
|
|
||||||
free(row1);
|
|
||||||
free(row2);
|
|
||||||
|
|
||||||
*score_out = (float)total_score;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SharpYuvEstimate420Risk(const void* r_ptr, const void* g_ptr,
|
|
||||||
const void* b_ptr, int rgb_step, int rgb_stride,
|
|
||||||
int rgb_bit_depth, int width, int height,
|
|
||||||
const SharpYuvOptions* options, float* score) {
|
|
||||||
if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
|
|
||||||
r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || options == NULL ||
|
|
||||||
score == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (rgb_bit_depth != 8) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width <= 4 || height <= 4) {
|
|
||||||
*score = 0.0f; // too small, no real risk.
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The address of the function pointer is used to avoid a read race.
|
|
||||||
SharpYuvInit((VP8CPUInfo)&SharpYuvGetCPUInfo);
|
|
||||||
|
|
||||||
return DoEstimateRisk(
|
|
||||||
(const uint8_t*)r_ptr, (const uint8_t*)g_ptr, (const uint8_t*)b_ptr,
|
|
||||||
rgb_step, rgb_stride, rgb_bit_depth, width, height, options,
|
|
||||||
kSharpYuvPrecomputedRisk, kSharpYuvPrecomputedRiskYuvSampling, score);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef SAFE_ALLOC
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
@ -53,7 +53,7 @@ extern "C" {
|
|||||||
|
|
||||||
// SharpYUV API version following the convention from semver.org
|
// SharpYUV API version following the convention from semver.org
|
||||||
#define SHARPYUV_VERSION_MAJOR 0
|
#define SHARPYUV_VERSION_MAJOR 0
|
||||||
#define SHARPYUV_VERSION_MINOR 5
|
#define SHARPYUV_VERSION_MINOR 4
|
||||||
#define SHARPYUV_VERSION_PATCH 0
|
#define SHARPYUV_VERSION_PATCH 0
|
||||||
// Version as a uint32_t. The major number is the high 8 bits.
|
// Version as a uint32_t. The major number is the high 8 bits.
|
||||||
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
|
// The minor number is the middle 8 bits. The patch number is the low 16 bits.
|
||||||
@ -164,36 +164,6 @@ SHARPYUV_EXTERN int SharpYuvConvertWithOptions(
|
|||||||
int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width,
|
int u_stride, void* v_ptr, int v_stride, int yuv_bit_depth, int width,
|
||||||
int height, const SharpYuvOptions* options);
|
int height, const SharpYuvOptions* options);
|
||||||
|
|
||||||
// Computes a score between 0 and 100 which represents the risk of having visual
|
|
||||||
// quality loss from converting an RGB image to YUV420.
|
|
||||||
// A low score, typically < 40, means there is a low risk of artifacts from
|
|
||||||
// chroma subsampling and a simple averaging algorithm can be used instead of
|
|
||||||
// the more expensive SharpYuvConvert function.
|
|
||||||
// A medium score, typically >= 40 and < 70, means that simple chroma
|
|
||||||
// subsampling will produce artifacts and it may be advisable to use the more
|
|
||||||
// costly SharpYuvConvert for YUV420 conversion.
|
|
||||||
// A high score, typically >= 70, means there is a very high risk of artifacts
|
|
||||||
// from chroma subsampling even with SharpYuvConvert, and best results might be
|
|
||||||
// achieved by using YUV444.
|
|
||||||
// If not using SharpYuvConvert, a threshold of about 50 can be used to decide
|
|
||||||
// between (simple averaging) 420 and 444.
|
|
||||||
// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
|
|
||||||
// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
|
|
||||||
// rgb_step: distance in bytes between two horizontally adjacent pixels on the
|
|
||||||
// r, g and b channels. If rgb_bit_depth is > 8, it should be a
|
|
||||||
// multiple of 2.
|
|
||||||
// rgb_stride: distance in bytes between two vertically adjacent pixels on the
|
|
||||||
// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
|
|
||||||
// multiple of 2.
|
|
||||||
// rgb_bit_depth: number of bits for each r/g/b value. Only a value of 8 is
|
|
||||||
// currently supported.
|
|
||||||
// width, height: width and height of the image in pixels
|
|
||||||
// Returns 0 on failure.
|
|
||||||
SHARPYUV_EXTERN int SharpYuvEstimate420Risk(
|
|
||||||
const void* r_ptr, const void* g_ptr, const void* b_ptr, int rgb_step,
|
|
||||||
int rgb_stride, int rgb_bit_depth, int width, int height,
|
|
||||||
const SharpYuvOptions* options, float* score);
|
|
||||||
|
|
||||||
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
|
// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
|
||||||
// support (it's rarely used in practice, especially for images).
|
// support (it's rarely used in practice, especially for images).
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "sharpyuv/sharpyuv.h"
|
|
||||||
#include "sharpyuv/sharpyuv_cpu.h"
|
#include "sharpyuv/sharpyuv_cpu.h"
|
||||||
#include "src/webp/types.h"
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
@ -64,58 +63,6 @@ static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len,
|
|||||||
}
|
}
|
||||||
#endif // !WEBP_NEON_OMIT_C_CODE
|
#endif // !WEBP_NEON_OMIT_C_CODE
|
||||||
|
|
||||||
#define YUV_FIX 16 // fixed-point precision for RGB->YUV
|
|
||||||
static const int kYuvHalf = 1 << (YUV_FIX - 1);
|
|
||||||
|
|
||||||
// Maps a value in [0, (256 << YUV_FIX) - 1] to [0,
|
|
||||||
// precomputed_scores_table_sampling - 1]. It is important that the extremal
|
|
||||||
// values are preserved and 1:1 mapped:
|
|
||||||
// ConvertValue(0) = 0
|
|
||||||
// ConvertValue((256 << 16) - 1) = rgb_sampling_size - 1
|
|
||||||
static int SharpYuvConvertValueToSampledIdx(int v, int rgb_sampling_size) {
|
|
||||||
v = (v + kYuvHalf) >> YUV_FIX;
|
|
||||||
v = (v < 0) ? 0 : (v > 255) ? 255 : v;
|
|
||||||
return (v * (rgb_sampling_size - 1)) / 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef YUV_FIX
|
|
||||||
|
|
||||||
static int SharpYuvConvertToYuvSharpnessIndex(
|
|
||||||
int r, int g, int b, const SharpYuvConversionMatrix* matrix,
|
|
||||||
int precomputed_scores_table_sampling) {
|
|
||||||
const int y = SharpYuvConvertValueToSampledIdx(
|
|
||||||
matrix->rgb_to_y[0] * r + matrix->rgb_to_y[1] * g +
|
|
||||||
matrix->rgb_to_y[2] * b + matrix->rgb_to_y[3],
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
const int u = SharpYuvConvertValueToSampledIdx(
|
|
||||||
matrix->rgb_to_u[0] * r + matrix->rgb_to_u[1] * g +
|
|
||||||
matrix->rgb_to_u[2] * b + matrix->rgb_to_u[3],
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
const int v = SharpYuvConvertValueToSampledIdx(
|
|
||||||
matrix->rgb_to_v[0] * r + matrix->rgb_to_v[1] * g +
|
|
||||||
matrix->rgb_to_v[2] * b + matrix->rgb_to_v[3],
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
return y + u * precomputed_scores_table_sampling +
|
|
||||||
v * precomputed_scores_table_sampling *
|
|
||||||
precomputed_scores_table_sampling;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SharpYuvRowToYuvSharpnessIndex_C(
|
|
||||||
const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
|
|
||||||
int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
|
|
||||||
const SharpYuvConversionMatrix* matrix,
|
|
||||||
int precomputed_scores_table_sampling) {
|
|
||||||
int i;
|
|
||||||
assert(rgb_bit_depth == 8);
|
|
||||||
(void)rgb_bit_depth; // Unused for now.
|
|
||||||
for (i = 0; i < width;
|
|
||||||
++i, r_ptr += rgb_step, g_ptr += rgb_step, b_ptr += rgb_step) {
|
|
||||||
dst[i] =
|
|
||||||
SharpYuvConvertToYuvSharpnessIndex(r_ptr[0], g_ptr[0], b_ptr[0], matrix,
|
|
||||||
precomputed_scores_table_sampling);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
|
uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
|
||||||
@ -124,13 +71,6 @@ void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
|
|||||||
int len);
|
int len);
|
||||||
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
|
void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
|
||||||
const uint16_t* best_y, uint16_t* out, int bit_depth);
|
const uint16_t* best_y, uint16_t* out, int bit_depth);
|
||||||
void (*SharpYuvRowToYuvSharpnessIndex)(const uint8_t* r_ptr,
|
|
||||||
const uint8_t* g_ptr,
|
|
||||||
const uint8_t* b_ptr, int rgb_step,
|
|
||||||
int rgb_bit_depth, int width,
|
|
||||||
uint16_t* dst,
|
|
||||||
const SharpYuvConversionMatrix* matrix,
|
|
||||||
int precomputed_scores_table_sampling);
|
|
||||||
|
|
||||||
extern VP8CPUInfo SharpYuvGetCPUInfo;
|
extern VP8CPUInfo SharpYuvGetCPUInfo;
|
||||||
extern void InitSharpYuvSSE2(void);
|
extern void InitSharpYuvSSE2(void);
|
||||||
@ -142,8 +82,6 @@ void SharpYuvInitDsp(void) {
|
|||||||
SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
|
SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
|
||||||
SharpYuvFilterRow = SharpYuvFilterRow_C;
|
SharpYuvFilterRow = SharpYuvFilterRow_C;
|
||||||
#endif
|
#endif
|
||||||
// There is only a C version for now so always include it.
|
|
||||||
SharpYuvRowToYuvSharpnessIndex = SharpYuvRowToYuvSharpnessIndex_C;
|
|
||||||
|
|
||||||
if (SharpYuvGetCPUInfo != NULL) {
|
if (SharpYuvGetCPUInfo != NULL) {
|
||||||
#if defined(WEBP_HAVE_SSE2)
|
#if defined(WEBP_HAVE_SSE2)
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
||||||
#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
||||||
|
|
||||||
#include "sharpyuv/sharpyuv.h"
|
|
||||||
#include "sharpyuv/sharpyuv_cpu.h"
|
#include "sharpyuv/sharpyuv_cpu.h"
|
||||||
#include "src/webp/types.h"
|
#include "src/webp/types.h"
|
||||||
|
|
||||||
@ -24,15 +23,6 @@ extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
|
|||||||
const uint16_t* best_y, uint16_t* out,
|
const uint16_t* best_y, uint16_t* out,
|
||||||
int bit_depth);
|
int bit_depth);
|
||||||
|
|
||||||
// For each pixel, computes the index to look up that color in a precomputed
|
|
||||||
// risk score table where the YUV space is subsampled to a size of
|
|
||||||
// precomputed_scores_table_sampling^3 (see sharpyuv_risk_table.h)
|
|
||||||
extern void (*SharpYuvRowToYuvSharpnessIndex)(
|
|
||||||
const uint8_t* r_ptr, const uint8_t* g_ptr, const uint8_t* b_ptr,
|
|
||||||
int rgb_step, int rgb_bit_depth, int width, uint16_t* dst,
|
|
||||||
const SharpYuvConversionMatrix* matrix,
|
|
||||||
int precomputed_scores_table_sampling);
|
|
||||||
|
|
||||||
void SharpYuvInitDsp(void);
|
void SharpYuvInitDsp(void);
|
||||||
|
|
||||||
#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user