Exemplo n.º 1
0
static int best_color_index(f_pixel px, const colormap *map, float min_opaque_val, float *dist_out)
{
    const colormap_item *const acolormap = map->palette;
    const int numcolors = map->colors;
    int ind=0;
    const int iebug = px.a > min_opaque_val;
    float dist = colordifference(px,acolormap[0].acolor);

    for(int i = 1; i < numcolors; i++) {
        float newdist = colordifference(px,acolormap[i].acolor);

        if (newdist < dist) {

            /* penalty for making holes in IE */
            if (iebug && acolormap[i].acolor.a < 1) {
                if (newdist+1.f/1024.f > dist) continue;
            }

            ind = i;
            dist = newdist;
        }
    }

    if (dist_out) *dist_out = dist;
    return ind;
}
Exemplo n.º 2
0
/** Weighted per-channel variance of the box. It's used to decide which channel to split by */
static f_pixel box_variance(const hist_item achv[], const struct box *box)
{
    f_pixel mean = box->color;
    double variancea=0, variancer=0, varianceg=0, varianceb=0;

    for(unsigned int i = 0; i < box->colors; ++i) {
        f_pixel px = achv[box->ind + i].acolor;
        double weight = achv[box->ind + i].adjusted_weight;
        variancea += variance_diff(mean.a - px.a, 2.0/256.0)*weight;
        variancer += variance_diff(mean.r - px.r, 1.0/256.0)*weight;
        varianceg += variance_diff(mean.g - px.g, 1.0/256.0)*weight;
        varianceb += variance_diff(mean.b - px.b, 1.0/256.0)*weight;
    }

    return (f_pixel){
        .a = variancea*(4.0/16.0),
        .r = variancer*(7.0/16.0),
        .g = varianceg*(9.0/16.0),
        .b = varianceb*(5.0/16.0),
    };
}

static double box_max_error(const hist_item achv[], const struct box *box)
{
    f_pixel mean = box->color;
    double max_error = 0;

    for(unsigned int i = 0; i < box->colors; ++i) {
        const double diff = colordifference(mean, achv[box->ind + i].acolor);
        if (diff > max_error) {
            max_error = diff;
        }
    }
    return max_error;
}
Exemplo n.º 3
0
inline static double color_weight(f_pixel median, hist_item h)
{
    float diff = colordifference(median, h.acolor);
    // if color is "good enough", don't split further
    if (diff < 2.f/256.f/256.f) diff /= 2.f;
    return sqrt(diff) * (sqrt(1.0+h.adjusted_weight)-1.0);
}
Exemplo n.º 4
0
static inline
double color_weight(f_pixel median, const hist_item& h)
{
	double diff = colordifference(median, h.acolor);
	// if color is "good enough", don't split further
	if (diff < 1.0/256.0/256.0) diff /= 2.0;
	return sqrt(diff) * (sqrt(1.0+h.adjusted_weight)-1.0);
}
Exemplo n.º 5
0
/* increase histogram popularity by difference from the final color (this is used as part of feedback loop) */
static void adjust_histogram(hist_item *achv, const colormap *map, const struct box* bv, unsigned int boxes)
{
    for(unsigned int bi = 0; bi < boxes; ++bi) {
        for(unsigned int i=bv[bi].ind; i < bv[bi].ind+bv[bi].colors; i++) {
            achv[i].adjusted_weight *= sqrt(1.0 +colordifference(map->palette[bi].acolor, achv[i].acolor)/4.0);
            achv[i].likely_colormap_index = bi;
        }
    }
}
Exemplo n.º 6
0
double box_error(const struct box *box, const hist_item achv[])
{
    f_pixel avg = box->color;

    double total_error=0;
    for (unsigned int i = 0; i < box->colors; ++i) {
        total_error += colordifference(avg, achv[box->ind + i].acolor) * achv[box->ind + i].perceptual_weight;
    }

    return total_error;
}
Exemplo n.º 7
0
static double box_max_error(const hist_item achv[], const struct box *box)
{
    f_pixel mean = box->color;
    double max_error = 0;
	unsigned int i;

    for(i = 0; i < box->colors; ++i) {
        const double diff = colordifference(mean, achv[box->ind + i].acolor);
        if (diff > max_error) {
            max_error = diff;
        }
    }
    return max_error;
}
Exemplo n.º 8
0
/* increase histogram popularity by difference from the final color (this is used as part of feedback loop) */
static
void adjust_histogram(
	hist_item* achv,
	const colormap* map,
	const box* bv,
	uint boxes
	)
{
	for (uint bi=0; bi<boxes; ++bi) {
		const box& bx = bv[bi];
		f_pixel pc = map->palette[bi].acolor;
		for (uint i=bx.ind; i<bx.ind+bx.colors; i++) {
			hist_item& hist = achv[i];
			hist.adjusted_weight *= sqrt(1.0 + colordifference(pc, hist.acolor) / 2.0);
		}
	}
}
Exemplo n.º 9
0
struct nearest_map *nearest_init(const colormap *map)
{
    mempool m = NULL;
    struct nearest_map *centroids = mempool_new(&m, sizeof(*centroids));
    centroids->mempool = m;

