How to resolve the algorithm Color quantization step by step in the C programming language
How to resolve the algorithm Color quantization step by step in the C programming language
Table of Contents
Problem Statement
Color quantization is the process of reducing number of colors used in an image while trying to maintain the visual appearance of the original image. In general, it is a form of cluster analysis, if each RGB color value is considered as a coordinate triple in the 3D colorspace. There are some well know algorithms [1], each with its own advantages and drawbacks. Task: Take an RGB color image and reduce its colors to some smaller number (< 256). For this task, use the frog as input and reduce colors to 16, and output the resulting colors. The chosen colors should be adaptive to the input image, meaning you should not use a fixed palette such as Web colors or Windows system palette. Dithering is not required. Note: the funny color bar on top of the frog image is intentional.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Color quantization step by step in the C programming language
This C code implements the palette quantization algorithm known as Octree Quantization.
It takes an image represented as an array of pixels and a target number of colors as input, and outputs a reduced color palette that closely approximates the original image while reducing its file size by decreasing the number of colors used.
Here is a summary of the code:
- Octree Node:
- The
oct_node_t
struct represents an octree node. - Each node stores the sum of colors, count of pixels, and other metadata.
- Octree nodes are organized into an eight-way tree structure.
- The
- Heap Operations:
- The code uses a binary heap to store Octree nodes, maintaining them in a specific order based on their properties.
- The
cmp_node
function defines the comparison criteria for the heap.
- Tree Construction and Color Insertion:
- The
node_insert
function inserts a color triple into the Octree. - It traverses the tree based on the pixel's color values, creating nodes as needed.
- Each node accumulates the color information of pixels in its subtree.
- The
- Tree Folding:
- The
node_fold
function removes leaf nodes from the Octree. - It combines their color information with their parent node and updates the parent's count and child list.
- The
- Color Replacement:
- The
color_replace
function traverses the Octree based on the pixel's color values. - For each pixel, it replaces its color with the color stored in the corresponding Octree node.
- The
- Palette Quantization:
- The
color_quant
function builds an Octree from the image and maintains a heap of leaf nodes. - It iteratively folds the first node in the heap (the one with the least significant color information) into its parent and adds the parent to the heap.
- This process continues until the desired number of colors is reached.
- Finally, the code assigns the average color of each leaf node as the quantized color and replaces the original pixel colors with these quantized colors.
- The
Overall, this code provides an efficient and effective method for reducing the number of colors in an image while preserving its visual quality.
Source code in the c programming language
typedef struct oct_node_t oct_node_t, *oct_node;
struct oct_node_t{
/* sum of all colors represented by this node. 64 bit in case of HUGE image */
uint64_t r, g, b;
int count, heap_idx;
oct_node kids[8], parent;
unsigned char n_kids, kid_idx, flags, depth;
};
/* cmp function that decides the ordering in the heap. This is how we determine
which octree node to fold next, the heart of the algorithm. */
inline int cmp_node(oct_node a, oct_node b)
{
if (a->n_kids < b->n_kids) return -1;
if (a->n_kids > b->n_kids) return 1;
int ac = a->count * (1 + a->kid_idx) >> a->depth;
int bc = b->count * (1 + b->kid_idx) >> b->depth;
return ac < bc ? -1 : ac > bc;
}
/* adding a color triple to octree */
oct_node node_insert(oct_node root, unsigned char *pix)
{
# define OCT_DEPTH 8
/* 8: number of significant bits used for tree. It's probably good enough
for most images to use a value of 5. This affects how many nodes eventually
end up in the tree and heap, thus smaller values helps with both speed
and memory. */
unsigned char i, bit, depth = 0;
for (bit = 1 << 7; ++depth < OCT_DEPTH; bit >>= 1) {
i = !!(pix[1] & bit) * 4 + !!(pix[0] & bit) * 2 + !!(pix[2] & bit);
if (!root->kids[i])
root->kids[i] = node_new(i, depth, root);
root = root->kids[i];
}
root->r += pix[0];
root->g += pix[1];
root->b += pix[2];
root->count++;
return root;
}
/* remove a node in octree and add its count and colors to parent node. */
oct_node node_fold(oct_node p)
{
if (p->n_kids) abort();
oct_node q = p->parent;
q->count += p->count;
q->r += p->r;
q->g += p->g;
q->b += p->b;
q->n_kids --;
q->kids[p->kid_idx] = 0;
return q;
}
/* traverse the octree just like construction, but this time we replace the pixel
color with color stored in the tree node */
void color_replace(oct_node root, unsigned char *pix)
{
unsigned char i, bit;
for (bit = 1 << 7; bit; bit >>= 1) {
i = !!(pix[1] & bit) * 4 + !!(pix[0] & bit) * 2 + !!(pix[2] & bit);
if (!root->kids[i]) break;
root = root->kids[i];
}
pix[0] = root->r;
pix[1] = root->g;
pix[2] = root->b;
}
/* Building an octree and keep leaf nodes in a bin heap. Afterwards remove first node
in heap and fold it into its parent node (which may now be added to heap), until heap
contains required number of colors. */
void color_quant(image im, int n_colors)
{
int i;
unsigned char *pix = im->pix;
node_heap heap = { 0, 0, 0 };
oct_node root = node_new(0, 0, 0), got;
for (i = 0; i < im->w * im->h; i++, pix += 3)
heap_add(&heap, node_insert(root, pix));
while (heap.n > n_colors + 1)
heap_add(&heap, node_fold(pop_heap(&heap)));
double c;
for (i = 1; i < heap.n; i++) {
got = heap.buf[i];
c = got->count;
got->r = got->r / c + .5;
got->g = got->g / c + .5;
got->b = got->b / c + .5;
printf("%2d | %3llu %3llu %3llu (%d pixels)\n",
i, got->r, got->g, got->b, got->count);
}
for (i = 0, pix = im->pix; i < im->w * im->h; i++, pix += 3)
color_replace(root, pix);
node_free();
free(heap.buf);
}
You may also check:How to resolve the algorithm Find if a point is within a triangle step by step in the Dart programming language
You may also check:How to resolve the algorithm Roman numerals/Decode step by step in the Fortran programming language
You may also check:How to resolve the algorithm Arena storage pool step by step in the PARI/GP programming language
You may also check:How to resolve the algorithm Ackermann function step by step in the M4 programming language
You may also check:How to resolve the algorithm Element-wise operations step by step in the jq programming language