Table Of Contents
This sample application demonstrates the
implementation of Bi-linear interpolation and Bi-Cubic interpolation in a GLSL
Screenshot of ZoomInterpolation Application.
In OpenGL, we can specify an interpolation type(Filter type)
to create a resized image of texture. When a texture or region of a texture is
mapped to a higher or lower screen region, OpenGL uses this interpolation type
to create texture image in different size.
To create a large image from a small texture area, openGL
provides two interpolation options, GL_LINEAR, and GL_LINEAR. In addition to OpenGL interpolation types, here bi-cubic interpolation is implemented
through GLSL shader.
OpenGL GL_NEAREST Interpolation.
GL_NEAREST just copies data available in nearest pixel and
it create a blocky effect when zoom to high region. In nearest interpolation,
intermediate pixels are created with nearest valid pixel. This kind of interpolated
image will be blocky since same data is copied to intermediate pixels.
Below image is created through opengl GL_NEAREST
interpolation and its quality is very bad.
We can use the following code to achieve nearest
interpolation in opengl fixed function pipeline.
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);
Interpolation with GL_NEAREST interpolation type.
OpenGL GL_LINEAR Interpolation.
OpenGL provides a good interpolation method, GL_LINEAR. It
interpolates nearest 4 pixels and creates a smooth image comparing to the
GL_NEAREST method. This method interpolate both in X direction and Y direction. Therefore it called Bi-Linear interpolation.
The following code can be used to achieve Bi-Linear
interpolation in openGL fixed function pipeline.
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR );
The following image is created through GL_LINEAR
interpolation and its edges are smooth when comparing to the image created
through GL_NEAREST interpolation.
Interpolation with GL_LINEAR interpolation type.
OpenGL provides only two interpolations methods to zoom an
image. These interpolation methods are not enough when a small image is zoomed
to large area. We can see small blocky effect in the above image ( GL_LINEAR ).
The first step is to create a GLSL shader for Bi-Linear
interpolation. This interpolation provides same output of GL_LINEAR.
In Bi-Linear interpolation nearest four pixels
are considered to create an intermediate pixel.
In the above figure an intermediate pixel F(p’,q’) is created
by interpolating nearest four texels F(p,q),
F(p,q+1), F(p+1,q), F(p+1,q+1). Texel is the term used to indicate an element(
similar to pixel) in a texture.
An interpolation factor a, is used in X direction to
interpolate F(p,q) and F(p,q+1) as follows.
F(p’’) = a * F(p,q) + (1.0 – a ) F(p, q+1) F(p+1’’) = a * F(p+1,q) + (1.0 – a ) F(p+1, q+1)
An interpolation factor b, is used in Y direction to
interpolate F(p’’)and F(p+1’’) as follows.
F(p’,q’) = b * F(p’’) + (1.0 - b) * F(p+1’’)
Corresponding GLSL shader code.
vec4 tex2DBiLinear( sampler2D textureSampler_i, vec2 texCoord_i )
vec4 p0q0 = texture2D(textureSampler_i, texCoord_i);
vec4 p1q0 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX, 0));
vec4 p0q1 = texture2D(textureSampler_i, texCoord_i + vec2(0, texelSizeY));
vec4 p1q1 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX , texelSizeY));
float a = fract( texCoord_i.x * fWidth );
vec4 pInterp_q0 = mix( p0q0, p1q0, a ); vec4 pInterp_q1 = mix( p0q1, p1q1, a );
float b = fract( texCoord_i.y * fHeight ); return mix( pInterp_q0, pInterp_q1, b ); }
In this method nearest 16 pixels are used to
create an intermediate pixel F(p’q’).
Following equation [from Digital
Image Processing: PIKS Inside, Third Edition] is used to interpolate
nearest 16 pixles.
Where Rc() denotes a bicubic interpolation function such as a cubic B-spline, Traingular, Bell cubic interpolation function. In this sample I just use a Triangular, Bell, and B-Spline interpolation function.
On zooming to a large space the intermediate pixels are created with nearest pixels.
Where F(p’,q’) is an intermediate texel. F(p’,q’) is identified by interpolating nearest 16 pixels. Where a is the offset in X direction, and b is the offset in Y direction from nearest valid data. These offset are considered between 0 and 1.
Following is a GLSL shader code for bi cubic interpolation. BiCubic function get a texture coordinate (x,y) and returns the interpolated value of nearest 16 texels. Nearest 16 texels are iterated through 2 for loops from [x-1,y-1] to [x+2, y+2]. For each nearest element an interpolation factor is calculated with the corresponding bi-cubic interpolation function. In this method Triangular() is used to get an interpolation factor. Different versions of Bi-Cubic interpolation[BSpline, Traingular, Bell] can be created by changing Triangular() and its logic. When plotting values from Triangular(), we will get the below image in a triangle form.
From plotting of triangular function, left most value of X axis is -2 and right most value of X axis is +2. It indicates Triangular function returns lower value for a high input and high value for a low input.
In BiCubic(), the nearest data get a high weightage[From Triangular()] and farthest pixel get a low weightage. In effect an intermediate pixel is created by interpolating nearest 16 data. The weightage will be higher for nearest pixels. The output image of Triangular Bi-Cubic is smoother than Bi-Linear .
Following code is a GLSL implementation of Bi-Cubic interpolation.
vec4 BiCubic( sampler2D textureSampler, vec2 TexCoord )
float texelSizeX = 1.0 / fWidth; float texelSizeY = 1.0 / fHeight; vec4 nSum = vec4( 0.0, 0.0, 0.0, 0.0 );
vec4 nDenom = vec4( 0.0, 0.0, 0.0, 0.0 );
float a = fract( TexCoord.x * fWidth ); float b = fract( TexCoord.y * fHeight ); for( int m = -1; m <=2; m++ )
for( int n =-1; n<= 2; n++)
vec4 vecData = texture2D(textureSampler, TexCoord + vec2(texelSizeX * float( m ), texelSizeY * float( n )));
float f = Triangular( float( m ) - a );
vec4 vecCooef1 = vec4( f,f,f,f );
float f1 = Triangular ( -( float( n ) - b ) );
vec4 vecCoeef2 = vec4( f1, f1, f1, f1 );
nSum = nSum + ( vecData * vecCoeef2 * vecCooef1 );
nDenom = nDenom + (( vecCoeef2 * vecCooef1 ));
return nSum / nDenom;
Implementation of Bi-Cubic Interpolation[ Triangular ]
Triangular function is a simple bi-cubic function, as defined in the following equation.
float Triangular( float f )
f = f / 2.0;
if( f < 0.0 )
return ( f + 1.0 );
return ( 1.0 - f );
Interpolation with GLSL BiCubic Triangular interpolation type.
Implementation of Bi-Cubic Interpolation[ Bell]
When comparing the Bi-Cubic
Triangular image with Bi-Linear, the edges are blurred. The reason of this edge
is weightage provided for nearest and farthest data. If weightage to nearest
data is high and far pixels are very low, then Bi-Cubic interpolation can
achieve a smooth edges. Another Bi-cubic
interpolation funciton which creates a bell shaped( nearest vaues[Center] are
high) and far values are low[left and right ends].
float BellFunc( float x )
float f = ( x / 2.0 ) * 1.5; if( f > -1.5 && f < -0.5 )
return( 0.5 * pow(f + 1.5, 2.0));
else if( f > -0.5 && f < 0.5 )
return 3.0 / 4.0 - ( f * f );
else if( ( f > 0.5 && f < 1.5 ) )
return( 0.5 * pow(f - 1.5, 2.0));
Interpolation with BiCubic Bell interpolation type.
Implementation of Bi-Cubic Interpolation[ B-Spline]
When comparing the Bi-Cubic Bell shaped, B spline is smoother and edges are more clear. Below equation is used to create BSpline() function.
float BSpline( float x )
float f = x;
if( f < 0.0 )
f = -f;
if( f >= 0.0 && f <= 1.0 )
return ( 2.0 / 3.0 ) + ( 0.5 ) * ( f* f * f ) - (f*f);
else if( f > 1.0 && f <= 2.0 )
return 1.0 / 6.0 * pow( ( 2.0 - f ), 3.0 );
Interpolation with BiCubic BSpline interpolation type.
ZoomInterpolation is a sample application created to demonstrate different interpolation methods. On startup it creates a texture with a bitmap [Flower.bmp] available in resource of this application.
This application displays two images, zoomed image is in left, and actual image is at right side. A red rectangle indicates the zoomed image. Small area of image is selected for texture mapping and displayed to screen.
When mouse clicks on zoomed image and pans, the texture mapping region changes with respect to mouse move and it creates a pan effect.
Zoom and UnZoom:
When Mouse scroll, the zoom/unzoom is implemented by increasing or decreasing the texture mapping area.
CZoomInterpolationDlg::HandleZoom() handles zoom and unzoom. Two buttons “Zoom+” and “Zoom-“ is also added to increase zoom or decrease zoom. I need these buttons to zoom or unzoom in my laptop.
Loading new Image:
A button “Load Image” is available to load an image file from your machine. This image area is created in an aspect ratio of 4:3 and therefore input image is expected in an aspect ratio of 4:3 for better output image. Otherwise stretched/skewed image will be displayed. BMPLoader class is used to retrieve RGB data from bitmap with the help of Gdi+ library. This class supports different image extensions such as .bmp, .jpg, .png, .tga etc.
Plotting of Interpolation Curve:
A simple class is created to plot the curve indicating weights applied in current Bi-Cubic interpolation function. Triangular, Bell, and BSpline are plotted with the same code of glsl shader code.
1) The input image is expected in an aspect ratio of 4:3 for better output image. Otherwise stretched/skewed image will be displayed.
2) For GLSL shader implementation, Some opengl following extensions are required in your machine.
If your machine do-not have supporting graphics device, this application will display interpolation with openGL fixed function pipeline(Nearest and Linear).
3) The shaders for different bi-cubic and Bi-linear interpolation is prepared with the help some equations, I expect some issues in this code.
- 07-Aug-2011: Initial Version.