    unsigned int skipped=0;
    unsigned int skip_index[map->colors]; for(unsigned int j=0; j < map->colors; j++) skip_index[j]=0;

    colormap *subset_palette = get_subset_palette(map);
    const int selected_heads = subset_palette->colors;
    centroids->heads = mempool_new(&centroids->mempool, sizeof(centroids->heads[0])*(selected_heads+1)); // +1 is fallback head

    unsigned int h=0;
    for(; h < selected_heads; h++)
    {
        unsigned int num_candiadtes = 1+(map->colors - skipped)/((1+selected_heads-h)/2);

        centroids->heads[h] = build_head(subset_palette->palette[h].acolor, map, num_candiadtes, &centroids->mempool, skip_index, &skipped);
        if (centroids->heads[h].num_candidates == 0) {
            break;
        }
    }

    centroids->heads[h].radius = MAX_DIFF;
    centroids->heads[h].center = (f_pixel){0,0,0,0};
    centroids->heads[h].num_candidates = 0;
    centroids->heads[h].candidates = mempool_new(&centroids->mempool, (map->colors - skipped) * sizeof(centroids->heads[h].candidates[0]));
    for(unsigned int i=0; i < map->colors; i++) {
        if (skip_index[i]) continue;

        centroids->heads[h].candidates[centroids->heads[h].num_candidates++] = (struct color_entry) {
            .color = map->palette[i].acolor,
            .index = i,
            .radius = 999,
        };
    }
    centroids->num_heads = ++h;

    // get_subset_palette could have created a copy
    if (subset_palette != map->subset_palette) {
        pam_freecolormap(subset_palette);
    }

    return centroids;
}

unsigned int nearest_search(const struct nearest_map *centroids, const f_pixel px, const float min_opaque_val, float *diff)
{
    const int iebug = px.a > min_opaque_val;

    const struct head *const heads = centroids->heads;
    for(unsigned int i=0; i < centroids->num_heads; i++) {
        float headdist = colordifference(px, heads[i].center);

        if (headdist <= heads[i].radius) {
            assert(heads[i].num_candidates);
            unsigned int ind=heads[i].candidates[0].index;
            float dist = colordifference(px, heads[i].candidates[0].color);

            /* penalty for making holes in IE */
            if (iebug && heads[i].candidates[0].color.a < 1) {
                dist += 1.f/1024.f;
            }

            for(unsigned int j=1; j < heads[i].num_candidates; j++) {
                float newdist = colordifference(px, heads[i].candidates[j].color);

                /* penalty for making holes in IE */
                if (iebug && heads[i].candidates[j].color.a < 1) {
                    newdist += 1.f/1024.f;
                }

                if (newdist < dist) {

                    dist = newdist;
                    ind = heads[i].candidates[j].index;
                }
            }
            if (diff) *diff = dist;
            return ind;
        }
    }
    assert(0);
    return 0;
}

void nearest_free(struct nearest_map *centroids)
{
    mempool_free(centroids->mempool);
}
Exemplo n.º 10
0
static struct head build_head(f_pixel px, const colormap *map, int num_candidates, mempool *m, unsigned int skip_index[], unsigned int *skipped)
{
    struct sorttmp colors[map->colors];
    unsigned int colorsused=0;

    for(unsigned int i=0; i < map->colors; i++) {
        if (skip_index[i]) continue;
        colors[colorsused].index = i;
        colors[colorsused].radius = colordifference(px, map->palette[i].acolor);
        colorsused++;
    }

    qsort(&colors, colorsused, sizeof(colors[0]), compareradius);
    assert(colorsused < 2 || colors[0].radius <= colors[1].radius);

    num_candidates = MIN(colorsused, num_candidates);

    struct head h;
    h.candidates = mempool_new(m, num_candidates * sizeof(h.candidates[0]));
    h.center = px;
    h.num_candidates = num_candidates;
    for(unsigned int i=0; i < num_candidates; i++) {
        h.candidates[i] = (struct color_entry) {
            .color = map->palette[colors[i].index].acolor,
            .index = colors[i].index,
            .radius = colors[i].radius,
        };
    }
    h.radius = colors[num_candidates-1].radius/4.0f; // /2 squared

    for(unsigned int i=0; i < num_candidates; i++) {

        assert(colors[i].radius <= h.radius*4.0f);
        // divide again as that's matching certain subset within radius-limited subset
        // - 1/256 is a tolerance for miscalculation (seems like colordifference isn't exact)
        if (colors[i].radius < h.radius/4.f - 1.f/256.f) {
            skip_index[colors[i].index]=1;
            (*skipped)++;
        }
    }
    return h;
}

static colormap *get_subset_palette(const colormap *map)
{
    // it may happen that it gets palette without subset palette or the subset is too large
    int subset_size = (map->colors+3)/4;

    if (map->subset_palette && map->subset_palette->colors <= subset_size) {
        return map->subset_palette;
    }

    const colormap *source = map->subset_palette ? map->subset_palette : map;
    colormap *subset_palette = pam_colormap(subset_size);

    for(unsigned int i=0; i < subset_size; i++) {
        subset_palette->palette[i] = source->palette[i];
    }

    return subset_palette;
}