Bicubic resampling by Pixel Bender

August 25th, 2009  |  Published in Uncategorized  |  14 Comments

There is bilinear resampling by Pixel Bender already, why not bicubic too?

With the very helpful Java implementation, I can get bicubic resampling running in Pixel Bender in hours.

Here is my result, along with the resampling results in PhotoShop as a comparison:

Source image (4x4), scaled by your browser)

Source image (size 4x4, scaled by your browser)

Source image enlarged in PS (nearest neighbor)

Source image enlarged by PS (nearest neighbor)

Bicubic resampling by Pixel Bender

Bicubic resampling by Pixel Bender

There is some difference with PhotoShop’s versions (below), hope it’s not my mistake…

Bicubic resampling by PhotoShop.

Bicubic resampling by PhotoShop.

Bicubic smoother in PhotoShop

Bicubic smoother by PhotoShop

Bicubic sharper in PhotoShop

Bicubic sharper by PhotoShop

My codes can be downloaded below:
Bicubic resampling sample program source (with PB source)


Update:
Notified by author of the Java version, the Java code was wrong and has been updated. Here below is my updated code:
Bicubic resampling sample program source (with PB source)

updated output of PB


Update (2010-11-17):
Once again notified by Paul, the author of the Java version, there is something need to be updated. Here below is my updated code:
Bicubic resampling sample program source (with PB source)

updated output of PB

Tags: , ,

