|
| | Er zijn 116 gasten en 6 MSX vrienden online
Je bent een anonieme bezoeker.
|
| |
Schrijver
| Screenshot smoothening
| [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 22 Juni 2004, 23:29   | Quote:
| PECL stands for PHP Extension Community Library, those are (precompiled) extensions for the PHP-engine.
|
Ah, so I'd better use the PECL version instead?
Quote:
| IMO those images look too blurry after resizing w/ antialiasing... whatever
1. How do you scale your image? Which algo did you use?
2. How is the code for scaling built up? Would you mind posting the main part here? Perhaps there are some optimizations left. Because scaling a whole image taking > 1 min sounds a bit odd...
|
Yes, the algorythm is too basic to discuss, really
1. I don't scale the image. I just took them right from NLMSX (pressing F9 for the screenshot-procedure, ey?  )
2. Erm... one moment please  (variable names are mostly in Dutch  . The only thing you need to know is that everything beginning letter (r, g, b, for example $rood, $groen and $blauw) stand for red, green and blue intensities, respectively  . Now, If you'd allow me...
<?php
/**
* anti alias an image
* BASIC algorythm by [D-'minus'-Tail] :P
*/
function anti_alias($image) {
$im=imagecreatetruecolor(imagesx($image), imagesy($image));
for ($y=0; $y<imagesy($image); $y+=1) {
for ($x=0; $x<imagesx($image); $x+=1) {
$sc[0]=imagecolorat($image, $x-1, $y);
$sc[1]=imagecolorat($image, $x+1, $y);
$sc[2]=imagecolorat($image, $x, $y-1);
$sc[3]=imagecolorat($image, $x, $y+1);
$sc[4]=imagecolorat($image, $x-1, $y-1);
$sc[5]=imagecolorat($image, $x-1, $y+1);
$sc[6]=imagecolorat($image, $x+1, $y-1);
$sc[7]=imagecolorat($image, $x+1, $y+1);
for ($c=0; $c<8; $c++) {
$r[$c]=$sc[$c] >> 16 & 0xFF;
$g[$c]=$sc[$c] >> 8 & 0xFF;
$b[$c]=$sc[$c] & 0xFF;
}
$rood=$groen=$blauw=0;
for ($c=0; $c<8; $c++) {
$rood+=$r[$c];
$groen+=$g[$c];
$blauw+=$b[$c];
}
for ($c=0; $c<4; $c++) {
$rood+=$r[$c];
$groen+=$g[$c];
$blauw+=$b[$c];
}
$rood/=12;
$groen/=12;
$blauw/=12;
/**
* The following lines are for brightness control.
* Uncommment them if you think the output's too dark.
*/
/*$rood+=12;
$groen+=12;
$blauw+=12;
if ($rood>255)
$rood=255;
if ($groen>255)
$groen=255;
if ($blauw>255)
$blauw=255;*/
$blend_color=imagecolorallocate($image, $rood, $groen, $blauw);
imagesetpixel($im, $x, $y, $blend_color);
}
}
return $im;
}
As you can see, it takes a resource type variable for input, and produces a new one (beginning from imagecreatetruecolor()), which is returned in the very end. The upper scripts will take care for proper display on HTML pages.
Of course, except for stripping the white lines (of which I don't think it will matter), there's a lot of optimization to do, for I really * hacked* it...
Plus, I do some illegal actions, e.g. getting pixels outside of the image's borders. But I doubt that will give the tremendous speed issue. As you can see now, the script is really hacked into another  | | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 22 Juni 2004, 23:38   | Now, the "algorythm" described in words:
FOR ALL PIXELS(x,y) {
1 Let's estimate the color of the pixel in the new image at position x,y. Therefore:
2 we need the colors of the surrounding pixels in the original picture. Those pixels are located at:
- x, y-1
- x+1, y-1
- x+1, y
- x+1, y+1
- x, y+1
- x-1, y+1
- x-1, y
- x-1, y-1
3 We obtain the color of each of those pixels
4 The pixels directly (e.g. not diagonal) adjacent to the to-be-estimated-pixel weigh heavier than the diagonal-adjacent pixels (say, 2 times).
5 This makes up for a total of 2+2+2+2+1+1+1+1 = 12 R, G and B intensities.
6 Finally, we calculate the average, and assign a blend color.
7 A pixel with color==blend color is set at x,y in the new picture.
}
Fin.
[edit]The algorythm is too simple for putting it into words, but the results are quite nice, and the execution time should be amazingly fast...  [/edit] | | Sousuke msx freak Berichten: 154 | Geplaatst: 23 Juni 2004, 00:25   | Quote:
| variable names are mostly in Dutch
|
Don't worry about that, I can speak/read dutch, so it's no problem for me  Besides, it should be clear when reading the code
Bout the algo: I don't know how GD works, but is there a way to get/set a whole image line? Perhaps the bottleneck is the imagecolorat-call.
I suppose that function calculates the location of the specified pixel and then reads it, and that would take *much* time. Additionally (nearly) every pixel is read 8 times. 
So try reading lines, process them, then put back the new line. Should be much much faster that way 
(Think someone mentioned this before  )
Oh and just one small speed up:
You are creating a 24bit-image, so this function $blend_color=imagecolorallocate($image, $rood, $groen, $blauw); is not necessary. Simply write $blend_color=$rood & 0xFF << 0x10 | $groen & 0xFF << 0x08 | $blauw & 0xFF;
Hope it works
[edit] Quote:
| Ah, so I'd better use the PECL version instead?
|
Well those are addons or plug-ins for your PHP4. Dunno what extra modules you need 
Have a look here in their database pecl.php.net[/edit] | | mth msx freak Berichten: 189 | Geplaatst: 23 Juni 2004, 01:51   | I'm not familiar with PHP or its libs, but it seems strange that you call imagecolorallocate on the source image ($image) instead of the target image ($im).
Also, I'm surprised you take the weighted average of all neighbouring pixels, but ignore the colour of the centre pixel. You could try to add it with a weight of 4 and then divide by 16 instead of 12. That won't make things faster, but the output will become a bit sharper.
Vampier once made a SCREEN8 to PNG/BMP (I forgot) converter in PHP, it was fast enough to use for realtime conversions. So PHP as a language should be fast enough for image conversion algorithms. Probably one of the operations you're using is much slower than expected.
Try to disable parts of your code and see what the impact on performance is. For example, ignore the input completely and write RGB=(x mod 256, y mod 256, 0) to the output image. Try to fetch only 4 neighbours instead of 8. Try to duplicate the for-loops that add to rood/groen/blauw and divide by 24, see if it becomes twice as slow or doesn't change a lot in performance. Generally, just play a bit with the different parts of the code to get a feeling for where most CPU time is spent.
A completely different solution would be to use a drawing program to apply the algorithm. Most of them have pre-cooked blur filters, as well as the ability to create your own filter. For example, in the GIMP you can use the option Filters -> Generic -> Convolution Matrix. Paint Shop Pro also has an option to create your own filter. The matrix for your filter looks like this:
0 0 0 0 0
0 1 2 1 0
0 2 0 2 0
0 1 2 1 0
0 0 0 0 0
with divisor=12 and offset=0.
(Doing the conversion in PHP certainly has a cool factor, but since you'll have to cut out the interesting bits of the screenshot in an image editor anyway, one extra step shouldn't be a real annoyance.)
| | Sousuke msx freak Berichten: 154 | Geplaatst: 23 Juni 2004, 03:00   | Quote:
| Try to disable parts of your code and see what the impact on performance is.
|
I've played a bit w/ the GD-library. And as I already supposed, the (multiple) imagecolorat-calls are the main slowdown of the smoothener.
I my new algo reads line for line and processes them, instead of reading pixel for pixel. Of course the code has become a bit larger and more complex, but it doesn't take so long anymore (and my PHP-engine doesn't complain about too long execution times  )
Hopy that there are no fatal mistakes in the code, and you can read/understand/use the code
function anti_alias2($image)
{
// avoid function calls :)
$iw=imagesx($image);
$ih=imagesy($image);
// create new image
$im=imagecreatetruecolor($iw, $ih);
// initialize line buffers
$l1r=array_fill(0,$iw-1,0); $l2r=array_fill(0,$iw-1,0); $l3r=array_fill(0,$iw-1,0);
$l1g=array_fill(0,$iw-1,0); $l2g=array_fill(0,$iw-1,0); $l3g=array_fill(0,$iw-1,0);
$l1b=array_fill(0,$iw-1,0); $l2b=array_fill(0,$iw-1,0); $l3b=array_fill(0,$iw-1,0);
// read first line
for ($x=0; $x<$iw; $x++) {
$pixel = imagecolorat($image, $x, 0);
$l3r[$x] = ($pixel >> 0x10) & 0xff;
$l3g[$x] = ($pixel >> 0x08) & 0xff;
$l3b[$x] = ($pixel) & 0xff;
};
// vertical loop (through lines 1 to h - skip first line)
for ($y=0; $y<$ih; $y++) {
// update buffers
$l1r=$l2r; $l1g=$l2g; $l1b=$l2b;
$l2r=$l3r; $l2g=$l3g; $l2b=$l3b;
if ($y < ($ih+1)) {
for ($x=0; $x<$iw; $x++) {
$pixel = imagecolorat($image, $x, $y);
$l3r[$x] = ($pixel >> 0x10) & 0xff;
$l3g[$x] = ($pixel >> 0x08) & 0xff;
$l3b[$x] = ($pixel) & 0xff;
};
}
else {
$l3r=array_fill(0,$iw-1,0);
$l3g=array_fill(0,$iw-1,0);
$l3b=array_fill(0,$iw-1,0);
};
// horizontal loop (through pixels) - here's the main algo
for ($x=0; $x<$iw; $x++) {
$red = ((($l2r[$x-1] + $l2r[$x+1] + $l1r[$x ] + $l3r[$x ]) << 1)+
($l1r[$x-1] + $l3r[$x-1] + $l1r[$x+1] + $l3r[$x+1]));
$green = ((($l2g[$x-1] + $l2g[$x+1] + $l1g[$x ] + $l3g[$x ]) << 1) +
($l1g[$x-1] + $l3g[$x-1] + $l1g[$x+1] + $l3g[$x+1]));
$blue = ((($l2b[$x-1] + $l2b[$x+1] + $l1b[$x ] + $l3b[$x ]) << 1) +
($l1b[$x-1] + $l3b[$x-1] + $l1b[$x+1] + $l3b[$x+1]));
$red = (($red / 12)+12); if ($red > 0xff) $red = 0xff;
$green = (($green / 12)+12); if ($green > 0xff) $green = 0xff;
$blue = (($blue / 12)+12); if ($blue > 0xff) $blue = 0xff;
$l2r[$x] = $red;
$l2g[$x] = $green;
$l2b[$x] = $blue;
};
// update image
for ($x=0; $x<$iw; $x++) {
$pixel = (($l2r[$x] << 0x10) | ($l2g[$x] << 0x08) | ($l2b[$x]));
imagesetpixel($im, $x, $y, $pixel);
};
};
// return new image
return $im;
};
Here's the test-page: www.hl-soft.net/test.php
Have phun  | | Sonic_aka_T
 msx guru Berichten: 2262 | Geplaatst: 23 Juni 2004, 17:09   | Two suggestions... One, try averaging only with the direct neighbours. This should give a pretty nice result too, and you would only have to check 4 pixels instead of 8. Also I would go a bit easier on the blur effect. Try a weight of perhaps 1 for each neighbour and a weight of 2 or 4 for the original color. You would probably cut your time in half (at least) and still get a reasonable result. I for one would give it a go...
| | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 23 Juni 2004, 21:01   | Yup, I had that algorythm before, but the results weren't as satisfactory as the current one.
By the way, Sousuke: your algorithm's about 8 times as fast as mine, indeed. As said, I didn't care for optimization when I made it. But I didn't think such a simple block of code would cause such a huge amount of stress  . Anyway, instead of 1'20" it takes 10"-20" as execution time. Still too much I guess... Maybe I should try to install that ImageMagick properly... | | Sousuke msx freak Berichten: 154 | Geplaatst: 25 Juni 2004, 20:12   | Quote:
| Anyway, instead of 1'20" it takes 10"-20" as execution time. Still too much I guess... Maybe I should try to install that ImageMagick properly...
|
Yup, it's still too long. And additionally that image has to be filtered each time, when the page is opened!  I wonder how long ImageMagick will take for that
Another idea: Why don't you convert each new image only once, and save it's result somewhere on the HDD. If that image is needed again, then grab the converted one.
Should be a little bit faster this way  | | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 26 Juni 2004, 10:33   | Quote:
| Quote:
| Anyway, instead of 1'20" it takes 10"-20" as execution time. Still too much I guess... Maybe I should try to install that ImageMagick properly...
|
Yup, it's still too long. And additionally that image has to be filtered each time, when the page is opened!  I wonder how long ImageMagick will take for that
Another idea: Why don't you convert each new image only once, and save it's result somewhere on the HDD. If that image is needed again, then grab the converted one.
Should be a little bit faster this way 
|
Yes, I'd agree with the latter  , but it can also be loaded just once, and save it for, let's say, 20 minutes in the browser's cache. Shouldn't be a real hassle. | | ro msx guru Berichten: 2320 | Geplaatst: 26 Juni 2004, 16:16   | on the other hand, WHY would you have a original MSX screenshot ani-aliased anyway? isn't this some sort of masking/tricking to make it look better while in fact it's a trick. Dunno your reason but why?
I've done a realtime PHP screen5 picture loader myself (see www.thefuzz.nl and check download/screenshots for proof) and I myself was indeed surprised too about the slow PHP process! (about 5 to 10 secs to load up a screen, depending on brightness and dimension settings) Yeah, I build in a scaler and brightness button to get closer to original format
If you want antialiassed pictures you also might wanna use photoshop and use some blur or anything (in combination with the automation function)
cheers. ro | | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 27 Juni 2004, 03:00   | Well ro, a MSX picture would surely look fine on a ( MSX!) screen, so, when you wanna stretch it to sizes acceptable on 17" monitors (most likely, it's the most standard monitor size these days), you would surely want to antialias it. And besides, PC monitors (VGA monitors, to be exact) are too sharp to give images that blurry look that MSX monitors give them. So, as a kind of substitute, I offered this crappy anti-alias algorythm.
So that's why  | | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 27 Juni 2004, 03:01   | By the way, ro, those images are great!  | | ro msx guru Berichten: 2320 | Geplaatst: 27 Juni 2004, 12:15   | Yeah, I understand a VGA (specially with streched images) makes an a MSX screen look very blocky (too sharp) but your blurry algo makes it more than UN-sharp (too blurry), also the scaler function in some emulater (blue?) fuckes up the original in a way which I hate.
There should be some compensation in the blurry algo routs to make ik blocky, but not too sharp.
| | ro msx guru Berichten: 2320 | Geplaatst: 27 Juni 2004, 12:51   | another thing; making it a truecolor image (since your blur routine (anti alias) is using true colors) will help slowdown the process. Not to mention the file size!!
(which, in its turn, will slowdown the image download)
using PNG will enable you to use indexed colors. You could make the algo so that only about 16 EXTRA colors can be used to blur the image (ending up with a 32 indexed color portable network graphic image) or anything like that.
it will speed up your script too cuz colors are pre alocated for example
I've checked my own php GE5_viewer again, but I can't say I hate them outcoming pics (read: sharpness) . . I Like it ! (retro baby, retro)
Well, hopefully you end up having some compromised neat blurry algo which will be very usefull at the end. Keep us informed D-t!
| | [D-Tail] online
 msx guru Berichten: 2994 | Geplaatst: 27 Juni 2004, 17:31   | erm... Well, I don't know all the exact [D-Tail]s of the .PNG fileformat. The PHP/GD manual recommends creating true color images using imagecreatetruecolor() over creating normal images using imagecreate(). But as Sousuke already stated, it's the imagecolorallocate() which messes up the algorythm's speed. I don't know any specific PHP/GD .PNG-related issues, for in PHP you just create an image. In the end you decide which format will be output, using imagepng($image) or imagexbm($image) or so. So I think PHP/GD will optimize the picture for the fileformat itself.
| |
| |
| |
| |