Jump to content

Posterization filter algorithm

Recommended Posts

I'm working on automatic graphics processing utility which performs batch-actions on a bunch of image-files, and i wonder how input values from Posterize-effect in PaintNET could be used.

So i have a standard posterization algorithm in my program:

byteRed = IntToByte( Round( byteRed / posterizeValRed ) * posterizeValRed );
byteGreen= IntToByte( Round( byteGreen / posterizeValGreen ) * posterizeValGreen );
byteBlue = IntToByte( Round( byteBlue / posterizeValBlue ) * posterizeValBlue );
byteAlpha = IntToByte( Round( byteAlpha / posterizeValAlpha ) * posterizeValAlpha );

But input values for posterization effect (a number from 2 to 64) in PaintNET are very confusing. So the question is - how can i interpret them to use in my utility?

EDIT: or maybe somebody knows the algorithm which used in PaintNET so i can change my implementation of it accordingly...

P.S. Not sure if i made post in appropriate section of this forum. I'm sorry if not.

Edited by Markus13
Link to comment
Share on other sites

Well, after some additional tests today it's clear that it's not a matter of input values - seems that posterization in PaintNET also tweaks saturation/contrast/brightness in some way. So it's obviously a different algorithm. And i'll appreciate if somebody will provide information about it.

Edited by Markus13
Link to comment
Share on other sites

@toe_head2001, thanks for pointing out older sources of PaintNET. After digging it i found that the actual algorithm of posterization uses some kind of pre-generated palette.
So the whole process done in two steps:
first there should be formed palettes for each level (Red, Green, Blue), depending on input values of the filter:

redLevels = CalcLevels( posterizeValRed );
greenLevels = CalcLevels( posterizeValGreen );
blueLevels = CalcLevels( posterizeValBlue );
function CalcLevels( inputVal ){ // inputVal is int[2..64]
    var t1 = new Array( inputVal ); // array of byte
    var i; // byte
    for (i = 0; i < inputVal; i++){
        t1[i] = IntToByte( Round( (255 * i) / (inputVal - 1) ) );
    var levels = new Array( 256 ); // array of byte
    var j = 0; // byte
    var k = 0; // int16
    for(i = 0; i <= 255; i++){
        levels[i] = t1[j];
        k += inputVal;
        if( k > 255 ){
            k -= 255;
    return levels;

and in the second step we should perform next operation on each pixel of image:

function PixelOperation( srcColor ){
    var byteRed = getRvalue( srcColor ); // byte
    var byteGreen = getGvalue( srcColor ); // byte
    var byteBlue = getBvalue( srcColor ); // byte
    var byteAlpha = getAvalue( srcColor ); // byte
    byteRed = redLevels[byteRed];
    byteGreen = greenLevels[byteGreen];
    byteBlue = blueLevels[byteBlue];
    //byteAlpha = alphaLevels[byteAlpha]; // we can do the same for alpha if we need to
    return RGBA( byteRed, byteGreen, byteBlue, byteAlpha );

By the way, if we will implement this algorithm in some compiling language (i used JavaScript just to demonstrate the approach) - it will be much faster than standard approach, cuz with this method there will be only 3 (4 with alpha) writing instructions for each pixel. So the overall posterization-application time will be like 2-3 times faster (or even more, depending on image-size) comparing to standard posterization algorithm, which has floating-point calculations for each color-byte of each pixel.

Edited by Markus13
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...