Responses

  1. Brian says:

    November 24th, 2009 at 9:13 am (#)

    This filter looks fantastic when upsampling an image, but it is really jagged when downsampling. Any thoughts?

  2. Andy says:

    November 24th, 2009 at 10:00 pm (#)

    The code I ported from is actually designed for up sampling only as the name bicubic interpolation suggests. It is because it takes the nearest four points to calculate the values in between.
    More pixels (>4) are needed for “correct” calculation in high ratio down sampling.

  3. How to resize an image with ActionScript at Jozef Chúťka's blog says:

    January 15th, 2010 at 5:38 pm (#)

    [...] BitmapData, Bitmap, ByteArray, read this article. Continue reading about bilinear resampling and bicubic resampling using pixel [...]

  4. Yoz says:

    January 16th, 2010 at 10:40 pm (#)

    Hi, I have just figured out smoother downscaling
    http://blog.yoz.sk/2010/01/how-to-resize-an-image-with-actionscript/

  5. Paul Breeuwsma says:

    February 26th, 2010 at 5:20 am (#)

    Hi, I wrote the Java implementation and made a mistake: the code didn’t do bicubic interpolation, sorry.
    I fixed it a few days ago. So this code for Pixel Blender is wrong too and also has to be fixed.

  6. Andy says:

    March 1st, 2010 at 2:55 am (#)

    @Paul Breeuwsma Thanks for the info! I’ve just updated the code according to your changes. :)

  7. Paul Breeuwsma says:

    June 21st, 2010 at 8:47 am (#)

    Hi, I changed my code again, already a while ago, the new formula is more smooth than the one used here now. But now, it should be perfect. :)

  8. Josh M says:

    August 19th, 2010 at 5:54 am (#)

    Thanks for the code Andy. When scaling a bitmap of size 700×458 by 8, the kernal took about 2.1 seconds. Taking a look at the pb code, pre-computing some reoccurring float operations gave some very promising performance improvements. After the mod, I am seeing the same shaderJob taking 1.2 seconds.

    Here is the code:

    kernel bicubicResampling

    {
    parameter float2 scale
    ;

    input image4 src;
    output pixel4 dst;

    void
    evaluatePixel()
    {
    float2 scaledPt = outCoord() * scale – float2(0.5,0.5);
    float2 pt = floor(scaledPt);

    //http://www.paulinternet.nl/?page=bicubic
    float4 p00 = sampleNearest(src,pt+float2(-1.0,-1.0));
    float4 p01 = sampleNearest(src,pt+float2(-1.0,0.0));
    float4 p02 = sampleNearest(src,pt+float2(-1.0,1.0));
    float4 p03 = sampleNearest(src,pt+float2(-1.0,2.0));
    float4 p10 = sampleNearest(src,pt+float2(0.0,-1.0));
    float4 p11 = sampleNearest(src,pt+float2(0.0,0.0));
    float4 p12 = sampleNearest(src,pt+float2(0.0,1.0));
    float4 p13 = sampleNearest(src,pt+float2(0.0,2.0));
    float4 p20 = sampleNearest(src,pt+float2(1.0,-1.0));
    float4 p21 = sampleNearest(src,pt+float2(1.0,0.0));
    float4 p22 = sampleNearest(src,pt+float2(1.0,1.0));
    float4 p23 = sampleNearest(src,pt+float2(1.0,2.0));
    float4 p30 = sampleNearest(src,pt+float2(2.0,-1.0));
    float4 p31 = sampleNearest(src,pt+float2(2.0,0.0));
    float4 p32 = sampleNearest(src,pt+float2(2.0,1.0));
    float4 p33 = sampleNearest(src,pt+float2(2.0,2.0));

    //pre-computes
    float4 t2p01 = 2.0*p01;
    float4 t2p02 = 2.0*p02;
    float4 t2p03 = 2.0*p03;
    float4 t2p10 = 2.0*p10;
    float4 t2p11 = 2.0*p11;
    float4 t2p12 = 2.0*p12;
    float4 t2p13 = 2.0*p13;
    float4 t2p20 = 2.0*p20;
    float4 t2p21 = 2.0*p21;
    float4 t2p30 = 2.0*p30;
    float4 t2p31 = 2.0*p31;
    float4 t4p10 = 4.0*p10;
    float4 t4p11 = 4.0*p11;
    float4 t4p01 = 4.0*p01;
    float4 t4p00 = 4.0*p00;
    float4 n2p00 = -2.0*p00;

    float4 p10mp12 = -p10 + p12;
    float4 p00mp01 = p00 – p01;
    float4 p32ap33 = p32 – p33;
    float4 p22ap23 = p22 – p23;
    float4 p00mp02 = p00 – p02;
    float4 p02mp03 = p02 – p03;
    float4 p12ap13 = p12 – p13;
    float4 p02mmp03 = p02 – p03;
    float4 np10ap11 = -p10 + p11;

    float4 a02 = t2p10 – t2p11 + p12ap13;
    float4 a03 = np10ap11 – p12ap13;
    float4 a11 = p00mp02 – p20 + p22;
    float4 a12 = n2p00 + t2p01 – p02mp03 + t2p20 – t2p21 + p22ap23;
    float4 a13 = p00mp01 + p02mmp03 – p20 + p21 – p22ap23;
    float4 a20 = t2p01 – t2p11 + p21 – p31;
    float4 a21 = n2p00 + t2p02 + t2p10 – t2p12 – p20 + p22 + p30 – p32;
    float4 a22 = t4p00 – t4p01 + t2p02 – t2p03 – t4p10 + t4p11 – t2p12 + t2p13 + t2p20 – t2p21 + p22ap23 – t2p30 + t2p31 – p32ap33;
    float4 a23 = n2p00 + t2p01 – t2p02 + t2p03 + t2p10 – t2p11 + t2p12 – t2p13 – p20 + p21 – p22 + p23 + p30 – p31 + p32ap33;
    float4 a30 = -p01 + p11 – p21 + p31;
    float4 a31 = p00mp02 – p10 + p12 + p20 – p22 – p30 + p32;
    float4 a32 = n2p00 + t2p01 – p02mp03 + t2p10 – t2p11 + p12 – p13 – t2p20 + t2p21 – p22ap23 + t2p30 – t2p31 + p32ap33;
    float4 a33 = p00mp01 + p02mmp03 + np10ap11 – p12ap13 + p20 – p21 + p22 – p23 – p30 + p31 – p32ap33;

    float x = scaledPt.x – pt.x;
    float x2 = x * x;
    float x3 = x2 * x;

    float y = scaledPt.y – pt.y;
    float y2 = y * y;
    float y3 = y2 * y;

    dst = p11 + p10mp12 * y + a02 * y2 + a03 * y3 +
    (-p01 + p21) * x + a11 * x * y + a12 * x * y2 + a13 * x * y3 +
    a20 * x2 + a21 * x2 * y + a22 * x2 * y2 + a23 * x2 * y3 +
    a30 * x3 + a31 * x3 * y + a32 * x3 * y2 + a33 * x3 * y3;
    }
    }

  9. thumbnail 만들 때의 문제해결 | dieBuster says:

    August 19th, 2010 at 9:33 pm (#)

    [...] http://blog.onthewings.net/2009/08/25/bicubic-resampling-by-pixel-bender/ window.fbAsyncInit = function() { FB.init({appId: "", status: true, cookie: true, xfbml: true}); }; (function() { var e = document.createElement("script"); e.async = true; e.src = document.location.protocol + "//connect.facebook.net/en_US/all.js"; document.getElementById("fb-root").appendChild(e); }()); [Translate] Share! 관련된 글:색상혼합과 픽셀벤더를 이용한 가상 디스플레이 계층 [...]

  10. Andy Li says:

    November 17th, 2010 at 2:35 am (#)

    @Paul

    Thanks for the info and the works! I’ve updated it again. :)

    @Josh

    Great to see the performance gain!
    However, as the code is changed according to Paul, your optimization need to be updated too.
    I haven’t incorporated your optimization since I do not have the time to do so. Feel free to share with us your optimized version again :)

  11. Soroush says:

    April 3rd, 2011 at 11:36 pm (#)

    Hello Andy,
    What about video upscaling; does flash player is default to low quality nearest neighbor when dealing with video? and if so is your code applicable to video upscaling?

    It is a pity that Adobe do not implement such highly required feature natively in flash player and we still need custom coding to achieve desired resampling method.

  12. Andy Li says:

    April 4th, 2011 at 3:57 pm (#)

    @Soroush

    I’m not sure about video upscaling, but I believe it is linear. For latest version of FP, if there is hardware decoding, the scaling should be done by graphic card too.

    The bicubic pb filter can be applied to video, but it probably will consume lots of CPU power.

  13. dieBuster Flash » Blog Archive » BitmapData 확대축소 문제해결 says:

    April 12th, 2011 at 11:56 pm (#)

    [...] http://blog.onthewings.net/2009/08/25/bicubic-resampling-by-pixel-bender/ [...]

  14. ahmet says:

    December 26th, 2011 at 4:11 pm (#)

    hi
    thanks for sharing
    is there any code sample
    thanks

Leave a Response

*