BBC BASIC for Windows
« Image scaling (bilinear interpolation) »

Welcome Guest. Please Login or Register.
Apr 5th, 2018, 9:57pm



ATTENTION MEMBERS: Conforums will be closing it doors and discontinuing its service on April 15, 2018.
Ad-Free has been deactivated. Outstanding Ad-Free credits will be reimbursed to respective payment methods.

If you require a dump of the post on your message board, please come to the support board and request it.


Thank you Conforums members.

BBC BASIC for Windows Resources
Online BBC BASIC for Windows documentation
BBC BASIC for Windows Beginners' Tutorial
BBC BASIC Home Page
BBC BASIC on Rosetta Code
BBC BASIC discussion group
BBC BASIC for Windows Programmers' Reference

« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Image scaling (bilinear interpolation)  (Read 1839 times)
David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Image scaling (bilinear interpolation)
« Thread started on: Dec 28th, 2012, 03:44am »

Here's the BASIC prototype intended for translation into assembly language (non-MMX as usual; too beyond my abilities). I don't think I'm interested in discussions about the merits (or otherwise) of this interpolation method over any other, I'm just glad I've got it working!

If you've got the GFXLIB package installed then you can copy, paste and run this program.

I'm guessing that, despite a hell of a lot of CPU cycles per pixel drawn, the non-MMX assembler version should be fast enough for my purposes.

Code:
      REM. Version 1.1
      REM.
      REM. Bilinear interpolating image scaler (rough BASIC prototype),
      REM. to be translated to assembly language.
      REM.
      REM. Requires GFXLIB (version 2.03 or higher)
      
      HIMEM = PAGE + 5*&100000
      
      MODE 8 : OFF
      
      INSTALL @lib$ + "GFXLIB2"                  : PROCInitGFXLIB
      INSTALL @lib$ + "GFXLIB_modules\PlotScale" : PROCInitModule
      
      img% = FNLoadImg( @lib$+"GFXLIB_media\gfxlib_480x128x8.BMP", 0)
      w% = 480
      h% = 128
      
      w2 = 0.8 * w% : w2% = w2
      h2 = 0.8 * h% : h2% = h2
      img2% = FNmalloc( 4 * (w2%+1)*(h2%+1) )
      
      xr% = ((w% - 1) / w2) * 65536
      yr% = ((h% - 1) / h2) * 65536
      
      B% = img2%
      
      PRINT '" Scaling image, please wait..."
      
      FOR I% = 0 TO h2%-1
        
        Y% = (yr% * I%) AND &FFFF0000
        dy% = ((yr%*I% - Y%) << 8) >> 16
        dy_% = 255 - dy%
        Y% = Y% >> 16
        
        FOR J% = 0 TO w2%-1
          
          X% = (xr% * J%) AND &FFFF0000
          dx% = ((xr%*J% - X%) << 8) >> 16
          X% = X% >> 16
          
          dx_%    = 255 - dx%
          dxdy%   = dx% * dy%
          dxdy_%  = dx% * dy_%
          dx_dy%  = dx_% * dy%
          dx_dy_% = dx_% * dy_%
          
          A% = img% + 4*(Y%*w% + X%)
          
          a& = ?A%
          b& = A%?4
          c& = A%?(4*w%)
          d& = A%?(4*w% + 4)
          ?B% = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          a& = ?(A% + 1)
          b& = A%?5
          c& = A%?(4*w% + 1)
          d& = A%?(4*w% + 5)
          B%?1 = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          a& = ?(A% + 2)
          b& = A%?6
          c& = A%?(4*w% + 2)
          d& = A%?(4*w% + 6)
          B%?2 = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          B% += 4
          
        NEXT
      NEXT
      
      CLS
      
      REM. Draw normal, non-scaled image
      SYS GFXLIB_BPlot%, dispVars{}, img%, w%, h%, 0, 0
      
      REM. Draw scaled image (nearest neighbour)
      SYS GFXLIB_PlotScale%, dispVars{}, img%, w%, h%, w2%, h2%, 0, 170
      
      REM. Draw scaled image (bilinear interpolation)
      SYS GFXLIB_BPlot%, dispVars{}, img2%, w2%, h2%, 0, 310
      
      PROCdisplay
      
      PRINT '" Bottom image is normal size (not scaled)"
      PRINT " Middle image is scaled using nearest-neighbour algorithm"
      PRINT " Top image is scaled using bilinear interpolation"
 



