I have been working to get most high saturation and bright colors. For that I have below command and the C program to get same result.
convert one.jpg -alpha off -scale '50x50!' -depth 8 \
'(' -clone 0 -colorspace HSB -channel gb -separate +channel -threshold 50% -compose multiply -composite ')'\
-alpha off -compose copy_opacity -composite sparse-color:-|\
convert -size 50x50 xc: -sparse-color voronoi @- +dither -colors 6 -depth 8 -format %c histogram:info:
There are two commands executed so I divided and make it separately. Then I wrote the output of first command into text file and read that text file in second command. Please look at below two command.
/*First Part*/
convert one.jpg -alpha off -scale '50x50!' -depth 8 '(' -clone 0 -colorspace HSB -channel gb -separate +channel -threshold 50% -compose multiply -composite ')' -alpha off -compose copy_opacity -composite sparse-color:-test.txt
/*Second Part*/
convert -size 50x50 xc: -sparse-color voronoi @-test.txt +dither -colors 6 -depth 8 -format %c histogram:info:
Using this I got the same output. Below is my C program to achieve the same. In the code the first part has been covered. But the results I got from first convert command and C code are not same. I don't understand what I missed.
#include "MagickWand/studio.h"
#include "MagickWand/MagickWand.h"
void dominantSix(){
/* convert one.jpg -alpha off -scale '50x50!'\
-depth 8 '(' -clone 0 -colorspace HSB -channel gb -separate +channel -threshold 50% -compose multiply -composite ')'\
-alpha off -compose copy_opacity -composite sparse-color:-test.txt */
MagickWand * wand, * wand0, * wand1;
PixelIterator * iteration;
PixelWand ** row;
PixelInfo pixel;
size_t x, y, row_width;
wand = NewMagickWand();
MagickReadImage(wand, "car.jpg");
MagickSetImageAlphaChannel(wand, OffAlphaChannel);
MagickScaleImage(wand, 50, 50);
MagickSetImageDepth(wand,8);
wand0 = CloneMagickWand(wand);
wand1 = CloneMagickWand(wand);
MagickTransformImageColorspace(wand0, HSBColorspace);
MagickSetImageChannelMask(wand0, GreenChannel);
MagickSeparateImage(wand0, GreenChannel);
MagickThresholdImage(wand0, QuantumRange*50/100);
MagickTransformImageColorspace(wand1, HSBColorspace);
MagickSetImageChannelMask(wand1, BlueChannel);
MagickSeparateImage(wand1, BlueChannel);
MagickThresholdImage(wand1, QuantumRange*50/100);
MagickCompositeImage(wand0, wand1, MultiplyCompositeOp, MagickFalse, 0, 0);
wand1 = DestroyMagickWand(wand1);
MagickSetImageAlphaChannel(wand, OffAlphaChannel);
MagickCompositeImage(wand, wand0, CopyAlphaCompositeOp, MagickFalse, 0, 0);
wand0 = DestroyMagickWand(wand0);
size_t height = MagickGetImageHeight(wand);
size_t width = MagickGetImageWidth(wand);
iteration = NewPixelIterator(wand);
FILE *fptr;
fptr = fopen("program.txt", "w");
for (y = 0; y < height; ++ y)
{
row = PixelGetNextIteratorRow(iteration, &row_width);
for (x = 0; x < row_width; ++x)
{
PixelGetMagickColor(row[x], &pixel);
size_t red = pixel.red*255/QuantumRange;
size_t green = pixel.green*255/QuantumRange;
size_t blue = pixel.blue*255/QuantumRange;
char color[30];
sprintf(color, "%zu%s%zu%s%s%zu%s%zu%s%zu%s%s", x, ",", y, ",", "srgb(", red, ",", green, ",", blue, ",", "1) ");
fprintf(fptr,"%s", color);
}
PixelSyncIterator(iteration);
}
fclose(fptr);
PixelSyncIterator(iteration);
iteration = DestroyPixelIterator(iteration);
wand = DestroyMagickWand(wand);
MagickWandTerminus();
}
int main(int argc, char const *argv[]) {
dominantSix();
return 0;
}
Below is the source Image and the links of two text files one is from CLI and other from C.
program.txt
stepIf you're already writing c, you may be able to skip the sparse-color extraction, and apply the colors directly to MagickSparseColorImage
// ... Omitting first half of function ...
MagickSetImageAlphaChannel(wand, OffAlphaChannel);
MagickCompositeImage(wand, wand0, CopyAlphaCompositeOp, MagickFalse, 0, 0);
wand0 = DestroyMagickWand(wand0);
size_t height = MagickGetImageHeight(wand);
size_t width = MagickGetImageWidth(wand);
size_t spares_index = 0;
// Allocated enough memory to hold Sparse Color data
double * sparse_args = malloc(sizeof(double) * height * width * 5);
// Iterate over pixel data
iteration = NewPixelIterator(wand);
for (y = 0; y < height; ++ y)
{
row = PixelGetNextIteratorRow(iteration, &row_width);
for (x = 0; x < row_width; ++x)
{
PixelGetMagickColor(row[x], &pixel);
// Append coord + color data if pixel is visible.
if (pixel.alpha == QuantumRange) {
sparse_args[spares_index++] = (double)x;
sparse_args[spares_index++] = (double)y;
sparse_args[spares_index++] = pixel.red / QuantumRange;
sparse_args[spares_index++] = pixel.green / QuantumRange;
sparse_args[spares_index++] = pixel.blue / QuantumRange;
}
}
}
iteration = DestroyPixelIterator(iteration);
wand = DestroyMagickWand(wand);
// Generate new image to apply spares-color data
MagickWand * final;
final = NewMagickWand();
MagickSetSize(final, 50, 50);
MagickReadImage(final, "xc:");
MagickSparseColorImage(final, VoronoiColorInterpolate, spares_index, sparse_args);
MagickQuantizeImage(final, 6, RGBColorspace, 0, NoDitherMethod, MagickFalse);
// Generate Histogram
size_t histogram_size = 0;
PixelWand ** colors = MagickGetImageHistogram(final, &histogram_size);
for (int index = 0; index < histogram_size; ++index) {
PixelWand * color = colors[index];
size_t color_count = PixelGetColorCount(color);
if (color_count) {
char * color_name = PixelGetColorAsString(color);
printf("%s => %lu\n", color_name, color_count);
free(color_name);
}
}
// Clean-up
free(sparse_args);
colors = DestroyPixelWands(colors, histogram_size);
final = DestroyMagickWand(final);
Hard to tell where/what you need help with. But to generate the program.txt
data, you should be able to leverage the SPARES-COLOR:
protocol.
// ...
MagickSetImageAlphaChannel(wand, OffAlphaChannel);
MagickCompositeImage(wand, wand0, CopyAlphaCompositeOp, MagickFalse, 0, 0);
wand0 = DestroyMagickWand(wand0);
// Set image format to sparse protocol
MagickSetImageFormat(wand, "SPARSE-COLOR");
// Extract format data to buffer.
size_t blob_length = 0;
unsigned char * blob = MagickGetImageBlob(wand, &blob_length);
// Write buffer to file
FILE * fptr;
fptr = fopen("program.txt", "w");
fwrite(blob, sizeof(unsigned char), blob_length, fptr);
fclose(fptr);
free(blob);
wand = DestroyMagickWand(wand);
MagickWandTerminus();
Or even simpler
// ...
MagickSetImageAlphaChannel(wand, OffAlphaChannel);
MagickCompositeImage(wand, wand0, CopyAlphaCompositeOp, MagickFalse, 0, 0);
wand0 = DestroyMagickWand(wand0);
// Write sparse program
MagickWriteImage(wand, "SPARSE-COLOR:program.txt");
wand = DestroyMagickWand(wand);
MagickWandTerminus();