William
William

Reputation: 63

Using CImg to fill in color using linear interpolation

"Using CImg, write a program that constructs a square image and assigns a color to each corner. Using linear interpolation, fill in and color each pixel in the square so that there is a smooth coloring across the entire area of the square"

I have a hard time to understand how to pick a color for each corner, and fill in color for the square. Below is the code that I have, but it seems randomly place the color, and I cannot pick my own color. Below the code I have right now.

#include <iostream>
#include "CImg/CImg.h"

using namespace cimg_library;
using namespace std;

int main() {
  //Create an empty image
  CImg<unsigned char> square(255, 255, 1, 3, 0);

  for (int i = 0; i < 255; i++){
      for(int j = 0; j < 255; j++){
          //Red
          square(i,j,0,0) = i; 
          //Green
          square(i,j,0,1) = j;
          //Blue
          square(i,j,0,2) = i;                
      }
  }

  //Display and save filtered image
  CImgDisplay disp(square); 
  while (!disp.is_closed())
      disp.wait();   
  square.save("squareInterpolation.bmp");  
}

Result from my code:
image

Result I wanted (ignore the white border):
image

Thank you so much!

Upvotes: 2

Views: 1727

Answers (1)

Mark Setchell
Mark Setchell

Reputation: 207455

At the moment, your code isn't doing any interpolation - it is just assigning. Interpolation is where you know some values at the limits of an image and calculate the values in-between those known values (using a formula) to fill in the unknown values.

Actually, CImg will do interpolation for you and, IMHO, good engineers re-use and recycle well-tested code as it keeps costs down. So, the simplest solution is to create a 2x2 image of the red, green, blue and white corner points (the known values in the interpolation) and let CImg resize your image up to 255x255 using interpolation.

That could look like this:

#include <iostream>
#include <cstdlib>
#define cimg_display 0
#include "CImg.h"

using namespace cimg_library;
using namespace std;

#define INTERPOLATION_LINEAR            3
#define INTERPOLATION_CUBIC             5

#define BOUNDARY_DIRICHLET              0
#define BOUNDARY_NEUMANN                1

int main() {
   // Create 2x2 image with Red, Green, Blue and White pixels
   CImg<unsigned char> image(2,2,1,3,0);
   image(0,0,0,0)=255;  // top-left is Red
   image(1,0,0,1)=255;  // top-right is Green
   image(0,1,0,2)=255;  // bottom-left is Blue
   image(1,1,0,0)=255;  // bottom-right is white
   image(1,1,0,1)=255;  // bottom-right is white
   image(1,1,0,2)=255;  // bottom-right is white

   // Let CImg do the interpolation for us - because smart engineers re-use well tested code
   CImg<unsigned char> result=image.resize(255,255,-100,-100,INTERPOLATION_LINEAR,BOUNDARY_DIRICHLET);

   // Save result image as NetPBM PNM - no libraries required
   result.save_pnm("result.pnm");
}

enter image description here

I guess that is not the way you are expected to do it, so I would combine that solution with a further one where I implemented the interpolation myself. Here is a formula you might use from the Wikipedia article on Bilinear Interpolation.

enter image description here

That could be implemented to like this:

#include <iostream>
#include <cstdlib>
#define cimg_display 0
#include "CImg.h"

using namespace cimg_library;
using namespace std;

int main() {
   // Create 256x256 image with Red, Green, Blue and White pixels
   CImg<unsigned char> image(256,256,1,3,0);
   image(0,0,0,0)=255;      // top-left is Red
   image(255,0,0,1)=255;    // top-right is Green
   image(0,255,0,2)=255;    // bottom-left is Blue
   image(255,255,0,0)=255;  // bottom-right is white
   image(255,255,0,1)=255;  // bottom-right is white
   image(255,255,0,2)=255;  // bottom-right is white

   // Fill inner area by interpolation
   for(int r=0;r<256;r++){                   // "r" for "row" 
      for(int c=0;c<256;c++){                // "c" for "column"
         for(int b=0;b<3;b++){               // "b" for "band" in my head
            float oneMinusX=(255-r)/255.0;
            float oneMinusY=(255-c)/255.0;
            image(r,c,0,b)=image(0,0,0,b)*oneMinusX*oneMinusY +
                     image(255,0,0,b)*oneMinusY*r/255.0 +
                     image(0,255,0,b)*oneMinusX*c/255.0 +
                     image(255,255,0,b)*r*c/(255.0*255.0);
         }
      }
   }

   // Save result image as NetPBM PNM - no libraries required
   image.save_pnm("result.pnm");
}

Upvotes: 1

Related Questions