Example #1
0
/**
 * Simple octree color quantization: Similar to http://rosettacode.org/wiki/Color_quantization#C
 */
void octreeColorQuantize(const RGBAImage& image, size_t max_colors,
		std::vector<RGBAPixel>& colors, Octree** octree) {
	assert(max_colors > 0);

	// have an octree with the colors as leaves
	Octree* internal_octree = new Octree();
	// and a priority queue of leaves to be processed
	// the order of leaves is very important, see NodeComparator
	std::priority_queue<Octree*, std::vector<Octree*>, NodeComparator> queue;

	// insert the colors into the octree
	for (int x = 0; x < image.getWidth(); x++) {
		for (int y = 0; y < image.getHeight(); y++) {
			RGBAPixel color = image.pixel(x, y);
			Octree* node = Octree::findOrCreateNode(internal_octree, color);
			node->setColor(color);
			// add the leaf only once to the queue
			if (node->getCount() == 1)
				queue.push(node);
		}
	}

	// now: reduce the leaves until we have less colors than maximum
	while (queue.size() > max_colors) {
		Octree* node = queue.top();
		assert(node->isLeaf());
		queue.pop();
		
		// add the color value of the leaf to the parent
		node->reduceToParent();
		Octree* parent = node->getParent();
		// delete the leaf (leaf is automatically removed from parent in reduceToParent())
		delete node;

		// add parent to queue if it is a leaf now
		if (parent->isLeaf())
			queue.push(parent);
	}

	// gather the quantized colors
	while (queue.size()) {
		Octree* node = queue.top();
		assert(node->isLeaf());
		node->setColorID(colors.size());
		colors.push_back(node->getColor());
		queue.pop();
	}

	if (octree != nullptr)
		*octree = internal_octree;
	else
		delete internal_octree;
}
void testOctreeWithImage(const RGBAImage& image) {
	std::set<RGBAPixel> colors;
	int r = 0, g = 0, b = 0, count = 0;

	Octree octree;

	// insert all pixels into an octree
	for (int x = 0; x < image.getWidth(); x++) {
		for (int y = 0; y < image.getHeight(); y++) {
			RGBAPixel color = image.getPixel(x, y);
			colors.insert(color);
			r += rgba_red(color);
			g += rgba_green(color);
			b += rgba_blue(color);
			count++;

			Octree::findOrCreateNode(&octree, color)->setColor(color);
		}
	}

	// make sure that all colors are inserted correctly
	BOOST_CHECK(octree.isRoot() && !octree.isLeaf());
	BOOST_CHECK(!octree.hasColor());

	// reduce all colors up to the root of the tree
	// the color should be the overall average color
	traverseReduceOctree(&octree);
	BOOST_CHECK(octree.hasColor());

	RGBAPixel average1 = octree.getColor();
	RGBAPixel average2 = rgba(r / count, g / count, b / count, 255);
	BOOST_CHECK_EQUAL(average1, average2);

	BOOST_TEST_MESSAGE("Overall colors: " << colors.size());
	BOOST_TEST_MESSAGE("Pixels per color: " << (double) (image.getWidth() * image.getHeight()) / colors.size());
	BOOST_TEST_MESSAGE("Average color: " << (int) rgba_red(average1) << ","
			<< (int) rgba_green(average1) << "," << (int) rgba_blue(average1));
}
Example #3
0
void CaveRendermode::draw(RGBAImage& image, const mc::BlockPos& pos,
		uint16_t id, uint16_t data) {
	// a nice color gradient to see something
	// (because the whole map is just full of cave stuff,
	// one can't differentiate the single caves)

	double h1 = (double) (64 - pos.y) / 64;
	if (pos.y > 64)
		h1 = 0;

	double h2 = 0;
	if (pos.y >= 64 && pos.y < 96)
		h2 = (double) (96 - pos.y) / 32;
	else if (pos.y > 16 && pos.y < 64)
		h2 = (double) (pos.y - 16) / 48;

	double h3 = 0;
	if (pos.y > 64)
		h3 = (double) (pos.y - 64) / 64;
	
	int R = h1 * 128.0 + 128.0;
	int G = h2 * 255.0;
	int B = h3 * 255.0;
	
	int Y = (R*3+G*10+B)/14; //get luminance of recolor
	
	// We try to do luminance-neutral additive/subtractive color instead of alpha blending, for better contrast
	// So first subtract luminance from each component.
	R = (R-Y)/3; // /3 is similar to alpha=85
	G = (G-Y)/3;
	B = (B-Y)/3;
	
	int size = image.getWidth();
	for (int y = 0; y < size; y++)
		for (int x = 0; x < size; x++) {
			uint32_t pixel = image.getPixel(x, y);
			if (pixel != 0) {				
				image.setPixel(x,y, rgba_add_clamp(pixel, R, G, B));
			}
		}
}