fast 2x image scaling algorithm
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.
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
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
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:
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;}
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.
*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.
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]
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]
The best way I found was to create two arrays of scaled offsets, and translate them into the bitmap and onto the screen...
.. something like that.
R
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
Hmm, I''d just do something like
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.
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
Popular Topics
Advertisement