API equivalent of 'convert -format %c histogram:info'?

The MagickWand interface is a new high-level C API interface to ImageMagick core methods. We discourage the use of the core methods and encourage the use of this API instead. Post MagickWand questions, bug reports, and suggestions to this forum.
Post Reply
jgalyan
Posts: 3
Joined: 2011-12-03T23:50:09-07:00
Authentication code: 8675308

API equivalent of 'convert -format %c histogram:info'?

Post by jgalyan » 2011-12-04T00:03:13-07:00

I thought this would be easy, but I've been wracking my brain over this for about 12 hours now, as it's the last piece of the program I'm working on, and I just cannot get the API to write a histogram in the format that 'convert -format %c histogram:info' does. All I can get MagickWriteImage to do is either write a single line describing the image, or a list of every pixel in the image and its RGBA values.

So, how can I use the API to generate output like this?
69871: ( 0, 0, 0, 0) #00000000 none
1: ( 18, 18, 18,255) #121212 grey7
1: ( 23, 23, 23,255) #171717 grey9
2: ( 26, 26, 26,255) #1A1A1A grey10
1: ( 33, 33, 33,255) #212121 grey13
5: ( 46, 46, 46,255) #2E2E2E grey18
7: ( 51, 51, 51,255) #333333 grey20
4: ( 54, 54, 54,255) #363636 grey21
2: ( 56, 56, 56,255) #383838 grey22
5: ( 61, 61, 61,255) #3D3D3D grey24

Code:

Code: Select all

      // outputFilePath is of the form "/foo/bar/baz/123456789_color_distribution.txt"
      outputPathChars = (*env)->GetStringUTFChars(env, outputFilePath, JNI_FALSE);
      finalOutputPath = malloc(snprintf(NULL, 0, "%s%s", "histogram:info:", outputPathChars) + 1);
      sprintf(finalOutputPath, "%s%s", "histogram:info:", outputPathChars);
      MagickSetImageDepth(wand, 8);
      printf("Attempting to write histogram text file to %s\n", finalOutputPath);
      MagickSetImageFormat(wand, "%c");
      status = MagickWriteImage(wand, finalOutputPath);
I've also tried:

Code: Select all

      outputPathChars = (*env)->GetStringUTFChars(env, outputFilePath, JNI_FALSE);
      finalOutputPath = malloc(snprintf(NULL, 0, "%s", outputPathChars) + 1);
      sprintf(finalOutputPath, "%s", outputPathChars);
      MagickSetImageDepth(wand, 8);
      printf("Attempting to write histogram text file to %s\n", finalOutputPath);
      MagickSetImageFormat(wand, "%c histogram:info");
      status = MagickWriteImage(wand, finalOutputPath);
Then I tried MagickGetImageHistogram, and while I can iterate over the PixelWand array, I haven't figured out how to get valid RGB values out of them, nor does there seem to be any way to get the color names.

I'm sure I'm missing something that should be really obvious, but it's probably just too obvious for me to see it.

el_supremo
Posts: 1015
Joined: 2005-03-21T21:16:57-07:00

Re: API equivalent of 'convert -format %c histogram:info'?

Post by el_supremo » 2011-12-04T12:48:46-07:00

This code might get you started.

Code: Select all

#include <windows.h>
#include <wand/magick_wand.h>
int sort_hist(PixelWand **p,PixelWand **q)
{
	size_t ip,iq;
	ip = PixelGetColorCount(*p);
	iq = PixelGetColorCount(*q);
	if(ip > iq)return(1);
	if(ip < iq)return(-1);
	return(0);

}
void test_wand(void)
{
	MagickWand *mw = NULL;
// Comment out this define to use the region iterator instead of the Draw
//#define USE_DRAW
	PixelWand **pixels = NULL;
	size_t i,num_colours;
	char *pc;
	FILE *fo = NULL;

	MagickWandGenesis();

	/* Create a wand */
	mw = NewMagickWand();

	/* Read the input image */
	MagickReadImage(mw,"logo:");
	fo = fopen("logo.txt","w");
	pixels = MagickGetImageHistogram(mw,&num_colours);
if(1) {
	// Optionally sort them into ascending order of frequency
	qsort(pixels,num_colours,sizeof(PixelWand *),sort_hist);
}
	for(i=0;i<num_colours;i++) {
		fprintf(fo,"%6d: (",PixelGetColorCount(pixels[i]));
		fprintf(fo,"%d, ",PixelGetRedQuantum(pixels[i]));
		fprintf(fo,"%d, ",PixelGetGreenQuantum(pixels[i]));
		fprintf(fo,"%d, ",PixelGetBlueQuantum(pixels[i]));
		fprintf(fo,"%d)",PixelGetAlphaQuantum(pixels[i]));
if(1) {
		pc = PixelGetColorAsString(pixels[i]);
		fprintf(fo," %s",pc);
		// Must destroy the string once it is no longer required
		DestroyString(pc);
}
		fprintf(fo,"\n");
	}

	fclose(fo);
	// Free up the PixelWand array
	RelinquishMagickMemory(pixels);
	if(mw) mw = DestroyMagickWand(mw);

	MagickWandTerminus();
}
As far as I can see, the colour name is obtained with a call to the MagickCore function QueryColorname and there's no equivalent call in the MagickWand API.

@magick:
There's one oddity in the histogram that the program below produces. PixelGetColorAsString prints all the colours as rgb percent values - except one!
Here's the last four entries of the sorted output:

Code: Select all

  2942: (65535, 0, 0, 65535) rgb(100%,0%,0%)
  7150: (1028, 1799, 1799, 65535) rgb(4,7,7)
 12466: (8738, 15934, 37522, 65535) rgb(13.3333%,24.3137%,57.2549%)
256244: (65535, 65535, 65535, 65535) rgb(100%,100%,100%)
Note the one with count 7150 has rgb(4,7,7) rather than percentage values. It seems to have been treated as if it was a Q8 colour rather than Q16.

Pete
Sorry, my ISP shutdown all personal webspace so my MagickWand Examples in C is offline.
See my message in this topic for a link to a zip of all the files.

jgalyan
Posts: 3
Joined: 2011-12-03T23:50:09-07:00
Authentication code: 8675308

Re: API equivalent of 'convert -format %c histogram:info'?

Post by jgalyan » 2011-12-04T16:01:54-07:00

Pete -

That gets me close, thanks a bunch!

Jeff

User avatar
anthony
Posts: 8883
Joined: 2004-05-31T19:27:03-07:00
Authentication code: 8675308
Location: Brisbane, Australia

Re: API equivalent of 'convert -format %c histogram:info'?

Post by anthony » 2012-02-02T23:51:54-07:00

That specific rgb() value is because the color matched the color expansion of a simpler 8-bit color value.
EG #ABCDEF 8-bit expanded to #ABABCDCDEFEF as a 16-bit equivalent color.

Actually you could also get a 'named color' if the pixel color is a perfect match. However all named colors are defined from 8-bit color values, so they are a sub-set of the 8-bit value sub-set you found! Still it is relatively easy to get the named colors for pure 'white' and 'black', and the other primary and secondary colors.

Simplest way out is to use the color values directly! But then you need to deal with QuantumRange of the IM you are using!
Anthony Thyssen -- Webmaster for ImageMagick Example Pages
https://imagemagick.org/Usage/

Post Reply