Zoom an image with different interpolation types.
Table Of Contents
Introduction
This sample application demonstrates the implementation of Bi-linear interpolation and Bi-Cubic interpolation in a GLSL shader.
Screenshot of ZoomInterpolation Application.
Background
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.
GLSL Bi-Linear
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) // Linear interpolation in X direction[Top]. F(p+1’’) = a * F(p+1,q) + (1.0 – a ) F(p+1, q+1) // Linear interpolation in X direction[Bottom].
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.
// Function to get a texel data from a texture with GL_NEAREST property. // Bi-Linear interpolation is implemented in this function with the // help of nearest four data. 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 ); // Get Interpolation factor for X direction. // Fraction near to valid data. vec4 pInterp_q0 = mix( p0q0, p1q0, a ); // Interpolates top row in X direction. vec4 pInterp_q1 = mix( p0q1, p1q1, a ); // Interpolates bottom row in X direction. float b = fract( texCoord_i.y * fHeight ); // Get Interpolation factor for Y direction. return mix( pInterp_q0, pInterp_q1, b ); // Interpolate in Y direction. }
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; //size of one texel float texelSizeY = 1.0 / fHeight; //size of one texel 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 ); // get the decimal part float b = fract( TexCoord.y * fHeight ); // get the decimal part 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.
The above diagram is the output of Triangular() function. Triangular(x) is plotted in Y direction. x starts from -2.0 and ends at +2.0. It indicate when x is high, Triangular(x) is low and therefore far data of an intermediate texel get lower weight. The following code is used in GLSL shader for Triangular Bi-Cubic implementation.
float Triangular( float f ) { f = f / 2.0; if( f < 0.0 ) { return ( f + 1.0 ); } else { return ( 1.0 - f ); } return 0.0; }
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 weight provided for nearest and farthest data. If weight 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].
The above diagram is the output of BellFunc() function. BellFunc(x) is plotted in Y direction. x starts from -2.0 and ends at +2.0. It indicate when x is high, BellFunc(x) is very low and therefore far data of an intermediate texel get very lower weight. The following code is used in GLSL shader for Bell shaped Bi-Cubic implementation.
float BellFunc( float x ) { float f = ( x / 2.0 ) * 1.5; // Converting -2 to +2 to -1.5 to +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)); } return 0.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.
The above diagram is the output of BSpline() function. BSpline(x) is plotted in Y direction. x starts from -2.0 and ends at +2.0. It indicate when x is high, BSpline(x) is very low and therefore far data of an intermediate texel get very lower weight. When comparing to Bell shaped wave, values in far range ( near -2 and +2 ) are very low. Therefore final output image is also smoother than Bell Bi-Cubic interpolated image. The following code is used in GLSL shader for BSpline implementation.
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 ); } return 1.0; }
Interpolation with BiCubic BSpline interpolation type.
About ZoomInterpolation Application:
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.
Pan operation:
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. These buttons will be helpful for zoom and unzoom in a 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.
Main Classes Used in ZoomInterpolationApp:
BMPLoader
: This class is used for getting RGB information of an image file.GLExtension
: This class holds all opengl extensions required for GLSL shader.GLSetup
: This class is used for creating rendering context and other opengl initialisations.GLVertexBuffer
: This class holds vertex data required for rendering a Quad image withtexture mapping.PlotInterpCurve
: This class draws current interpolation curve with the help of GDI. ZoomInterpolation
: This class handles main operations of ZoomInterpolation Application.Limitations:
GL_ARB_fragment_shader
GL_ARB_vertex_shader
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.
References:
- Digital Image Processing: PIKS Inside, Third Edition. William K. Pratt[ISBN: 0-471-22132-5] Section:
- 4.3. Image Reconstruction Systems.
- 13.5.1. Interpolation Methods
- http://www.cambridgeincolour.com/tutorials/image-interpolation.htm
- http://en.wikipedia.org/wiki/Bilinear_interpolation
- http://en.wikipedia.org/wiki/Bicubic_interpolation
History:
- 07-Aug-2011: Initial Version.
Post Comment
2u78cM wow, awesome blog article.Really thank you! Keep writing.
DyKHhJ I value the article post.Really looking forward to read more. Really Great.
iW5SrH I truly appreciate this article post.Much thanks again.
zAoi8D wow, awesome article post.Really thank you! Great.
jT1la5 This is one awesome blog article.Really thank you! Really Great.
ZRmJYL It as not that I want to replicate your web-site, but I really like the style. Could you tell me which theme are you using? Or was it custom made?
XvuN2o Keep up the superb piece of work, I read few articles on this web site and I conceive that your site is very interesting and has lots of superb info.
b6a6OE Well I definitely enjoyed studying it. This information offered by you is very useful for proper planning.
1Hih9z Really informative post.Really looking forward to read more. Keep writing.
UjU6kz Major thankies for the article. Fantastic.