Fast Smoothing Algorithm

Discussion in 'Supercard SDK' started by BassAceGold, Mar 26, 2012.

Mar 26, 2012

Fast Smoothing Algorithm by BassAceGold at 7:38 AM (3,137 Views / 1 Likes) 2 replies

  1. BassAceGold
    OP

    Member BassAceGold Testicles

    Joined:
    Aug 14, 2006
    Messages:
    494
    Country:
    Canada
    While working on my new menu, I needed someway of improving the image quality of downscaled images. The easiest way for reducing the pixeling that occurs in downscaling is pixel smoothing, or averaging. However this can require a lot of power and end up being really slow if one decides to implement such feature the easy way i.e. unpacking color channels, averaging, then repacking.

    I initially had implemented the easy method to my library and was appalled at the drastic performance hit. At 396mhz, I could not stream mp3, and redraw the album cover at full speed with the smoothing enabled. This new algorithm, is drastically faster, almost to the point where it's performance hit is negligible on the lowest CPU speed (60mhz), at least in comparison to looping through all the pixels to draw an image.

    Here is an image to illustrate the results:

    Far right, image with no smoothing: full speed on lowest CPU speed
    Far left, image with easy smoothing solution, lags on 396mhz cpu speed
    Middle image, new smoothing function, full speed on 60mhz cpu speed
    [​IMG]

    Now for the code! It is relatively easy to add to any project:

    Code:
    typedef struct SmoothPixel{
    u16 *buf;//pointer to image buffer
    int x, y, wd, ht;//pixel you are drawing X, Y, image width, height
    char corners;//set to non-zero for 8 pixel averaging, or 0 for 4 pixels
    }SmoothPixel;
    
    //these will average 15 bit colors, without unpacking
    //method found from http://www.slack.net/~ant/info/rgb_mixing.html
    #define PIXAVG_R5G5B5(a,b) ((a + b + ((a ^ b) & 0x0421)) >> 1)
    //this is used for weighting the corner pixel averages
    #define PIXAVG_R5G5B5_HALF(a,b) ((a + b + ((a ^ b) & 0x0421)) >> 2)
    
    //only one branch statement used, could be split into two functions if necessary (one for 4 pixel avg, 8 pixel avg)
    u16 BAG_Effects_PixSmoothing(const SmoothPixel *smooth){
    register int curColor[9];
    register int  x = smooth->x, y = smooth->y, wd = smooth->wd, ht = smooth->ht;
    
    //center pixel
    curColor[0] = smooth->buf[x + y * wd];
    //left pixel
    x--;
    x += (x < 0);
    curColor[1] = smooth->buf[x + y * wd];
    //right pixel
    x+=2;
    x -= (x > wd);
    curColor[2] = smooth->buf[x + y * wd];
    //reset x to main pix
    x--;
    //up pixel
    y--;
    y += (y < 0);
    curColor[3] = smooth->buf[x + y * wd];
    //down pixel
    y+=2;
    y -= (y > ht);
    curColor[4] = smooth->buf[x + y * wd];
    if(smooth->corners){
    //reset pos to center pixel
    y--;
    //left corners
    x--;
    x += (x < 0);
    //left top
    y--;
    y += (y < 0);
    curColor[5] = smooth->buf[x + y * wd];  
    //left bottom
    y+=2;
    y -= (y > ht);
    curColor[6] = smooth->buf[x + y * wd];
    //right corners
    x+=2;
    x -= (x > wd);
    //right bottom
    curColor[7] = smooth->buf[x + y * wd];
    //right yop
    y-=2;
    y += (y < 0);
    curColor[8] = smooth->buf[x + y * wd];
    //8 pixel average(lol)
    return PIXAVG_R5G5B5(curColor[0], PIXAVG_R5G5B5(curColor[1], PIXAVG_R5G5B5(curColor[2], PIXAVG_R5G5B5(curColor[3],
    //last normal pixel.......now the corner pixels
    PIXAVG_R5G5B5(curColor[4], PIXAVG_R5G5B5_HALF(curColor[5], PIXAVG_R5G5B5_HALF(curColor[6],
    PIXAVG_R5G5B5_HALF(curColor[7], curColor[8]))))))));
    }
    //4 pixel average
    return PIXAVG_R5G5B5(curColor[0], PIXAVG_R5G5B5(curColor[1], PIXAVG_R5G5B5(curColor[2], PIXAVG_R5G5B5(curColor[3], curColor[4]))));
    }
    
    And that is all there is too it. Hopefully this becomes of use to others as it has been for me.

    PS. I have tried applying it to NDSSFC emulator, but the performance hit of looping through each pixel is too high to bother adding this smoothing functionality to.
     
    Margen67 likes this.
  2. Terminator02

    Member Terminator02 ヽ( 。 ヮ゚)ノ

    Joined:
    Apr 10, 2010
    Messages:
    4,517
    Location:
    Somewhere near monkat
    Country:
    United States
    I think you mixed up the far left from the far right in your description of the image, but great work, can't wait for your new menu :P
     
    1 person likes this.
  3. BassAceGold
    OP

    Member BassAceGold Testicles

    Joined:
    Aug 14, 2006
    Messages:
    494
    Country:
    Canada
    Damn, I was positive that I double checked that too. I should stop posting things so early in the morning.
     

Share This Page