双三次插值的原理是将目标图像的每一个像素在原图像中对应点周围进行4x4=16个像素的加权,然后相加。本文主要介绍用C OpenCV实现图像双三次插值的算法,可供参考。
目录
前言1。图像双三次插值算法原理2。C OpenCV代码1。计算权重矩阵2。遍历插值3。测试和结果
前言
最近在学习一些传统的图像处理算法,比如传统的图像插值算法。传统的图像插值算法有邻接插值法、双线性插值法和双三次插值法,其中邻接插值法和双线性插值法在网上有详细的介绍,用c写的代码也有,但是网上虽然有很多关于双三次插值原理和相应代码的介绍,但大多都不是很详细。所以基于自己对原理的理解,写了图像双三次插值算法的c opencv代码,记录在这里。
一、图像双三次插值算法原理
第一,原理部分。双三次插值的原理是将目标图像的每一个像素在原图像中对应点周围进行4x4=16个像素的加权,然后相加。这里的加权是三次函数,这也是图像双三次插值算法名字的由来(个人猜测)。使用的三次函数如下图所示:
关键问题是这个三次函数的输入和输出分别代表什么。简单来说,输入就是原图中对应点周围4x4区域的坐标值,在0到2之间,输出就是这些点的横坐标或纵坐标的权重。四个横坐标和四个纵坐标,对应的乘法就是一个44的权重矩阵,然后用这个权重矩阵乘以并加上原图像对应的区域就可以得到目标图像点的像素。
下图可以帮助你更好的理解。
首先,u和v是什么?例如,对于100100的灰度图像,要将其放大到500500,其缩放因子sx=500/100=5,sy=500/100=5。现在目标图像是500x500,500x500的空格需要用原图像的100x100像素值填充。根据src_x=i/sx和src_y=j/sy,可以得到目标像素坐标(I,j)对应的原始图像像素坐标(src_x,src_y),是src_x和src_y的小数。
知道了u和v,就可以用u和v来计算双三次插值算法的权值。上面说了,三次函数的输入是原始图像中对应点周围的4x4区域相对于该点的坐标值。上图,横坐标上有四个输入,分别是1 u,U,1-u,2-U;纵坐标上还有四个输入,分别是1 v、5 V、1v和2v。根据三次函数计算出权重后,相互相乘就是对应的4x4大小的权重矩阵。
知道了如何求权重矩阵,就可以遍历整幅图像进行插值了。下面是根据我自己对原理的理解写的c opencv代码。代码没有优化,但是可以让大家直观的理解图像的双三次插值算法。
二、C++ OpenCV代码
1.计算权重矩阵
前面说过,权重矩阵是横坐标的四个输出和纵坐标的四个输出的乘积,所以只需要找到横坐标和纵坐标对应的八个输出值。
代码如下:
std:vectordouble getWeight(双c,双a=0.5)
{
//c为U和V,横坐标和纵坐标的输出计算方法相同。
STD:vector double temp(4);
temp[0]=1c;temp[1]=c;
temp[2]=1癈;temp[3]=2癈;
//y(x)=(a ^ 2)| x | * | x | * | x |-(a ^ 3)| x | * | x | 1 | x |=1
//y(x)=a | x | * | x | * | x |-5a | x | * | x | 8a | x |-4a 1 | x | 2
STD:vector double weight(4);
weight[0]=(a * pow(abs(temp[0])),3) - 5 * a * pow(abs(temp[0]),2)8 * a * ABS(temp[0])-4 * a);
weight[1]=(a 2) * pow(abs(temp[1]),3) - (a 3) * pow(abs(temp[1]),2)1;
weight[2]=(a 2) * pow(abs(temp[2]),3) - (a 3) * pow(abs(temp[2]),2)1;
weight[3]=(a * pow(abs(temp[3])),3) - 5 * a * pow(abs(temp[3]),2)8 * a * ABS(temp[3])-4 * a);
返回重量;
}
2.遍历插值
代码如下:
空的双三次(cv:Mat src,cv:Mat dst,int dst_rows,int dst_cols)
{
dst.create(dst_rows,dst_cols,src。type());
double sy=static _ cast double(dst _ rows)/static _ cast double(src。行);
double sx=static _ cast double(dst _ cols)/static _ cast double(src。cols);
简历:材料边框;
cv:copyMakeBorder(src,Border,1,1,1,1,cv:Border _ REFLECT _ 101);
//处理灰度图
if (src.channels()==1)
{
for(int I=1;I dst _ rows 1;我)
{
int src _ y=(I 0.5)/sy-0.5;//做了几何中心对齐
if(src _ y 0)src _ y=0;
if(src _ y src。rows-1)src _ y=src。第1行;
src _ y=1;
//目标图像点坐标对应原图点坐标的四个纵坐标
int i1=STD:floor(src _ y);
int I2=STD:ceil(src _ y);
int i0=i1-1;
int i3=I2 1;
double u=src _ y-static _ castin t64(i1);
STD:vector double weight _ x=getWeight(u);
for(int j=1;j dst _ cols 1;j)
{
int src _ x=(j 0.5)/sy-0.5;
if(src _ x 0)src _ x=0;
if(src _ x src。rows-1)src _ x=src。第1行;
src _ x=1;
//目标图像点坐标对应原图点坐标的四个横坐标
int J1=STD:floor(src _ x);
int J2=STD:ceil(src _ x);
int j0=J1-1;
intJBOY3乐队=J2 1;
double v=src _ x-static _ cast int 64(J1);
STD:vector double weight _ y=getWeight(v);
//目标点像素对应原图点像素周围4x4区域的加权计算(插值)
双pix=weight _ x[0]* weight _ y[0]* border。atuchar(i0,j0)weight _ x[1]* weight _ y[0]* border。atuchar(i0,j1)
权重_ x[2]*权重_ y[0]*边框。atuchar(i0,J2)weight _ x[3]* weight _ y[0]* border。atuchar(i0,j3)
权重_ x[0]*权重_ y[1]*边框。atuchar(i1,j0)weight _ x[1]* weight _ y[1]* border。atuchar(i1,j1)
权重_ x[2]*权重_ y[1]*边框。atuchar(i1,J2)weight _ x[3]* weight _ y[1]* border。atuchar(i1,j3)
权重_ x[0]*权重_ y[2]*边框。atuchar(I2,j0)weight _ x[1]* weight _ y[2]* border。atuchar(I2,j1)
权重_ x[2]*权重_ y[2]*边框。atuchar(I2,J2)weight _ x[3]* weight _ y[2]* border。atuchar(I2,j3)
权重_ x[0]*权重_ y[3]*边框。atuchar(i3,j0)weight _ x[1]* weight _ y[3]* border。atuchar(i3,j1)
权重_ x[2]*权重_ y[3]*边框。atuchar(i3,J2)weight _ x[3]* weight _ y[3]* border。atuchar(i3,JBOY3乐队);
if(pix 0)pix=0;
if(pix 255)pix=255;
dst.atuchar(i - 1,j-1)=static _ castuchar(pix);
}
}
}
//处理彩色图像
else if (src.channels()==3)
{
for(int I=1;I dst _ rows 1;我)
{
int src _ y=(I 0.5)/sy-0.5;
if(src _ y 0)src _ y=0;
if(src _ y src。rows-1)src _ y=src。第1行;
src _ y=1;
int i1=STD:floor(src _ y);
int I2=STD:ceil(src _ y);
int i0=i1-1;
int i3=I2 1;
double u=src _ y-static _ castin t64(i1);
STD:vector double weight _ y=getWeight(u);
for(int j=1;j dst _ cols 1;j)
{
int src _ x=(j 0.5)/sy-0.5;
if(src _ x 0)src _ x=0;
if(src _ x src。rows-1)src _ x=src。第1行;
src _ x=1;
int J1=STD:floor(src _ x);
int J2=STD:ceil(src _ x);
int j0=J1-1;
intJBOY3乐队=J2 1;
double v=src _ x-static _ cast int 64(J1);
STD:vector double weight _ x=getWeight(v);
cv:Vec3b pix;
pix[0]=权重_ x[0]*权重_ y[0]*边框。atcv:Vec3b(i0,j0)[0]weight _ x[1]* weight _ y[0]* border。atcv:Vec3b(i0,j1)[0]
权重_ x[2]*权重_ y[0]*边框。atcv:Vec3b(i0,J2)[0]weight _ x[3]* weight _ y[0]* border。atcv:Vec3b(i0,j3)[0]
权重_ x[0]*权重_ y[1]*边框。atcv:Vec3b(i1,j0)[0]weight _ x[1]* weight _ y[1]* border。atcv:Vec3b(i1,j1)[0]
权重_ x[2]*权重_ y[1]*边框。atcv:Vec3b(i1,J2)[0]weight _ x[3]* weight _ y[1]* border。atcv:Vec3b(i1,j3)[0]
权重_ x[0]*权重_ y[2]*边框。atcv:Vec3b(I2,j0)[0]weight _ x[1]* weight _ y[2]* border。atcv:Vec3b(I2,j1)[0]
权重_ x[2]*权重_ y[2]*边框。atcv:Vec3b(I2,J2)[0]weight _ x[3]* weight _ y[2]* border。atcv:Vec3b(I2,j3)[0]
权重_ x[0]*权重_ y[3]*边框。atcv:Vec3b(i3,j0)[0]weight _ x[1]* weight _ y[3]* border。atcv:Vec3b(i3,j1)[0]
权重_ x[2]*权重_ y[3]*边框。atcv:Vec3b(i3,J2)[0]weight _ x[3]* weight _ y[3]* border。atcv:Vec3b(i3,JBOY3乐队)[0];
pix[1]=权重_ x[0]*权重_ y[0]*边框。atcv:Vec3b(i0,j0)[1]weight _ x[1]* weight _ y[0]* border。atcv:Vec3b(i0,j1)[1]
权重_ x[2]*权重_ y[0]*边框。atcv:Vec3b(i0,J2)[1]weight _ x[3]* weight _ y[0]* border。atcv:Vec3b(i0,j3)[1]
权重_ x[0]*权重_ y[1]*边框。atcv:Vec3b(i1,j0)[1]weight _ x[1]* weight _ y[1]* border。atcv:Vec3b(i1,j1)[1]
权重_ x[2]*权重_ y[1]*边框。atcv:Vec3b(i1,J2)[1]weight _ x[3]* weight _ y[1]* border。atcv:Vec3b(i1,j3)[1]
权重_ x[0]*权重_ y[2]*边框。atcv:Vec3b(I2,j0)[1]weight _ x[1]* weight _ y[2]* border。atcv:Vec3b(I2,j1)[1]
权重_ x[2]*权重_ y[2]*边框。atcv:Vec3b(I2,J2)[1]weight _ x[3]* weight _ y[2]* border。atcv:Vec3b(I2,j3)[1]
权重_ x[0]*权重_ y[3]*边框。atcv:Vec3b(i3,j0)[1]weight _ x[1]* weight _ y[3]* border。atcv:Vec3b(i3,j1)[1]
权重_ x[2]*权重_ y[3]*边框。atcv:Vec3b(i3,J2)[1]weight _ x[3]* weight _ y[3]* border。atcv:Vec3b(i3,JBOY3乐队)[1];
pix[2]=权重_ x[0]*权重_ y[0]*边框。atcv:Vec3b(i0,j0)[2]weight _ x[1]* weight _ y[0]* border。atcv:Vec3b(i0,j1)[2]
权重_ x[2]*权重_ y[0]*边框。atcv:Vec3b(i0,J2)[2]weight _ x[3]* weight _ y[0]* border。atcv:Vec3b(i0,j3)[2]
权重_ x[0]*权重_ y[1]*边框。atcv:Vec3b(i1,j0)[2]weight _ x[1]* weight _ y[1]* border。atcv:Vec3b(i1,j1)[2]
权重_ x[2]*权重_ y[1]*边框。atcv:Vec3b(i1,J2)[2]weight _ x[3]* weight _ y[1]* border。atcv:Vec3b(i1,j3)[2]
权重_ x[0]*权重_ y[2]*边框。atcv:Vec3b(I2,j0)[2]weight _ x[1]* weight _ y[2]* border。atcv:Vec3b(I2,j1)[2]
权重_ x[2]*权重_ y[2]*边框。atcv:Vec3b(I2,J2)[2]weight _ x[3]* weight _ y[2]* border。atcv:Vec3b(I2,j3)[2]
权重_ x[0]*权重_ y[3]*边框。atcv:Vec3b(i3,j0)[2]weight _ x[1]* weight _ y[3]* border。atcv:Vec3b(i3,j1)[2]
权重_ x[2]*权重_ y[3]*边框。atcv:Vec3b(i3,J2)[2]weight _ x[3]* weight _ y[3]* border。atcv:Vec3b(i3,JBOY3乐队)[2];
for(int I=0;我是src。通道();我)
{
if(pix[I]0)pix=0;
if(pix[I]255)pix=255;
}
dst.atcv:Vec3b(i - 1,j-1)=static _ castcv:Vec3b(pix);
}
}
}
}
3. 测试及结果
int main()
{
cv:Mat src=cv:im read(' C:\ \ Users \ \ Echo \ \ Pictures \ \ Saved Pictures \ \ British。png’);
cv:Mat dst;
双三次(src,dst,309/0.5,338/0.5);
cv:imshow('灰色,dst);
cv:imshow('src ',src);
cv:等待键(0);
}
彩色图像(放大两倍)
以上就是C OpenCV实现图像双三次插值算法详解的详细内容,更多关于C OpenCV图像双三次插值算法的资料请关注我们其它相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。