BobTheCoolGuy
3754 posts
|

[Man scaled at 400% by setting scaleX and scaleY to 4]
|
|
|
BobTheCoolGuy
3754 posts
|
Your challenge is to create a class that extends BitmapData or a method that scales BitmapData objects to a larger size. Here’s an example function prototype:
public static scaleBitmapData(data:BitmapData, newHeight:int, newWidth:int):BitmapData
The overall goal is to write a method that will scale a BitmapData in a way that it looks better than simply adjusting scaleX and scaleY. You may not use built in methods for scaling. Speed is also important to consider, but is not the main objective.
This isn’t a contest really, but just a challenge for fun. Even if you don’t think you can make a good algorithm, you can still give it a whirl and try to make an algorithm that sort of works, even if the quality is horrible.
Get the original guy image here
|
|
|
qwerberberber
508 posts
|
public static function scaleBitmap(_b,_w,_h):BitmapData
{
var ret:BitmapData = new BitmapData(_w,_h);
var v1:Vector<UInt> = _b.getVector(_b.rect);
var v2:Vector<UInt> = new Vector<UInt>(_w*_h);
var i:Int = _h;
while(i-->0)
{
var j:Int = _w;
while(j-->0)
{
v2[i*_w+j] = v1[Std.int(i/_b.height)*_b.width+Std.int(j/_b.width)];
}
}
ret.setVector(ret.rect,v2);
return ret;
}
expect a lot of syntax errors wrote in browser.
|
|
|
BobTheCoolGuy
3754 posts
|
Here’s probably the most basic method. It’s almost identical to qwerber’s, just less efficient. And it also fixes some bugs in his.
Spoiler Warning:
public static function scaleBitmapData(data:BitmapData, newHeight:int, newWidth:int):BitmapData
{
var b:BitmapData = new BitmapData(newWidth, newHeight, false, 0xFFFFFF);
for (var j:int = 0; j < b.width; ++j)
{
for (var k:int = 0; k < b.height; ++k)
{
b.setPixel(j, k, data.getPixel(int(j * data.width / newWidth), int(k * data.height / newHeight)));
}
}
return b;
}
Here’s the result:

Looks pretty darn familiar huh?
Also:

|
|
|
Senekis93
4090 posts
|
Not an entry, but I guess i’ll drop this here for anyone looking for a way to do this.
If you’re ok with a fixed zoom of 2x, 3x or 4x, you can easily port hqnx, which works wonders.
Don’t have the time to do it right now (busy and GiTD rush), but the algorithm is quite simple. I’ll make an AS3 port of it if I have some free time after the GiTD deadline.

|
|
|
MoonlaughMaster
6660 posts
|
I’m guessing hq4x is what those online vectorizing programs use … or at least something similar.
|
|
|
BobTheCoolGuy
3754 posts
|
Originally posted by Senekis93:
Not an entry, but I guess i’ll drop this here for anyone looking for a way to do this.
If you’re ok with a fixed zoom of 2x, 3x or 4x, you can easily port hqnx, which works wonders.
Don’t have the time to do it right now (busy and GiTD rush), but the algorithm is quite simple. I’ll make an AS3 port of it if I have some free time after the GiTD deadline.
Yep, no hurry. Of course, it’s more fun if you come up with the methods yourself, but that hqx method looks pretty spiffy.
|
|
|
lobstershow
1096 posts
|
hq4x doesn’t seem to understand dithering.
|
|
|
Draco18s
6860 posts
|
Personally I’m a fan of Content Aware Image Resizing
Originally posted by lobstershow:
hq4x doesn’t seem to understand dithering.
No. It specifically does not.
Also, I wrote a 2x scaler that has similar properties to the HQX method, although it requires certain assumptions about the input data.
|
|
|
jonathanasdf
3910 posts
|
quick! someone implement Lanczos in flash! OH WAIT, IT’S ALREADY BEEN DONE :O http://blog.yoz.sk/2010/11/lanczos-resampling-with-actionscript/
though, hqnx looks amazing :O
|
|
|
BobTheCoolGuy
3754 posts
|
Another one I wrote in a few minutes. Obviously using getPixel and setPixel is not the fastest for performance, etc. Basically it looks at the pixels on each side of itself and uses the color between them.
public static function scaleBD2(data:BitmapData, newHeight:int, newWidth:int):BitmapData
{
var b:BitmapData = new BitmapData(newWidth, newHeight, false, 0xFFFFFF);
for (var j:int = 0; j < b.width; ++j)
{
for (var k:int = 0; k < b.height; ++k)
{
var xn:Number = j * data.width / newWidth;
var yn:Number = k * data.height / newHeight;
var x:int = int(xn);
var y:int = int(yn);
var x2:int = (x + 1 == b.width?x:x + 1);
var y2:int = (y + 1 == b.height?y:y + 1);
b.setPixel(j, k, averageColors(averageColors(data.getPixel(x, y),data.getPixel(x2, y), 1 - (xn - x), (xn - x)), averageColors(data.getPixel(x, y2),data.getPixel(x2, y2), 1 - (xn - x), (xn - x)), 1 - (yn - y), yn - y));
}
}
return b;
}
public static function averageColors(c1:uint, c2:uint, w1:Number, w2:Number):uint
{
return ((((((c1 >> 16) & 0xff)*w1 + ((c2 >> 16) & 0xff)*w2) / (w1+w2))<<16)|(((((c1 >> 8) & 0xff)*w1 + ((c2 >> 8) & 0xff)*w2) / (w1+w2))<<8)| (((c1 & 0xff)*w1 + (c2 & 0xff)*w2) / (w1+w2)));
}
Result:

