mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
avfilter/palettegen: define the best axis to cut using the squared error
This is following the results from personal research¹. ¹: https://github.com/ubitux/research/tree/main/color-quantization#results
This commit is contained in:
parent
21f7814238
commit
86bced7c65
@ -147,31 +147,39 @@ static av_always_inline int diff(const uint32_t a, const uint32_t b)
|
|||||||
|
|
||||||
static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
|
static void compute_box_stats(PaletteGenContext *s, struct range_box *box)
|
||||||
{
|
{
|
||||||
int rr, gr, br;
|
int avg[3];
|
||||||
|
int64_t er2[3] = {0};
|
||||||
|
|
||||||
/* compute the box weight (sum all the weights of the colors in the
|
/* Compute average color */
|
||||||
* range) and its boundings */
|
uint64_t sr = 0, sg = 0, sb = 0;
|
||||||
uint8_t min[3] = {0xff, 0xff, 0xff};
|
|
||||||
uint8_t max[3] = {0x00, 0x00, 0x00};
|
|
||||||
box->weight = 0;
|
box->weight = 0;
|
||||||
for (int i = box->start; i < box->start + box->len; i++) {
|
for (int i = box->start; i < box->start + box->len; i++) {
|
||||||
const struct color_ref *ref = s->refs[i];
|
const struct color_ref *ref = s->refs[i];
|
||||||
const uint32_t rgb = ref->color;
|
sr += (ref->color >> 16 & 0xff) * ref->count;
|
||||||
const uint8_t r = rgb >> 16 & 0xff, g = rgb >> 8 & 0xff, b = rgb & 0xff;
|
sg += (ref->color >> 8 & 0xff) * ref->count;
|
||||||
min[0] = FFMIN(r, min[0]), max[0] = FFMAX(r, max[0]);
|
sb += (ref->color & 0xff) * ref->count;
|
||||||
min[1] = FFMIN(g, min[1]), max[1] = FFMAX(g, max[1]);
|
|
||||||
min[2] = FFMIN(b, min[2]), max[2] = FFMAX(b, max[2]);
|
|
||||||
box->weight += ref->count;
|
box->weight += ref->count;
|
||||||
}
|
}
|
||||||
|
avg[0] = sr / box->weight;
|
||||||
|
avg[1] = sg / box->weight;
|
||||||
|
avg[2] = sb / box->weight;
|
||||||
|
|
||||||
/* define the axis to sort by according to the widest range of colors */
|
/* Compute squared error of each color channel */
|
||||||
rr = max[0] - min[0];
|
for (int i = box->start; i < box->start + box->len; i++) {
|
||||||
gr = max[1] - min[1];
|
const struct color_ref *ref = s->refs[i];
|
||||||
br = max[2] - min[2];
|
const int64_t dr = (int)(ref->color >> 16 & 0xff) - avg[0];
|
||||||
|
const int64_t dg = (int)(ref->color >> 8 & 0xff) - avg[1];
|
||||||
|
const int64_t db = (int)(ref->color & 0xff) - avg[2];
|
||||||
|
er2[0] += dr * dr * ref->count;
|
||||||
|
er2[1] += dg * dg * ref->count;
|
||||||
|
er2[2] += db * db * ref->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Define the best axis candidate for cutting the box */
|
||||||
box->major_axis = 1; // pick green by default (the color the eye is the most sensitive to)
|
box->major_axis = 1; // pick green by default (the color the eye is the most sensitive to)
|
||||||
if (br >= rr && br >= gr) box->major_axis = 2;
|
if (er2[2] >= er2[0] && er2[2] >= er2[1]) box->major_axis = 2;
|
||||||
if (rr >= gr && rr >= br) box->major_axis = 0;
|
if (er2[0] >= er2[1] && er2[0] >= er2[2]) box->major_axis = 0;
|
||||||
if (gr >= rr && gr >= br) box->major_axis = 1; // prefer green again
|
if (er2[1] >= er2[0] && er2[1] >= er2[2]) box->major_axis = 1; // prefer green again
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
#codec_id 0: rawvideo
|
#codec_id 0: rawvideo
|
||||||
#dimensions 0: 16x16
|
#dimensions 0: 16x16
|
||||||
#sar 0: 1/1
|
#sar 0: 1/1
|
||||||
0, 0, 0, 1, 1024, 0x3395ef5a
|
0, 0, 0, 1, 1024, 0x394ee723
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
#codec_id 0: rawvideo
|
#codec_id 0: rawvideo
|
||||||
#dimensions 0: 16x16
|
#dimensions 0: 16x16
|
||||||
#sar 0: 1/1
|
#sar 0: 1/1
|
||||||
0, 0, 0, 1, 1024, 0x23e072c8
|
0, 0, 0, 1, 1024, 0xc54d773d
|
||||||
|
Loading…
Reference in New Issue
Block a user