If anyone spots any optimizations (non-BASIC specific) or possible improvements in precision without too much CPU overhead, then please do tell.


Regards,

David.
« Last Edit: Dec 28th, 2012, 04:25am by David Williams » User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Image scaling (bilinear interpolation)
« Reply #1 on: Dec 28th, 2012, 08:33am »

Okay, here's a demo of the extremely sub-optimal, non-SIMD, assembly language version of the above BASIC prototype:

http://www.bb4wgames.com/misc/scaling_bilinear.zip


Sorry, no source code yet. Too messy.


David.
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Image scaling (bilinear interpolation)
« Reply #2 on: Dec 28th, 2012, 4:46pm »

on Dec 28th, 2012, 03:44am, David Williams wrote:
Here's the BASIC prototype

As displayed on my PC, the bottom ('unscaled') image already has some obvious aliasing, particularly noticeable on the diagonal edges of the 'X' and the top of the 'G'. So it's not an ideal starting point!

It's also worth pointing out that whilst your 'original' image is perhaps typical of GFXLIB output it's a very poor test of the quality of a scaling algorithm - it still looks quite respectable with a nearest-neighbour method! A better choice would be either a circular or hyperbolic zone plate which will really separate the sheep from the goats:

Code:
      REM. Version 1.1
      REM.
      REM. Bilinear interpolating image scaler (rough BASIC prototype),
      REM. to be translated to assembly language.
      REM.
      REM. Requires GFXLIB (version 2.03 or higher)
      
      HIMEM = PAGE + 5*&100000
      
      MODE 8 : OFF
      
      INSTALL @lib$ + "GFXLIB2"                  : PROCInitGFXLIB
      INSTALL @lib$ + "GFXLIB_modules\PlotScale" : PROCInitModule
      
      img% = FNLoadImg( @lib$+"GFXLIB_media\gfxlib_480x128x8.BMP", 0)
      
      FOR Y% = 0 TO 127
        FOR X% = 0 TO 479
          r2 = (Y%-64)^2 + (X%-240)^2
          V% = &FF * (1 + SIN(r2/240)) / 2 + 0.5
          img%!(Y%*&780+X%*4) = V% + (V% << 8) + (V% << 16)
        NEXT
      NEXT
      
      w% = 480
      h% = 128
      
      w2 = 0.8 * w% : w2% = w2
      h2 = 0.8 * h% : h2% = h2
      img2% = FNmalloc( 4 * (w2%+1)*(h2%+1) )
      
      xr% = ((w% - 1) / w2) * 65536
      yr% = ((h% - 1) / h2) * 65536
      
      B% = img2%
      
      PRINT '" Scaling image, please wait..."
      
      FOR I% = 0 TO h2%-1
        
        Y% = (yr% * I%) AND &FFFF0000
        dy% = ((yr%*I% - Y%) << 8) >> 16
        dy_% = 255 - dy%
        Y% = Y% >> 16
        
        FOR J% = 0 TO w2%-1
          
          X% = (xr% * J%) AND &FFFF0000
          dx% = ((xr%*J% - X%) << 8) >> 16
          X% = X% >> 16
          
          dx_%    = 255 - dx%
          dxdy%   = dx% * dy%
          dxdy_%  = dx% * dy_%
          dx_dy%  = dx_% * dy%
          dx_dy_% = dx_% * dy_%
          
          A% = img% + 4*(Y%*w% + X%)
          
          a& = ?A%
          b& = A%?4
          c& = A%?(4*w%)
          d& = A%?(4*w% + 4)
          ?B% = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          a& = ?(A% + 1)
          b& = A%?5
          c& = A%?(4*w% + 1)
          d& = A%?(4*w% + 5)
          B%?1 = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          a& = ?(A% + 2)
          b& = A%?6
          c& = A%?(4*w% + 2)
          d& = A%?(4*w% + 6)
          B%?2 = ( a&*dx_dy_% + b&*dxdy_% + c&*dx_dy% + d&*dxdy% ) >> 16
          
          B% += 4
          
        NEXT
      NEXT
      
      CLS
      
      REM. Draw normal, non-scaled image
      SYS GFXLIB_BPlot%, dispVars{}, img%, w%, h%, 0, 0
      
      REM. Draw scaled image (nearest neighbour)
      SYS GFXLIB_PlotScale%, dispVars{}, img%, w%, h%, w2%, h2%, 0, 170
      
      REM. Draw scaled image (bilinear interpolation)
      SYS GFXLIB_BPlot%, dispVars{}, img2%, w2%, h2%, 0, 310
      
      PROCdisplay
      
      PRINT '" Bottom image is normal size (not scaled)"
      PRINT " Middle image is scaled using nearest-neighbour algorithm"
      PRINT " Top image is scaled using bilinear interpolation" 

