fast 2x image scaling algorithm

Started by
10 comments, last by samgzman 20 years, 3 months ago
does anyone know of any super fast image scaling algorithm? I am simply trying to scale a set of grayscal data by a 2x. 32x32 -> 64x64. I dont really care if blurring occurs..in fact it would actually be beneficial in my case. Any help would be awsome.
Advertisement
Blurring will slow things down. It''s usually a desired effect.

Since it''s greyscale, can we assume your data is 8 bits per pixel?

There is no really fast way that I know of to do this, aside from copying row by row, col by col.

That said, you can reduce the amount of overhead by doing something like this:

srcPtr = pointer to first Pixel In Image;
dstRowPtrA = pointer to first pixel in destination;
char color;
for ( y = 0; x < imageHeight; y++)
{
for ( x = 0; x < imageWidth; x++)
{
color = *srcPtr;
*dstRowPtrA = color;
*(dstRowPtrA + width of scaled image in bytes) = color;

dstRowPtrA ++;
srcPtr++;
}

// Skip a row //
dstRowPtrA += size of scaled image in bytes
}

Cheers,
Will
------------------http://www.nentari.com
One way would be to use your favourite graphics API(opengl or Directx). Create a texture of your object, and render a quad to a render texture of the desired target size. If you want blurring you can look at the many filtering options for textures that are available.
Loop through each pixel in the source image and make 4 pixels at a time in the destination image. To add blurring, you can use simple bilinear filtering. Imagine you drag out the source image to its final size (x2) and there are holes around every pixel. Interpolate between the existing pixels to fill the holes and you got your blurred image.
the code u posted RPGeezus didnt make much sense to me in following it logically, but it did it anyhow and here is what i got

this is the original image at 32x32:
<img src="http://invis.free.anonymizer.com/http://zurph.tripod.com/good.jpg"> and then final using ur code at 64x64:
<img src="http://invis.free.anonymizer.com/http://zurph.tripod.com/bad.jpg">

My code as it is:
	m_ucTest1 = new unsigned char[32*32];m_ucTest2 = new unsigned char[64*64];// m_ucTest1 is filled hereunsigned char* srcPtr  = &m_ucTest1[0];unsigned char* dstRowPtrA  = &m_ucTest2[0];	unsigned char color;for (int y = 0; y < 32; y++){     for (int x = 0; x < 32; x++)     {          color = *srcPtr;          *dstRowPtrA = color;          *(dstRowPtrA + 64) = color;          dstRowPtrA++;          srcPtr++;     }     dstRowPtrA += 64;} 
Whoops!







[edited by - samgzman on January 6, 2004 6:12:57 PM]
You need to change this:

*dstRowPtrA = color;
*(dstRowPtrA + 64) = color;

to this:

int i;
for(i=0;i<64;i++)
*(dstRowPtrA+i)=color;

then in the y part of the loop you need to increase by screen width, not image width.
here, use mine one - this code also draws the scaled image on a Win32 HWND/DC, via setpixel to check the result (setpixel is very slow!not realtime suitable! change this line, if needed)
it scales on both directions to arbitrary sizes, even overscaling is supported.

void ScaleRGBImageF( int posX, int posY, int sizeX, int sizeY, unsigned char *imagedata, HWND hWnd, int newSizeX, int newSizeY ){HDC tempDC = GetDC( hWnd );long lBytePos = 0;float xScaleFactor = 0.0f;float yScaleFactor = 0.0f;long  sx = 0; // set counter xlong  sy = 0; // set counter yfloat curXPos = 0.0f;float curYPos = 0.0f;long  srcBytePos = 0;long  dstBytePos = 0;    xScaleFactor = (float)sizeX / (float)newSizeX;    yScaleFactor = (float)sizeY / (float)newSizeY;    // pixel loop    for( sy=0; sy    {        for( sx=0; sx        {             srcBytePos = (((int)curYPos*sizeX)+(int)curXPos)*3;            dstBytePos = ((sy*newSizeX)+sx)*3;            SetPixel( tempDC, sx+posX, sy+posY, RGB( imagedata[srcBytePos], imagedata[srcBytePos+1], imagedata[srcBytePos+2]) );            curXPos += xScaleFactor;        }        curXPos = 0.0f;        curYPos += yScaleFactor;    }}  

int posX, int posY = position where to draw on screen, in pixels
int sizeX, int sizeY = original size, in pixels
unsigned char *imagedata = pointer to RGB imagedata
HWND hWnd = the Win32 HWND for drawing
int newSizeX, int newSizeY = bew scaled size, in pixels



DJSnow
---
this post is manually created and therefore legally valid without a signature

[edited by - DJSnow on January 6, 2004 9:19:37 PM]
DJSnow---this post is manually created and therefore legally valid without a signature
The best way I found was to create two arrays of scaled offsets, and translate them into the bitmap and onto the screen...

BYTE* pImage = LoadImage("image.bmp");BYTE* pScreen = GetScreen();int iXOffsets[64];int iYOffsets[64];int loop = 0;// look-up tablesfloat fScaleX = 64 / 0.5f;float fScaleY = 64 / 0.5f;for (loop = 0; loop < 64; loop++){    iXOffsets[loop] = loop * fXScale; // optimize this        iYOffsets[loop] = loop * fYScale * 64; // optimize this}// use look-up tables to render imagefor (int iy = 0, int iy2 = 0; iy < 64; iy++, iy2+=SCREEN_WIDTH){    for (int ix = 0; ix < 64; ix++)    {       // WARNING: the offsets may off the edge of the image =+GPF        pScreen[ix + iy2] = pImage[iXOffsets[ix] + iYOffsets[iy]];    }} 


.. something like that.

R





optionalreaction.net
"I will, even if I try, always be second; and because of that, I know nothing is a lesson." - me
Hmm, I''d just do something like
BYTE px1, px2, *src = img, *srcRowEnd, *srcColEnd = img + 32 * 32;DWORD *dest = destImg, pxOut;while(src < srcColEnd){   srcRowEnd = src + 32;   while(src < srcRowEnd)   {      px1 = *src++;      px2 = *src++;      pxOut = px1 | (px1 << 8) | (px2 << 16) | (px2 << 24);      dest[16] = pxOut; //next row (16*4 bytes)      *dest++ = pxOut; //current row, and increment   }   dest += 16;} 

That''s about as fast as I can get it. It goes along reading 2 pixels at a time, and then making a temp variable that has both of those pixels scaled to 2x, and then writes that temp to the current dest pos, and to one row down, to scale 2x in the Y direction too. Then of course you have to skip over that second line you were writing to before moving onto the next line, so you don''t write over it.
That will just make each pixel into 4 pixels of the same color though, no filtering, though that wouldn''t be too hard to add, just a little slower. You could use shifts to do your averaging though, since it''s to exactly 2x. So just take like px1, ((px1+px2)/2, px2 and ((px2+px3)/2 for the first 4 pixels of the first dest row, then do the next source row like that, which woudl be 2 rows down on the dest image, and then average between those 2 sets of pixels for the middle row, and repeat.

This topic is closed to new replies.

Advertisement