图像的三次B样条插值原理与C++实现
cac55 2024-10-12 02:29 40 浏览 0 评论
01 前言
前文我们讲过图像中最常用的三种插值算法:最邻近插值、双线性插值、双三次插值。
插值的本质,就是使用周围点的值来计算插值点的值,如下图所示,红点的值已知,黑点的值未知,那么通过一定算法,使用黑点周围红点的值来计算黑点的值,就是插值。
在图像中也是类似的,整型坐标点的像素值已知,浮点型坐标点的像素值未知,所以如果想求浮点型坐标点的像素值,则需要使用其周围整型坐标点的像素值来计算,如下图所示:
02 三次B样条插值原理
图像处理中几种常见的插值算法基本都是取浮点型坐标点周围的n*n个整型坐标点的像素值进行加权和,从而得到该浮点型坐标点的像素值,不同插值算法的主要区别在于权重计算方法,如下式(其中W为权重):
三次B样条插值与双三次插值的原理几乎一样,区别仅在于插值的基函数不一样,所以我们先来复习一下双三次插值原理。
如下图,假设想求图像中浮点型坐标点(x', y')的像素值。
双三次插值算法使用点(x', y')周围4*4个整型点的像素值来计算点(x', y')的像素值。如下式,其中I表示像素值,W表示权重。
权重W(i,j)的计算如下式,其中a取值范围-1~0之间,一般取固定值-0.5,p(i,j).x和p(i,j).y分别表示点p(i,j)的x坐标、y坐标。
上式中函数w(d)通常被称为双三次插值的基函数,三次B样条插值除了基函数与双三次插值不一样,其它都相同,其基函数如下:
03 几种常见插值算法的总结与比较
- 最邻近插值算法
最邻近插值取离浮点型坐标点的最近点像素值作为其像素值,也可以看成使用浮点型坐标点周围2*2个整型点的像素值来计算其像素值,不过只有最靠近的那个点权重为1,其余3个点权重系数都为0。
- 双线性插值算法
双线性插值与最邻近插值类似,同样使用浮点型坐标点周围2*2个整型点的像素值来计算其像素值,不过其周围每个整型点的权重都不为0。
- 双三次插值算法
双三次插值使用浮点型坐标点周围4*4个整型点的像素值来计算其像素值。
- 三次B样条插值算法
三次B样条插值除了基函数与双三次插值不一样,其它都相同。
下面我们取d从-2.5到2.5,数据点间隔0.01,分别画出以上几种插值算法的基函数曲线。从曲线可以知道,d越小,也即周围整型点越靠近插值点,那么该整型点的权重越大。从曲线平滑度来看:三次B样条插值>双三次插值>双线性插值>最邻近插值。
04 几种常见插值算法的代码实现
- 最近邻插值算法的代码实现
最邻近插值取离浮点型坐标点的最近点像素值作为其像素值,也即相当于对浮点型x、y坐标分别四舍五入,从而得到最近点的整型坐标。
//src--uchar型图像数据
//x_float--浮点型的x坐标
//y_float--浮点型的y坐标
uchar nearst_inner(Mat src, float x_float, float y_float)
{
int x = (int)(x_float + 0.5); //四舍五入
int y = (int)(y_float + 0.5); //四舍五入
return src.ptr<uchar>(y)[x];
}
- 双线性插值算法的代码实现
//基函数
float line_w_f(float x)
{
return (abs(x) <= 1) ? (1 - abs(x)) : 0;
}
//src--uchar型图像数据
//x_float--浮点型的x坐标
//y_float--浮点型的y坐标
uchar line_inner(Mat src, float x_float, float y_float)
{
int x = floor(x_float);
int y = floor(y_float);
float a0_0 = line_w_f(x - x_float) * line_w_f(y - y_float);
float a0_1 = line_w_f(x + 1 - x_float) * line_w_f(y - y_float);
float a1_0 = line_w_f(x - x_float) * line_w_f(y + 1 - y_float);
float a1_1 = line_w_f(x + 1 - x_float) * line_w_f(y + 1 - y_float);
float sum = src.ptr<uchar>(y)[x] * a0_0 + src.ptr<uchar>(y)[x + 1] * a0_1 + src.ptr<uchar>(y + 1)[x] * a1_0 + src.ptr<uchar>(y + 1)[x + 1] * a1_1;
return ((uchar)sum);
}
- 双三次插值算法的代码实现
//基函数
float cubic_w_f(float x, float a)
{
if (x <= 1)
{
return 1 - (a + 3) * x * x + (a + 2) * x * x * x;
}
else if (x < 2)
{
return -4 * a + 8 * a * x - 5 * a * x * x + a * x * x * x;
}
return 0.0;
}
//计算权重系数
void cal_cubic_coeff(float x, float y, float* coeff)
{
float u = x - floor(x) + 1;
float v = y - floor(y) + 1;
float a = -0.15;
float A[4];
A[0] = cubic_w_f(abs(u), a);
A[1] = cubic_w_f(abs(u - 1), a);
A[2] = cubic_w_f(abs(u - 2), a);
A[3] = cubic_w_f(abs(u - 3), a);
for (int s = 0; s < 4; s++)
{
float C = cubic_w_f(abs(v - s), a);
coeff[s * 4] = A[0] * C;
coeff[s * 4 + 1] = A[1] * C;
coeff[s * 4 + 2] = A[2] * C;
coeff[s * 4 + 3] = A[3] * C;
}
}
//双三次插值
uchar cubic_inner(Mat src, float x_float, float y_float, float a)
{
float coeff[16];
cal_cubic_coeff(x_float, y_float, coeff); //计算权重系数
float sum = 0.0;
int x0 = floor(x_float) - 1;
int y0 = floor(y_float) - 1;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
sum += coeff[i * 4 + j] * src.ptr<uchar>(y0 + i)[x0 + j];
}
}
return ((uchar)sum);
}
- 三次B样条插值算法的代码实现
//基函数
float bpline_w_f(float x)
{
if (x <= 1)
{
return 2.0/3.0 - (1.0 - x/2.0)*x*x;
}
else if (x > 1 && x <= 2)
{
return (2.0 - x) * (2.0 - x) * (2.0 - x) / 6.0;;
}
return 0.0;
}
//计算权重系数
void cal_bpline_coeff(float x, float y, float* coeff)
{
float u = x - floor(x) + 1;
float v = y - floor(y) + 1;
float A[4];
A[0] = bpline_w_f(abs(u));
A[1] = bpline_w_f(abs(u - 1));
A[2] = bpline_w_f(abs(u - 2));
A[3] = bpline_w_f(abs(u - 3));
for (int s = 0; s < 4; s++)
{
float C = bpline_w_f(abs(v - s));
coeff[s * 4] = A[0] * C;
coeff[s * 4 + 1] = A[1] * C;
coeff[s * 4 + 2] = A[2] * C;
coeff[s * 4 + 3] = A[3] * C;
}
}
//三次B样条插值
uchar bpline_inner(Mat src, float x_float, float y_float)
{
float coeff[16];
cal_bpline_coeff(x_float, y_float, coeff); //计算权重系数
float sum = 0.0;
int x0 = floor(x_float) - 1;
int y0 = floor(y_float) - 1;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
sum += coeff[i * 4 + j] * src.ptr<uchar>(y0 + i)[x0 + j];
}
}
return ((uchar)sum);
}
05 几种常见插值算法应用于图像缩放的结果对比
将以上几种插值算法分别应用于Lena图像的缩放,测试代码如下:
//src -- 输入图像
//dst -- 输出图像
//row_m -- 行的缩放倍数
//col_m -- 列的缩放倍数
//inner_type -- 插值类型 0:最邻近,1:双线性,2:双三次,3:三次B样条
void resize_img(Mat src, Mat& dst, float row_m, float col_m, int inner_type)
{
const int row = (int)(src.rows * row_m);
const int col = (int)(src.cols * col_m);
const float x_a = 1.0 / col_m;
const float y_a = 1.0 / row_m;
Mat dst_tmp = Mat::zeros(row, col, CV_8UC1);
if (inner_type == 0)
{
for (int i = 0; i < row; i++)
{
uchar* p = dst_tmp.ptr<uchar>(i);
float y = i * y_a;
for (int j = 0; j < col; j++)
{
float x = j * x_a;
p[j] = nearst_inner(src, x, y);
}
}
}
else if (inner_type == 1)
{
for (int i = 0; i < row; i++)
{
uchar* p = dst_tmp.ptr<uchar>(i);
float y = i * y_a;
for (int j = 0; j < col; j++)
{
float x = j * x_a;
p[j] = line_inner(src, x, y);
}
}
}
else if (inner_type == 2)
{
for (int i = 0; i < row; i++)
{
uchar* p = dst_tmp.ptr<uchar>(i);
float y = i * y_a;
for (int j = 0; j < col; j++)
{
float x = j * x_a;
p[j] = cubic_inner(src, x, y, -0.5);
}
}
}
else
{
for (int i = 0; i < row; i++)
{
uchar* p = dst_tmp.ptr<uchar>(i);
float y = i * y_a;
for (int j = 0; j < col; j++)
{
float x = j * x_a;
p[j] = bpline_inner(src, x, y);
}
}
}
dst_tmp.copyTo(dst);
}
//测试函数,调用以上图像缩放,并显示结果
void resize_img_test(void)
{
Mat img = imread("image/lena.png", CV_LOAD_IMAGE_GRAYSCALE);
float mul = 3.0; //宽和高的放大倍数都为3
Mat img_resize_nearst, img_resize_line, img_resize_cubic, img_resize_bpline;
resize_img(img, img_resize_nearst, mul, mul, 0);
resize_img(img, img_resize_line, mul, mul, 1);
resize_img(img, img_resize_cubic, mul, mul, 2);
resize_img(img, img_resize_bpline, mul, mul, 3);
imshow("img", img);
imshow("img_resize_nearst", img_resize_nearst); //最近邻
imshow("img_resize_line", img_resize_line); //双线性
imshow("img_resize_cubic", img_resize_cubic); //双三次
imshow("img_resize_bpline", img_resize_bpline); //三次B样条
waitKey();
}
运行以上代码,分别使用几种插值算法对Lena的宽、高都放大3倍,得到结果如下:
由以上结果可知放大图像之后:
- 马赛克现象:最近邻插值>双线性插值≥双三次插值>三次B样条插值
- 边缘锯齿现象:最近邻插值>双线性插值≥双三次插值>三次B样条插值
- 插值后模糊度:最近邻插值<双线性插值≤双三次插值<三次B样条插值
为了对比更明显一点,我们把Lena图像中帽子边缘区域截取出来对比:
相关推荐
- 高中生又来卷我们了!手搓 Android 浏览器,可高度定制+脚本支持
-
回想一下,你曾经的暑假,是怎么度过的?可能是无尽的娱乐时光,或者是懒洋洋的休息日。然而,对于这位Gitee上的高中生来说,他选择在这个暑假里独立开发一款Android浏览器——Vie浏览器,...
- 网页加载CAD图纸的两个方案对比说明(网页浏览编辑DWG)
-
一.说明梦想控件提供两种技术在网页中加载CAD图纸,一个是OCX技术方案,另一个是HTML5技术方案,它们各有优缺点,用户需根据实际情况进行选择,下边分别说明一下。1、ocx技术方案(1)OCX技术是...
- 前后端分离的开源在线考试系统调试实战
-
开篇在我们的教育生涯中,或多或少的都接触过在线考试系统。例如大学里最常见的各种软件考试,上机考试等,那么有没有开源的这样的系统呢?当然是有了,今天就来调试个开源的在线考试系统。本文重点是调试,因为很多...
- 网友:小松鼠长大了!UC浏览器推出18周年专版logo引热议
-
近日,互联网厂商logo更新再次引发热议。作为国内手机浏览器的代表性厂商,UC浏览器的标志性logo小松鼠悄然发生了变化,在网友中引发了关注和讨论。依照UC微博官方账号的说法,这个全新的形象是UC18...
- 超多案例!谷歌AI模型Nano Banana的5个实用+趣味玩法
-
再不用这个AI修图神器,你的同行明天就把订单抢光了。谷歌刚放出的NanoBanana,能在一张照片里把背景、姿势、衣服一次换完,脸还是那张脸。实测把地铁照改成海边大片,只用一句话,三秒出图,不用PS来...
- 2025年最佳Windows数据恢复软件解决方案前5名
-
您是否正在寻找互联网上排名前五的WindowsPC最佳数据恢复软件解决方案?其实,网上有很多工具可以恢复已删除的文件。但并非所有应用程序都值得使用。值得信赖的文件恢复工具可以帮助您快速检索丢失、删...
- 电脑数据恢复软件推荐:10个顶级数据恢复软件分享
-
在数字化的工作与生活中,电脑文件误删除的情况时有发生,这不仅会引发我们的焦虑情绪,更可能导致重要数据的丢失。不过,幸运的是,借助正确的数据恢复软件,我们仍有机会找回那些被误删的文件。10个顶级数据恢复...
- 更懂国内APP的开源智能体!感知定位推理中文能力全面提升
-
更懂国内APP的开源智能体!感知定位推理中文能力全面提升“帮我点外卖,别点到广告位。”一句话,说出了多少人对手机自动化的真实期待。浙大和美团刚扔出来的开源项目UItron,就是冲着这句吐槽来的——它真...
- 美光首家推出采用EUV技术的1γ DDR5 DRAM芯片
-
美光科技宣布已开始向部分生态系统合作伙伴和客户出货1γ(1-gamma)16GbitDDR5DRAM芯片。美光声称,它是第一个采用1-gamma(1γ)节点的公司,该节点指的是DRAM工艺技术的第...
- DDR4的PCB设计及仿真_ddr pcb
-
以下文章来源于鼎阳硬件智库,作者王彦武DDR4关键技术和方法分析1.1DDR4与DDR3不同之处相对于DDR3,DDR4首先在外表上就有一些变化,比如DDR4将内存下部设计为中间稍微突出,边缘变...
- DDR4和DDR5内存的性能差距有哪些?
-
DDR4和DDR5内存的性能差距主要体现在带宽、延迟、能效及未来扩展性上,以下是关键差异的总结及选择建议:1.带宽与频率DDR4:主流频率为2133MHz–3600MHz,带宽约25.6–30.2...
- DDR5内存一根和两根的区别,建议收藏观看。
-
大家好,我是海韵,DDR5内存条,单条和双条有什么区别,如何选择,DDR5单条和双条内存在性能上存在差距,单条内存保持在64个通道,但内部升级为32乘以2,虽然出口速度相同,但内部运行略有提升,...
- Kingston FURY叛逆者DDR5 RGB CUDIMM内存评测 强势突破9000MT/s!
-
【ZOL中关村在线原创评测】当8000MT/s从当年的液氮超频艰难达成,到如今XMP轻松开启,DDR5内存频率的极限探索似乎看不到终点。在早先,我们曾为大家带来KingstonFURY品牌的叛逆者D...
- SK海力士将在年内推出1bnm 32Gb DDR5内存颗粒
-
IT之家4月25日消息,据韩媒NEWSIS报道,SK海力士在今日的2024年一季度财报电话会议上表示将在年内推出1bnm32GbDDR5内存颗粒。32Gb颗粒意味着消费级的...
- DRAM史上最大代际倒挂继续:三星将延长DDR4生产期限至2026年
-
IT之家8月6日消息,韩媒TheElec今天(8月6日)发布博文,报道称三星决定延长DDR41zDRAM的生产期限至2026年,一方面在DRAM史上最大代际倒挂中进...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 如何绘制折线图 (52)
- javaabstract (48)
- 新浪微博头像 (53)
- grub4dos (66)
- s扫描器 (51)
- httpfile dll (48)
- ps实例教程 (55)
- taskmgr (51)
- s spline (61)
- vnc远程控制 (47)
- 数据丢失 (47)
- wbem (57)
- flac文件 (72)
- 网页制作基础教程 (53)
- 镜像文件刻录 (61)
- ug5 0软件免费下载 (78)
- debian下载 (53)
- ubuntu10 04 (60)
- web qq登录 (59)
- 笔记本变成无线路由 (52)
- flash player 11 4 (50)
- 右键菜单清理 (78)
- cuteftp 注册码 (57)
- ospf协议 (53)
- ms17 010 下载 (60)