Bilinear interpolation

From Rosetta Code
Revision as of 16:40, 17 March 2014 by rosettacode>Bearophile (Updated D entry)
Bilinear interpolation is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Bilinear interpolation is linear interpolation in 2 dimensions, and is typically used for image scaling.

C

<lang c>#include <stdint.h> typedef struct {

   uint32_t *pixels;
   unsigned int w;
   unsigned int h;

} image_t;

  1. define getByte(value, n) (value >> (n*8) & 0xFF)

uint32_t getpixel(image_t *image, unsigned int x, unsigned int y){

   return image->pixels[(y*image->w)+x];

} float lerp(float s, float e, float t){return s+(e-s)*t;} float blerp(float c00, float c10, float c01, float c11, float tx, float ty){

   return lerp(lerp(c00, c10, tx), lerp(c01, c11, tx), ty);

} void putpixel(image_t *image, unsigned int x, unsigned int y, uint32_t color){

   image->pixels[(y*image->w) + x] = color;

} void scale(image_t *src, image_t *dst, float scalex, float scaley){

   int newWidth = (int)src->w*scalex;
   int newHeight= (int)src->h*scaley;
   int x, y;
   for(x= 0, y=0; y < newHeight; x++){
       if(x > newWidth){
           x = 0; y++;
       }
       float gx = x / (float)(newWidth) * (src->w-1);
       float gy = y / (float)(newHeight) * (src->h-1);
       int gxi = (int)gx;
       int gyi = (int)gy;
       uint32_t result=0;
       uint32_t c00 = getpixel(src, gxi, gyi);
       uint32_t c10 = getpixel(src, gxi+1, gyi);
       uint32_t c01 = getpixel(src, gxi, gyi+1);
       uint32_t c11 = getpixel(src, gxi+1, gyi+1);
       uint8_t i;
       for(i = 0; i < 3; i++){
           //((uint8_t*)&result)[i] = blerp( ((uint8_t*)&c00)[i], ((uint8_t*)&c10)[i], ((uint8_t*)&c01)[i], ((uint8_t*)&c11)[i], gxi - gx, gyi - gy); // this is shady
           result |= (uint8_t)blerp(getByte(c00, i), getByte(c10, i), getByte(c01, i), getByte(c11, i), gx - gxi, gy -gyi) << (8*i);
       }
       putpixel(dst,x, y, result);
   }

}</lang>

D

This uses the module from the Grayscale Image task.

Translation of: C

<lang d>import grayscale_image;

/// Currently this accepts only a Grayscale image for simplicity. Image!Gray rescaleGray(in Image!Gray src,

                      in float scaleX, in float scaleY)

pure nothrow in {

   assert(src !is null, "Input Image is null.");
   assert(src.nx > 1 && src.ny > 1,
          "Minimal input image size is 2x2.");
   assert(cast(uint)(src.nx * scaleX) > 0,
          "Output image width must be > 0.");
   assert(cast(uint)(src.ny * scaleY) > 0,
          "Output image height must be > 0.");

} body {

   alias FP = float;
   static FP lerp(in FP s, in FP e, in FP t) pure nothrow {
       return s + (e - s) * t;
   }
   static FP blerp(in FP c00, in FP c10, in FP c01, in FP c11,
                   in FP tx, in FP ty) pure nothrow {
       return lerp(lerp(c00, c10, tx), lerp(c01, c11, tx), ty);
   }
   immutable newWidth = cast(uint)(src.nx * scaleX);
   immutable newHeight = cast(uint)(src.ny * scaleY);
   auto result = new Image!Gray(newWidth, newHeight, true);
   foreach (immutable y; 0 .. newHeight)
       foreach (immutable x; 0 .. newWidth) {
           immutable FP gx = x / FP(newWidth) * (src.nx - 1);
           immutable FP gy = y / FP(newHeight) * (src.ny - 1);
           immutable gxi = cast(uint)gx;
           immutable gyi = cast(uint)gy;
           immutable c00 = src[gxi,     gyi];
           immutable c10 = src[gxi + 1, gyi];
           immutable c01 = src[gxi,     gyi + 1];
           immutable c11 = src[gxi + 1, gyi + 1];
           immutable pixel = blerp(c00, c10, c01, c11,
                                   gx - gxi, gy - gyi);
           result[x, y] = Gray(cast(ubyte)pixel);
       }
   return result;

}

void main() {

   const im = loadPGM!Gray(null, "lena.pgm");
   im.rescaleGray(0.3, 0.1).savePGM("lena_smaller.pgm");
   im.rescaleGray(1.3, 1.8).savePGM("lena_larger.pgm");

}</lang>

Racket

This mimics the Wikipedia example. <lang racket>#lang racket (require images/flomap)

(define fm

 (draw-flomap
  (λ (dc)
    (define (pixel x y color)
      (send dc set-pen color 1 'solid)
      (send dc draw-point (+ x .5) (+ y 0.5)))  
    (send dc set-alpha 1)
    (pixel 0 0 "blue")
    (pixel 0 1 "red")
    (pixel 1 0 "red")
    (pixel 1 1 "green"))
  2 2))

(flomap->bitmap

(build-flomap
 4 250 250
 (λ (k x y)
   (flomap-bilinear-ref 
    fm k (+ 1/2 (/ x 250)) (+ 1/2 (/ y 250))))))</lang>