and

|
|
|
jonathanasdf
3910 posts
|
Originally posted by Draco18s:
Personally I’m a fan of Content Aware Image Resizing
oh what the hell did I just see… wow
|
|
|
Senekis93
4090 posts
|
Originally posted by jonathanasdf:
Originally posted by Draco18s:
Personally I’m a fan of Content Aware Image Resizing
oh what the hell did I just see… wow
Indeed. That’s amazing.
@Bob: Nice improvement. Way better than your first try. (:
|
|
|
BobTheCoolGuy
3754 posts
|
Originally posted by Senekis93:
Originally posted by jonathanasdf:
Originally posted by Draco18s:
Personally I’m a fan of Content Aware Image Resizing
oh what the hell did I just see… wow
Indeed. That’s amazing.
@Bob: Nice improvement. Way better than your first try. (:
That is amazing.
And Senekis, thanks, I plan on going for something more complicated sometime too. What’s also interesting to see is how different algorithms work better in different situations. Of the two I posted, I think I’d actually take the first algorithm for the yoshi image, as it preserves the sharpness of the image, but for the man, I’d take the second algorithm no doubt.
|
|
|
truefire
3011 posts
|
Holy wow that is awesome.
|
|
|
Draco18s
6860 posts
|
Originally posted by jonathanasdf:
though, hqnx looks amazing :O
It’s just a look-up table, truth be told. It looks at the pixel and it’s 8 neighbors, and performs a threshold test to see which pixels are close in color to the test pixel, then based on the 256 possible results of similar/not-similar, it outputs 4 new pixels.
|
|
|
Senekis93
4090 posts
|
Originally posted by Draco18s:
Originally posted by jonathanasdf:
though, hqnx looks amazing :O
It’s just a look-up table, truth be told. It looks at the pixel and it’s 8 neighbors, and performs a threshold test to see which pixels are close in color to the test pixel, then based on the 256 possible results of similar/not-similar, it outputs 4 new pixels.
Indeed. The lut takes a bunch of space, and it’s meant to be used in very specific aplications; mostly pixel art games where graphics are reused with different sizes (like the “huge” worlds of old Mario games); having the table allows to resize a lot of stuff at run time.
|
|
|
Draco18s
6860 posts
|
Originally posted by Senekis93:
Indeed. The lut takes a bunch of space, and it’s meant to be used in very specific aplications; mostly pixel art games where graphics are reused with different sizes (like the “huge” worlds of old Mario games); having the table allows to resize a lot of stuff at run time.
My algorithm does something similar, but it doesn’t use raw bitmap data. It uses a skeleton vector information that contains a few key pieces of information, such as which pixels are the ship’s exterior (the black bits), interior (the color bits), or background space (along with other pixel types, such as windshield, thrust jets, etc). It then uses math on the exterior bits to scale them up such that strait lines are preserved, as well as continuity (which causes curves to be preserved as well, interestingly).
The interior is filled in after it’s scaled up.
|