コード例 #1
0
ファイル: mediancut.cpp プロジェクト: beru/marred-pngquant
/** finds median in unsorted set by sorting only minimum required */
static
f_pixel get_median(const box* b, hist_item achv[])
{
	const uint median_start = (b->colors-1)/2;

	hist_item_sort_range(&(achv[b->ind]), b->colors,
					median_start,
					b->colors&1 ? 1 : 2);

	if (b->colors&1) return achv[b->ind + median_start].acolor;
	return averagepixels(2, &achv[b->ind + median_start], 1.0);
}
コード例 #2
0
ファイル: mediancut.c プロジェクト: AviTapp/pngquant
/** finds median in unsorted set by sorting only minimum required */
static f_pixel get_median(const struct box *b, hist_item achv[])
{
    const unsigned int median_start = (b->colors-1)/2;

    hist_item_sort_range(&(achv[b->ind]), b->colors,
                         median_start);

    if (b->colors&1) return achv[b->ind + median_start].acolor;

    // technically the second color is not guaranteed to be sorted correctly
    // but most of the time it is good enough to be useful
    return averagepixels(2, &achv[b->ind + median_start], 1.0, (f_pixel){0.5,0.5,0.5,0.5});
}
コード例 #3
0
void repixels(int dt_change, int do_change, int width, int height, long bmpSize, unsigned char* data)
{
	long i = 0;
	averagepixels(bmpSize, data);
	binarization(bmpSize, data);

	unsigned char* fake	   = (unsigned char*)malloc(sizeof(unsigned char) *  width * height);
	unsigned char* dt_data = (unsigned char*)malloc(sizeof(unsigned char) *  width * height);
	unsigned char* do_data = (unsigned char*)malloc(sizeof(unsigned char) *  width * height);

	singlizeimage(width, height, fake, data);
	filledges(width, height, fake);

	memcpy(dt_data, fake, sizeof(unsigned char) * width * height);
	memcpy(do_data, fake, sizeof(unsigned char) * width * height);

	for(i = 0; i <= dt_change; i++)
	{
		changepixels(DT_CHANGE_WHITE, width, height, bmpSize, dt_data);
	}
	changepixels(DO_CHANGE_WHITE, width, height, bmpSize, dt_data);

	for(i = 0; i <= do_change; i++)
	{
		changepixels(DO_CHANGE_WHITE, width, height, bmpSize, do_data);
	}

#ifdef DEBUG_OUTPUT
	writeToFile(2, width, height, dt_data, PROCESS_BOOL_SAVE_PATH1);
	writeToFile(2, width, height, do_data, PROCESS_BOOL_SAVE_PATH2);
#endif

	mergeimages(width, height, dt_data, do_data, fake);

	for(i = 0; i < REMOVE_LONELY_PIXEL; i++)
	{
		removelonelypixel(width, height, fake);
	}

	recoverimage(width, height, fake, data);	

	free(fake);
	free(dt_data);
	free(do_data);
}
コード例 #4
0
ファイル: mediancut.c プロジェクト: AviTapp/pngquant
/*
 ** Here is the fun part, the median-cut colormap generator.  This is based
 ** on Paul Heckbert's paper, "Color Image Quantization for Frame Buffer
 ** Display," SIGGRAPH 1982 Proceedings, page 297.
 */
LIQ_PRIVATE colormap *mediancut(histogram *hist, const float min_opaque_val, unsigned int newcolors, const double target_mse, const double max_mse)
{
    hist_item *achv = hist->achv;
    struct box bv[newcolors];

    /*
     ** Set up the initial box.
     */
    bv[0].ind = 0;
    bv[0].colors = hist->size;
    bv[0].color = averagepixels(bv[0].colors, &achv[bv[0].ind], min_opaque_val, (f_pixel){0.5,0.5,0.5,0.5});
    bv[0].variance = box_variance(achv, &bv[0]);
    bv[0].max_error = box_max_error(achv, &bv[0]);
    bv[0].sum = 0;
    bv[0].total_error = -1;
    for(unsigned int i=0; i < bv[0].colors; i++) bv[0].sum += achv[i].adjusted_weight;

    unsigned int boxes = 1;

    // remember smaller palette for fast searching
    colormap *representative_subset = NULL;
    unsigned int subset_size = ceilf(powf(newcolors,0.7f));

    /*
     ** Main loop: split boxes until we have enough.
     */
    while (boxes < newcolors) {

        if (boxes == subset_size) {
            representative_subset = colormap_from_boxes(bv, boxes, achv);
        }

        // first splits boxes that exceed quality limit (to have colors for things like odd green pixel),
        // later raises the limit to allow large smooth areas/gradients get colors.
        const double current_max_mse = max_mse + (boxes/(double)newcolors)*16.0*max_mse;
        const int bi = best_splittable_box(bv, boxes, current_max_mse);
        if (bi < 0)
            break;        /* ran out of colors! */

        unsigned int indx = bv[bi].ind;
        unsigned int clrs = bv[bi].colors;

        /*
         Classic implementation tries to get even number of colors or pixels in each subdivision.

         Here, instead of popularity I use (sqrt(popularity)*variance) metric.
         Each subdivision balances number of pixels (popular colors) and low variance -
         boxes can be large if they have similar colors. Later boxes with high variance
         will be more likely to be split.

         Median used as expected value gives much better results than mean.
         */

        const double halfvar = prepare_sort(&bv[bi], achv);
        double lowervar=0;

        // hist_item_sort_halfvar sorts and sums lowervar at the same time
        // returns item to break at …minus one, which does smell like an off-by-one error.
        hist_item *break_p = hist_item_sort_halfvar(&achv[indx], clrs, &lowervar, halfvar);
        unsigned int break_at = MIN(clrs-1, break_p - &achv[indx] + 1);

        /*
         ** Split the box.
         */
        double sm = bv[bi].sum;
        double lowersum = 0;
        for(unsigned int i=0; i < break_at; i++) lowersum += achv[indx + i].adjusted_weight;

        const f_pixel previous_center = bv[bi].color;
        bv[bi].colors = break_at;
        bv[bi].sum = lowersum;
        bv[bi].color = averagepixels(bv[bi].colors, &achv[bv[bi].ind], min_opaque_val, previous_center);
        bv[bi].total_error = -1;
        bv[bi].variance = box_variance(achv, &bv[bi]);
        bv[bi].max_error = box_max_error(achv, &bv[bi]);
        bv[boxes].ind = indx + break_at;
        bv[boxes].colors = clrs - break_at;
        bv[boxes].sum = sm - lowersum;
        bv[boxes].color = averagepixels(bv[boxes].colors, &achv[bv[boxes].ind], min_opaque_val, previous_center);
        bv[boxes].total_error = -1;
        bv[boxes].variance = box_variance(achv, &bv[boxes]);
        bv[boxes].max_error = box_max_error(achv, &bv[boxes]);

        ++boxes;

        if (total_box_error_below_target(target_mse, bv, boxes, hist)) {
            break;
        }
    }

    colormap *map = colormap_from_boxes(bv, boxes, achv);
    map->subset_palette = representative_subset;
    adjust_histogram(achv, map, bv, boxes);

    return map;
}
コード例 #5
0
ファイル: mediancut.cpp プロジェクト: beru/marred-pngquant
/*
 ** Here is the fun part, the median-cut colormap generator.  This is based
 ** on Paul Heckbert's paper, "Color Image Quantization for Frame Buffer
 ** Display," SIGGRAPH 1982 Proceedings, page 297.
 */
