Explaning Image downsample

Started by
24 comments, last by Khatharr 11 years, 1 month ago

Hi All,

I tried to figure out the meaning of that function, I couldn't, even tried on paper, but didn't get it. Would someone explain that to me smile.png ? If that's possible with Ascii text or some images would be so much appreciated.


static void inline resizeRow(uint32_t *dst, uint32_t *src, uint32_t pixelsPerRow)

{
        uint8_t * pSrc8 = (uint8_t *)src;
        uint8_t * pDest8 = (uint8_t *)dst;
        int stride = pixelsPerRow * sizeof(uint32_t);
        int x;
        int r, g, b, a;


        for (x=0; x<pixelsPerRow; x++)
        {
                r = pSrc8[0] + pSrc8[4] + pSrc8[stride+0] + pSrc8[stride+4];
                g = pSrc8[1] + pSrc8[5] + pSrc8[stride+1] + pSrc8[stride+5];
                b = pSrc8[2] + pSrc8[6] + pSrc8[stride+2] + pSrc8[stride+6];
                a = pSrc8[3] + pSrc8[7] + pSrc8[stride+3] + pSrc8[stride+7];
                pDest8[0] = (uint8_t)((r + 2)/4); // average with rounding
                pDest8[1] = (uint8_t)((g + 2)/4);
                pDest8[2] = (uint8_t)((b + 2)/4);
                pDest8[3] = (uint8_t)((a + 2)/4);
                pSrc8 += 8; // skip forward 2 source pixels
                pDest8 += 4; // skip forward 1 destination pixel
        }
}
 
Advertisement

It's halving the size of 2 rows of the source image by adding together the r, g, b and a components of each 4x4 pixel square in the 2 rows of the source image, adding 0.5 to each value as well (so adding 2 to the total), then dividing by 4, to get the destination colour.

Looks like the for loop should go to pixelsPerRow - 1 though, otherwise it will read pixels off the right hand side on the last iteration.

Presumably the function is called in a loop for every other row of the source image.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley
Downsampling is basically just taking an image at a higher resolution and redrawing it at a lower resolution.

For example, suppose I have a 10x10 pixel image, and downsample it to 5x5. There are a number of ways to do this. First, I could simply skip every other pixel:

Source image: 0 1 2 3 4 5 6 7 8 9

Destination image: 0 2 4 6 8

And then I skip a row, and repeat this process on the next row.

This is going to make things look a little bad, though. A better approach is to average the pixels:

Source image:

A B
C D

Destination pixel at 0,0 is A+B+C+D / 4
It looks like your code is doing the second method.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I think the loop should probably go from 0 to pixelsPerRow / 2 or else x should increment by 2 every iteration...

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

Thanks for your answer, I have made an imaginary bitmap, so I got 4*4 pixels assuming 1 Pixel is 3 bytes RGB, and I added them, but how come from two rows I get 4*4 pixels?

Would someone please show me some pics smile.png ?

Regarding also those lines:


                pDest8[0] = (uint8_t)((r + 2)/4); // average with rounding
                pDest8[1] = (uint8_t)((g + 2)/4);
                pDest8[2] = (uint8_t)((b + 2)/4);
                pDest8[3] = (uint8_t)((a + 2)/4);
                pSrc8 += 8; // skip forward 2 source pixels
                pDest8 += 4; // skip forward 1 destination pixel
 

He skipped 4 bytes, but at the second iteration he writes again at 0,1,2,3 at the dest, should be 4,5,6,7 ?

That's because it's a pointer not an array... if you do

pSrc[offset] that's just shorthand for *(pSrc + offset) but you add 4 to pSrc each iteration so if you have

char myCharArray[10000] = { some data };

char* pSrc = myCharArray;

pSrc[0] = 10;

pSrc += 4;

pSrc[0] = 11;

that's the same as writing 10 to myCharArray[0] and 11 to myCharArray[4].

EDIT: Oops, mixed up order of pSrc and pBase in first attempt.

EDIT2: Changed pBase into myCharArray... easier to understand...

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

@Paradimg Shift,

Thanks for your explanation, you know what I have worked a lot in C,C++, and I never know that info!! I'm gonna review pointers now..

If its ok for you, would you please just draw a simple bitmap to get the algorithm ?

I would like also to modify it so that it works for any scale, not just by two.

I'm terrible at drawing ;)

It's not easy to make it work for scales other than a simple division of the width either... you need to use a different way of weighting the pixel values since the sample points you take aren't centred on the pixels of the source image. Best to use a graphics library to do the downsizing for you (if you need to do it at runtime) or if you just need to resize a lot of images once use an image filtering program (or something like photoshop).

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

I have used opencv function cv::resize and it is slow on ARM... that's why I wanna write my own, and convert it to ARM Neon...

What is meant by stride + 0 , stride + 1 ?

This topic is closed to new replies.

Advertisement