zoukankan      html  css  js  c++  java
  • 三种常见的图像处理双三次插值算法

    三种常见的图像处理双三次插值算法

    双立方插值计算涉及16像素,间(i’, j’)像中的包括

    小数部分的像素坐标。dx表示X方向的小数坐标。dy表示Y方向的小数坐标。

    详细

    能够看下图:


    依据上述图示与双立方插值的数学表达式能够看出。双立方插值本质上图像16个像素点

    权重卷积之和作为新的像素值。

    当中R(x)表示插值表达式,能够依据须要选择的表达式不同。常见有基于三角取值、Bell

    分布表达、B样条曲线表达式。

    1. 基于三角形採样数学公式为


    最简单的线性分布,代码实现例如以下:

    private double triangleInterpolation( double f )
    {
    	f = f / 2.0;
    	if( f < 0.0 )
    	{
    		return ( f + 1.0 );
    	}
    	else
    	{
    		return ( 1.0 - f );
    	}
    }
    2.基于Bell分布採样的数学公式例如以下:


    Bell分布採样数学公式基于三次卷积计算实现。代码实现例如以下:

    private double bellInterpolation( double x )
    {
    	double f = ( x / 2.0 ) * 1.5;
    	if( f > -1.5 && f < -0.5 )
    	{
    		return( 0.5 * Math.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 * Math.pow(f - 1.5, 2.0));
    	}
    	return 0.0;
    }
    3.基于B样条曲线採样的数学公式例如以下:


    是一种基于多项式的四次卷积的採样计算,代码例如以下:

    private double bspLineInterpolation( double f )
    {
    	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 * Math.pow( ( 2.0 - f  ), 3.0 );
    	}
    	return 1.0;
    }
    实现图像双立方插值的完整源码例如以下:

    package com.gloomyfish.zoom.study;
    
    import java.awt.image.BufferedImage;
    import java.awt.image.ColorModel;
    
    import com.gloomyfish.filter.study.AbstractBufferedImageOp;
    
    public class BicubicInterpolationFilter extends AbstractBufferedImageOp  {
    	public final static int TRIANGLE__INTERPOLATION = 1;
    	public final static int BELL__INTERPOLATION = 2;
    	public final static int BSPLINE__INTERPOLATION = 4;
    	public final static int CATMULLROOM__INTERPOLATION = 8;
        public final static double B = 0.0;
        public final static double C = 0.5; // constant
    	private int destH; // zoom height
    	private int destW; // zoom width
    	private int type;
    	public BicubicInterpolationFilter()
    	{
    		this.type = BSPLINE__INTERPOLATION;
    	}
    	public void setType(int type) {
    		this.type = type;
    	}
    	public void setDestHeight(int destH) {
    		this.destH = destH;
    	}
    
    	public void setDestWidth(int destW) {
    		this.destW = destW;
    	}
    	
    	private double bellInterpolation( double x )
    	{
    		double f = ( x / 2.0 ) * 1.5;
    		if( f > -1.5 && f < -0.5 )
    		{
    			return( 0.5 * Math.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 * Math.pow(f - 1.5, 2.0));
    		}
    		return 0.0;
    	}
    	
    	private double bspLineInterpolation( double f )
    	{
    		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 * Math.pow( ( 2.0 - f  ), 3.0 );
    		}
    		return 1.0;
    	}
    	
    	private double triangleInterpolation( double f )
    	{
    		f = f / 2.0;
    		if( f < 0.0 )
    		{
    			return ( f + 1.0 );
    		}
    		else
    		{
    			return ( 1.0 - f );
    		}
    	}
    	
    	private double CatMullRomInterpolation( double f )
    	{
    	    if( f < 0.0 )
    	    {
    	        f = Math.abs(f);
    	    }
    	    if( f < 1.0 )
    	    {
    	        return ( ( 12 - 9 * B - 6 * C ) * ( f * f * f ) +
    	            ( -18 + 12 * B + 6 *C ) * ( f * f ) +
    	            ( 6 - 2 * B ) ) / 6.0;
    	    }
    	    else if( f >= 1.0 && f < 2.0 )
    	    {
    	        return ( ( -B - 6 * C ) * ( f * f * f )
    	            + ( 6 * B + 30 * C ) * ( f *f ) +
    	            ( - ( 12 * B ) - 48 * C  ) * f +
    	            8 * B + 24 * C)/ 6.0;
    	    }
    	    else
    	    {
    	        return 0.0;
    	    }
    	} 
    
    	@Override
    	public BufferedImage filter(BufferedImage src, BufferedImage dest) {
    		int width = src.getWidth();
    		int height = src.getHeight();
    
    		if (dest == null)
    			dest = createCompatibleDestImage(src, null);
    
    		int[] inPixels = new int[width * height];
    		int[] outPixels = new int[destH * destW];
    		getRGB(src, 0, 0, width, height, inPixels);
    		float rowRatio = ((float) height) / ((float) destH);
    		float colRatio = ((float) width) / ((float) destW);
    		int index = 0;
    		for (int row = 0; row < destH; row++) {
    			int ta = 0, tr = 0, tg = 0, tb = 0;
    			double srcRow = ((float) row) * rowRatio;
    			// 获取整数部分坐标 row Index
    			double j = Math.floor(srcRow);
    			// 获取行的小数部分坐标
    			double t = srcRow - j;
    			for (int col = 0; col < destW; col++) {
    				double srcCol = ((float) col) * colRatio;
    				// 获取整数部分坐标 column Index
    				double k = Math.floor(srcCol);
    				// 获取列的小数部分坐标
    				double u = srcCol - k;
    				double[] rgbData = new double[3];
    				double rgbCoffeData = 0.0;
    				for(int m=-1; m<3; m++)
    				{
    					for(int n=-1; n<3; n++)
    					{
    						int[] rgb = getPixel(j+m, k+n, width, height, inPixels);
    						double f1 = 0.0d;
    						double f2 = 0.0d;
    						if(type == TRIANGLE__INTERPOLATION)
    						{
    							f1  = triangleInterpolation( ((double) m ) - t );
    							f2 = triangleInterpolation ( -(( (double) n ) - u ) );	
    						}
    						else if(type == BELL__INTERPOLATION)
    						{
    							f1  = bellInterpolation( ((double) m ) - t );
    							f2 = bellInterpolation ( -(( (double) n ) - u ) );	
    						}
    						else if(type == BSPLINE__INTERPOLATION)
    						{
    							f1  = bspLineInterpolation( ((double) m ) - t );
    							f2 = bspLineInterpolation ( -(( (double) n ) - u ) );	
    						}
    						else
    						{
    							f1  = CatMullRomInterpolation( ((double) m ) - t );
    							f2 = CatMullRomInterpolation ( -(( (double) n ) - u ) );							
    						}
    						// sum of weight
    						rgbCoffeData += f2*f1;
    						// sum of the RGB values
    						rgbData[0] += rgb[0] * f2 * f1;
    						rgbData[1] += rgb[1] * f2 * f1;
    						rgbData[2] += rgb[2] * f2 * f1;
    					}
    				}
    				ta = 255;
    				// get Red/green/blue value for sample pixel
    				tr = (int) (rgbData[0]/rgbCoffeData);
    				tg = (int) (rgbData[1]/rgbCoffeData);
    				tb = (int) (rgbData[2]/rgbCoffeData);
    				index = row * destW + col;
    				outPixels[index] = (ta << 24) | (clamp(tr) << 16)
    						| (clamp(tg) << 8) | clamp(tb);
    			}
    		}
    		setRGB(dest, 0, 0, destW, destH, outPixels);
    		return dest;
    	}
    	
    	public int clamp(int value) {
    		return value > 255 ? 255 :
    			(value < 0 ? 0 : value);
    	}
    	
    	private int[] getPixel(double j, double k, int width, int height,
    			int[] inPixels) {
    		int row = (int) j;
    		int col = (int) k;
    		if (row >= height) {
    			row = height - 1;
    		}
    		if (row < 0) {
    			row = 0;
    		}
    		if (col < 0) {
    			col = 0;
    		}
    		if (col >= width) {
    			col = width - 1;
    		}
    		int index = row * width + col;
    		int[] rgb = new int[3];
    		rgb[0] = (inPixels[index] >> 16) & 0xff;
    		rgb[1] = (inPixels[index] >> 8) & 0xff;
    		rgb[2] = inPixels[index] & 0xff;
    		return rgb;
    	}
    	public BufferedImage createCompatibleDestImage(
    			BufferedImage src, ColorModel dstCM) {
            if ( dstCM == null )
                dstCM = src.getColorModel();
            return new BufferedImage(dstCM, 
            		dstCM.createCompatibleWritableRaster(destW, destH), 
            		dstCM.isAlphaPremultiplied(), null);
        }
    }
    
    执行效果:原图

    双立方插值放大以后:


    总结:

    基于这里三种方法实现的双立方插值以后图片跟原图像相比,都有一定模糊

    这里时候能够通过兴许处理实现图像锐化与对照度提升就可以得到Sharpen版本号

    当然也能够通过寻找更加合适的R(x)函数来实现双立方卷积插值过程时保留

    图像边缘与对照度。

    一定要包括转载

    版权声明:本文博主原创文章。博客,未经同意不得转载。

  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4823027.html
Copyright © 2011-2022 走看看