colormap* mediancut(histogram* hist, const double min_opaque_val, uint newcolors, const double target_mse)
{
	hist_item* achv = hist->achv;
	box* bv = new box[newcolors];

	/*
	 ** Set up the initial box.
	 */
	bv[0].ind = 0;
	bv[0].colors = hist->size;
	bv[0].color = averagepixels(bv[0].colors, &achv[bv[0].ind], min_opaque_val);
	bv[0].variance = box_variance(achv, &bv[0]);
	bv[0].sum = 0;
	bv[0].total_error = -1;
	for (uint i=0; i<bv[0].colors; i++) {
		bv[0].sum += achv[i].adjusted_weight;
	}
	
	uint boxes = 1;
	
	// remember smaller palette for fast searching
	colormap* representative_subset = NULL;
	uint subset_size = ceil(pow(newcolors,0.7));
	
	/*
	 ** Main loop: split boxes until we have enough.
	 */
	while (boxes < newcolors) {
		
		if (boxes == subset_size) {
			representative_subset = colormap_from_boxes(bv, boxes, achv, min_opaque_val);
		}
		
		int bi= best_splittable_box(bv, boxes);
		if (bi < 0)
			break;		  /* ran out of colors! */
		
		box& bx = bv[bi];
		uint indx = bx.ind;
		uint clrs = bx.colors;
		
		/*
		 Classic implementation tries to get even number of colors or pixels in each subdivision.

		 Here, instead of popularity I use (sqrt(popularity)*variance) metric.
		 Each subdivision balances number of pixels (popular colors) and low variance -
		 boxes can be large if they have similar colors. Later boxes with high variance
		 will be more likely to be split.

		 Median used as expected value gives much better results than mean.
		 */
		
		const double halfvar = prepare_sort(&bx, achv);
		double lowervar=0;
		
		// hist_item_sort_halfvar sorts and sums lowervar at the same time
		// returns item to break at ??minus one, which does smell like an off-by-one error.
		hist_item* break_p = hist_item_sort_halfvar(&achv[indx], clrs, &lowervar, halfvar);
		uint break_at = min<uint>(clrs-1, break_p - &achv[indx] + 1);
		
		/*
		 ** Split the box.
		 */
		double sm = bx.sum;
		double lowersum = 0;
		for (uint i=0; i<break_at; i++) {
			lowersum += achv[indx + i].adjusted_weight;
		}

		bx.colors = break_at;
		bx.sum = lowersum;
		bx.color = averagepixels(bx.colors, &achv[bx.ind], min_opaque_val);
		bx.total_error = -1;
		bx.variance = box_variance(achv, &bx);
		box& bx2 = bv[boxes];
		bx2.ind = indx + break_at;
		bx2.colors = clrs - break_at;
		bx2.sum = sm - lowersum;
		bx2.color = averagepixels(bx2.colors, &achv[bx2.ind], min_opaque_val);
		bx2.total_error = -1;
		bx2.variance = box_variance(achv, &bx2);
		
		++boxes;

		if (total_box_error_below_target(target_mse, bv, boxes, hist)) {
			break;
		}
	}

	colormap* map = colormap_from_boxes(bv, boxes, achv, min_opaque_val);
	map->subset_palette = representative_subset;
	adjust_histogram(achv, map, bv, boxes);
	delete bv;
	return map;
}