How to posterize an image?

How can I posterize an image with ImageJ? I guess I can do it with lookup tables but don’t know how.

Good day,

you simply have to reduce the number of gray-levels. With color images a solution appears more involved.

You may have a look at the macro function:

“changeValues(v1, v2, v3)
Changes pixels in the image or selection that have a value in the range v1-v2 to v3. For example, changeValues(0,5,5) changes all pixels less than 5 to 5, and changeValues(0x0000ff,0x0000ff,0xff0000) changes all blue pixels in an RGB image to red.”

I guess it’s not for scientific purposes?

Best

Herbie

1 Like

Dear Herbie,

I am already familiar with the algorithm. Just wonder if there is any convenient way to do that in ImageJ.

You didn’t mention that you know about a solution and sorry for proposing something evident.

I think a few lines of macro code aren’t really inconvenient. But of course this may be matter of taste…

Good day

Herbie

Dear Herbie,

I didn’t notice that your answer was only this line:

changeValues(v1, v2, v3)

Thank you. I tested it and it works :slightly_smiling:
Just out of curiosity, is it possible to posterize images using lookup tables too?

For achromatic images I see no problems. Why don’t you try?

Best

Herbie

In addition to using changeValues(v1, v2, v3) as suggested by @anon96376101, you can convert any RGB image into a posterized image with a given number of colours by changing it to an 8-bit Color type (Image > Type > 8-bit Color). The following macro illustrates this:

run("Clown (14K)");
run("8-bit Color", "number=12");

Have a look at the resulting LUT with Image > Color > Show LUT.

3 Likes

Unfortunately, I cannot seem to produce the following posterization. I want to posterize the following image:

As what can be done in the GIMP:

Any advice would be greatly appreciated!

Two weeks ago you wrote:

“Thank you. I tested it and it works”

Great!

Best

Herbie

I say it again. I tested changeValues(v1, v2, v3) and it worked. I just cannot reproduce the same effect as what I can do with GIMP.

Would this be good enough?

Don’t have time for fine-tuning.

HTH

Herbie

Thank you. I would prefer to have the same result as in GIMP though. Could you please share your script?

Hey guys @iarganda @ctrueden @bnorthan @hinerm @rimadoma

I’ve implemented the 2-level posterize algorithm used in GIMP as an ImageJ macro and it works:

for( i=0;i<getWidth();i++){
	for(j=0;j<getHeight();j++){
		v = getPixel(i, j);
		red = (v>>16)&0xff;  // extract red byte (bits 23-17)
		green = (v>>8)&0xff; // extract green byte (bits 15-8)
		blue = v&0xff;       // extract blue byte (bits 7-0)
		if (red < 128) 
			red = 0;
		else
			red = 255;
		if (green < 128) 
			green = 0;
		else
			green = 255;
		if (blue < 128) 
			blue = 0;
		else
			blue = 255;
		setPixel(i, j, red << 16 | green << 8 | blue);
	}
}

Do you know if it is possible to do the above with less code?
Thanks :slightly_smiling:

Your image is a 4-level image as the one I’ve posted.

You may color it to your liking by applying a LUT.

As mentioned several times, I simply use the appropriate values for the function
changeValues(v1, v2, v3);

But evidently, you’ve already found a solution that, however produces a result that differs much more from what you’ve posted as your preferred result than mine … (I think false-color is not a real issue here.)

Best

Herbie

Well, since the code does the same thing to each color component, you could write

function posterizeColor(color) {
    return color >= 128 ? 255 : 0;
}

and then call it red = posterizeColor(red); etc.

I don’t know why, but the following code is not producing the same result as my original code, could you please test it and see if your results differ too?

function posterizeColor(color) {
    return color >= 128 ? 255 : 0;
}

open("/home/meysam/cropped.jpg");
for( i=0;i<getWidth();i++){
	for(j=0;j<getHeight();j++){
		v = getPixel(i, j);
		red = (v>>16)&0xff;  // extract red byte (bits 23-17)
		green = (v>>8)&0xff; // extract green byte (bits 15-8)
		blue = v&0xff;       // extract blue byte (bits 7-0)
		red = posterizeColor(red);
		green = posterizeColor(green);
		blue = posterizeColor(blue);
		setPixel(i, j, red << 16 | green << 8 | blue);
	}
}

Dear @anon96376101
Here is what I am getting when I run my script:

You are right. At first glance I thought I am getting exactly the same result as GIMP’s output, but now that I look more closely, it seems to be somehow different. Could you please share the script you’ve used with changeValues(v1, v2, v3)? I think the problem with changeValues(v1, v2, v3) is that it changes the value of a pixel as a whole, and cannot separately manipulate its R, G & B channels. Please correct me if I am wrong.

At least one problem with your result is that it only shows three levels instead of four. But since it is your approach, it is up to you to make it behave as desired …

Another problem that I see, is that you assume that the colors in the result image are colors that are taken from the original. I don’t think that this is true. My impression is that of a false color image which implies (but I may be wrong) that the result image is basically achromatic. That said, I see no problem with changeValues(v1, v2, v3), although I think that it can be used for color posterization as well.

HTH

Herbie

Here is some code that may help:

setBatchMode( true );
img = getTitle();
imgR = img + " (red)";
imgG = img + " (green)";
imgB = img + " (blue)";
run("Split Channels");
chgVals();
selectImage( imgG );
chgVals();
selectImage( imgR );
chgVals();
run( "Merge Channels...", "c1=["+imgR+"] c2=["+imgG+"] c3=["+imgB+"]" );
setBatchMode( false );
exit();

function chgVals( ) {
    changeValues( 0, 127, 0);
    changeValues( 128, 255, 255);
}

HTH

Herbie

2 Likes

That’s great! Much obliged! :smile: