图像的放大:双三次插值算法(C++实现)

双线性插值算法的不足就是细节处理的不好,换句话说,就是曲线拟合得不够光滑,所以又有了双三次插值算法。双三次插值算法是基于周围的16个像素点,通过计算16个像素点的权重,累积得到增加点的像素值的。
图像的放大:双三次插值算法(C++实现)_第1张图片
简单点理解,公式如下:
p = f ( u , v ) = ∑ i = 0 3 ∑ j = 0 3 w i j x i y j p=f(u,v)=\sum_{i=0}^{3}\sum_{j=0}^{3}w_{ij}x_{i}y_{j} p=f(u,v)=i=03j=03wijxiyj
(u,v)为所插入点的坐标,(x,y)为周围16个像素点的坐标。本算法的重点和难点就是权重w的值如何获取。我们取其中的x方向(横轴)分析, w x i w_{xi} wxi的取值如下公式所示:
w x i = { ( a + 2 ) ∣ x i − u ∣ 3 − ( a + 3 ) ∣ x i − u ∣ 2 + 1 f o r ∣ x i − u ∣ ≤ 1 a ∣ x i − u ∣ 3 − 5 a ∣ x i − u ∣ 2 + 8 a ∣ x i − u ∣ − 4 a f o r 1 < ∣ x i − u ∣ < 2 0 o t h e r w i s e w_{xi}=\left\{\begin{matrix} (a+2)\left | x_i-u \right |^{3}-(a+3)\left | x_i-u \right |^{2}+1 & for & \left | x_i-u \right |\leq 1\\ a\left | x_i-u \right |^{3}-5a\left | x_i-u \right |^{2}+8a\left | x_i-u \right |-4a & for &1< \left | x_i-u \right |< 2 \\ 0 &otherwise \end{matrix}\right. wxi=(a+2)xiu3(a+3)xiu2+1axiu35axiu2+8axiu4a0forforotherwisexiu11<xiu<2
同理,也可以得到 w y j w_{yj} wyj,则可以得到权重的表达式如下公式所示:
w i j = w x i × w y j w_{ij}=w_{xi}\times w_{yj} wij=wxi×wyj
c++代码实现:
"bmp.h"的头文件代码:bmp图片的类以及读写函数 bmp.h

#include 
#include    
#include        
#include      
#include   
#include 
#include "bmp.h"
using namespace std;
#define DRAW_HEIGHT 512  //目标图像高度  
#define DRAW_WIDTH 512  //目标图像宽度  
double a=-0.5; //BiCubic基函数

void getW_x(double w_x[4],double x);
void getW_y(double w_y[4], double y);

int main()
{
    BMP rbmp;
    BMP wbmp(DRAW_WIDTH,DRAW_HEIGHT);
	char strFile[50] = "./lena24.bmp";//打开图像路径,BMP图像必须为24位真彩色格式  
	char strFilesave[50] = "./test.bmp";//处理后图像存储路径 
    //读取位图的数据 
    imread(strFile,rbmp);
    int width = rbmp.cols();
	int height = rbmp.rows(); 
	int l_width = WIDTHBYTES(width*24);//计算位图的实际宽度并确保它为4byte的倍数  
    //写位图的数据
    int write_width = WIDTHBYTES(DRAW_WIDTH*24);//计算写位图的实际宽度(字节)并确保它为4byte的倍数   
	/*******************图像处理部分******************/
    for (int hnum = 2; hnum < DRAW_HEIGHT-4; hnum++)
	{
    	for (int wnum = 2; wnum < DRAW_WIDTH-4; wnum++)
		{
			double d_original_img_hnum = hnum*height / (double)DRAW_HEIGHT;
			double d_original_img_wnum = wnum*width / (double)DRAW_WIDTH;
			int i_original_img_hnum = d_original_img_hnum;//距离最近的点坐标
			int i_original_img_wnum = d_original_img_wnum;//距离最近的点坐标
            double w_x[4], w_y[4];//行列方向的加权系数
            getW_x(w_x, d_original_img_hnum);
            getW_y(w_y, d_original_img_wnum);
            int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量  

            for(int i=0;i<4;i++)
            {
                for(int j=0;j<4;j++)
                {
                    int original_point=(i_original_img_hnum+i-1)*l_width + (i_original_img_wnum+j-1)*3;
                    wbmp.pColorData[pixel_point]+=rbmp.pColorData[original_point]*w_x[i]*w_y[j];
                    wbmp.pColorData[pixel_point + 1]+=rbmp.pColorData[original_point+1]*w_x[i]*w_y[j];
                    wbmp.pColorData[pixel_point + 2]+=rbmp.pColorData[original_point+2]*w_x[i]*w_y[j];
                }
            }
		}
    }
	/*******************图像处理部分******************/
    std::cout<<"Done!"<<std::endl;
    imwrite(strFilesave,wbmp); 
    system("pause"); 
    return 0;
}
/*计算系数*/
void getW_x(double w_x[4],double x){
    int X = (int)x;//取整数部分
    double stemp_x[4];
    stemp_x[0] = 1 + (x - X);
    stemp_x[1] = x - X;
    stemp_x[2] = 1 - (x - X);
    stemp_x[3] = 2 - (x - X);

    w_x[0] = a*abs(stemp_x[0] * stemp_x[0] * stemp_x[0]) - 5 * a*stemp_x[0] * stemp_x[0] + 8 * a*abs(stemp_x[0]) - 4 * a;
    w_x[1] = (a + 2)*abs(stemp_x[1] * stemp_x[1] * stemp_x[1]) - (a + 3)*stemp_x[1] * stemp_x[1] + 1;
    w_x[2] = (a + 2)*abs(stemp_x[2] * stemp_x[2] * stemp_x[2]) - (a + 3)*stemp_x[2] * stemp_x[2] + 1;
    w_x[3] = a*abs(stemp_x[3] * stemp_x[3] * stemp_x[3]) - 5 * a*stemp_x[3] * stemp_x[3] + 8 * a*abs(stemp_x[3]) - 4 * a;
}
void getW_y(double w_y[4], double y){
    int Y = (int)y;
    double stemp_y[4];
    stemp_y[0] = 1.0 + (y - Y);
    stemp_y[1] = y - Y;
    stemp_y[2] = 1 - (y - Y);
    stemp_y[3] = 2 - (y - Y);

    w_y[0] = a*abs(stemp_y[0] * stemp_y[0] * stemp_y[0]) - 5 * a*stemp_y[0] * stemp_y[0] + 8 * a*abs(stemp_y[0]) - 4 * a;
    w_y[1] = (a + 2)*abs(stemp_y[1] * stemp_y[1] * stemp_y[1]) - (a + 3)*stemp_y[1] * stemp_y[1] + 1;
    w_y[2] = (a + 2)*abs(stemp_y[2] * stemp_y[2] * stemp_y[2]) - (a + 3)*stemp_y[2] * stemp_y[2] + 1;
    w_y[3] = a*abs(stemp_y[3] * stemp_y[3] * stemp_y[3]) - 5 * a*stemp_y[3] * stemp_y[3] + 8 * a*abs(stemp_y[3]) - 4 * a;
}

效果图:
图像的放大:双三次插值算法(C++实现)_第2张图片
图像的放大:双三次插值算法(C++实现)_第3张图片
参考:图像缩放之双三次插值法

你可能感兴趣的:(图像处理,c/c++)