Richard.
User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Image scaling (bilinear interpolation)
« Reply #3 on: Dec 28th, 2012, 5:16pm »

on Dec 28th, 2012, 08:33am, David Williams wrote:
Okay, here's a demo of the extremely sub-optimal, non-SIMD, assembly language version of the above BASIC prototype

OK, so that's the 'promotional video' - designed to make it look as good as possible. Now I want to see the same thing with the zone-plate image used as the source! wink

Richard.
User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Image scaling (bilinear interpolation)
« Reply #4 on: Dec 28th, 2012, 6:34pm »

Here's a demo (with source) using Richard's rather striking "zone-plate image":

http://www.bb4wgames.com/temp/scalebilinear.zip

Press <space bar> to toggle between nearest-neighbour and bilinear-interpolated scaling.

Demo2 features a SFW female face image. Overall, bilinear looks a bit better (though struggles with her hair a bit).

Bear in mind GFXLIB_ScaleBilinear isn't intended for real-time scaling, at least not in its current, nasty form.

Nice article on MMX-powered bi. interp.:
http://software.intel.com/sites/landingpage/legacy/mmx/MMX_App_Bilinear_Interpolation_RGB.pdf

Even I can understand much of it!


Regards,

Daiv.d
« Last Edit: Dec 28th, 2012, 6:37pm by David Williams » User IP Logged

admin
Administrator
ImageImageImageImageImage


member is offline

Avatar




PM


Posts: 1145
xx Re: Image scaling (bilinear interpolation)
« Reply #5 on: Dec 28th, 2012, 9:51pm »

on Dec 28th, 2012, 6:34pm, David Williams wrote:
Here's a demo....
Demo2 features a SFW female face image....

Thanks. I would imagine the quality jump from 'nearest neighbour' to 'bilinear' is more marked than any further improvement achievable by using a more complex algorithm.

Quote:
Daiv.d

Seems rather Dune-like. Do you wish always to be called Daiv.d from now on?

Richard.
User IP Logged

David Williams
Developer

member is offline

Avatar

meh


PM

Gender: Male
Posts: 452
xx Re: Image scaling (bilinear interpolation)
« Reply #6 on: Dec 28th, 2012, 10:05pm »

on Dec 28th, 2012, 9:51pm, Richard Russell wrote:
Seems rather Dune-like. Do you wish always to be called Daiv.d from now on?


It really was a typo.


David.
--
User IP Logged

Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

| |

This forum powered for FREE by Conforums ©
Terms of Service | Privacy Policy | Conforums Support | Parental Controls