【数字图像处理】简单粗暴介绍最近邻插值和双线性插值(附python实现)

news2024/11/23 22:09:14

目录

  • 前言
  • 最近邻插值
    • 理论与公式部分
    • 代码部分
    • 优缺点
  • 双线性插值
    • 理论与公式部分
    • 代码实现
    • 优缺点
  • 双三次内插

前言

最近邻插值和双线性插值是两种常见的用于图像处理的方法,主要是用于实现图像的放大和缩小。本文中将以最为简单粗暴的方式介绍两种方法的原理,以及底层的代码实现。

为什么需要有插值的存在呢?这是因为计算机中存储的数据都是离散的。假设有一个350×350的图片,现在我要将其放大两倍,即新图为750×750,。对于原图当中的每一个像素,可以将其像素值的坐标对应乘上2,将其映射到新图中(如对于点(150, 100),其在新图中的坐标为(300, 200))。

但是这样做就有一个问题,新图中的像素点显然是更多的,这就会导致很多点并不能在原图中找到完全对应的点,这是因为原图中的坐标是离散分布的(如新图中的(201, 101),按照映射比例应该为(100.5, 50.5),但这在原图中是不存在的)。因此就会导致像素点的丢失。所以我们就需要采用一些办法解决这个问题。

最近邻插值

理论与公式部分

最近邻插值是最好理解也是最好实现的一种方法。其基本思想是**在目标像素点上插入离对应原像素点最近的点的像素值,而不考虑图像可能的颜色变化。**这是什么意思呢?我们仍然根据前言中的例子分析。

对于目标图中的点(300, 200),其通过逆变换得到的值是真实存在于原图中的,此时不需要做处理,直接将原图点像素值给到目标点即可;而对于目标图中的点(201, 101),根据映射关系对其进行逆变换得到其在原图上的点是(100.5, 50.5),但是原图中并不存在这个像素点,不过可以根据四舍五入的规则,找到原图真实存在的像素点中,与目标点距离最近的点。最近邻插值的办法就是,选取与目标点距离最近的一个点,并将该点的像素值赋给目标点。 那么对于(100.5, 50.5),按照四舍五入的规则,其像素值就应该同原图中点(101, 51)一致。

根据以上思路,总结为数学公式如下:
s r c x = d s t x ∗ d s i z e x src_x=dst_x*dsize_x srcx=dstxdsizex s r c y = d s t y ∗ d s i z e y src_y=dst_y*dsize_y srcy=dstydsizey
其中, s r c x src_x srcx s r c y src_y srcy是原图中用于确定目标点像素值的坐标, d s t x dst_x dstx d s t y dst_y dsty是目标图中目标点的坐标,dsize分别是提前预设的水平、竖直两个方向的缩放比率。

上述思路是纯粹的数学思路,还没有考虑离散化的问题。实际的计算公式应该增加舍入思想:

s r c x = r o u n d ( d s t x ∗ d s i z e x ) src_x=round(dst_x*dsize_x) srcx=round(dstxdsizex) s r c y = r o u n d ( d s t y ∗ d s i z e y ) src_y=round(dst_y*dsize_y) srcy=round(dstydsizey)

代码部分

以下是代码实现:

# 设置缩放比率,依次为水平、竖直比率
dsize = (2, 2)  
  
# 最近邻插值 
def nearest_neighbor_interpolation(src_img, dsize):


    # 获取原图的宽高属性并计算目标图片的宽高 
    height, width = src_img.shape[:2]  
    dst_height = math.ceil(dsize[1] * height)  
    dst_width = math.ceil(dsize[0] * width)  
  
    # 创建新图 
    dst_img = np.zeros((dst_height, dst_width, 3), dtype=np.uint8)  
  
    # 遍历处理  
    for r in range(dst_height):  
        for c in range(dst_width):  
            # 根据最近点取值  
            src_r, src_c = round(r / dsize[1]), round(c / dsize[0])  
            # 防溢出处理  
            if src_r >= height:  
                src_r = height - 1  
            if src_c >= width:  
                src_c = width - 1  
            # 插值 
            dst_img[r, c] = img[src_r, src_c]

# 返回处理后图像 
    return dst_img

优缺点

最近邻插值的优点是思路简单,实现也很简单。但缺点就是确定目标点像素值时考虑因素太少,处理后的图片失真比较大,马赛克现象严重。这也就引入了接下来要说的双线性插值办法。

双线性插值

理论与公式部分

根据上述的分析不难知道,最近邻插值方法中,对于目标点像素值的选取仅仅采用与其最近的那个点作为参考,效果并不是很好。而双线性插值中对于目标点像素值的选取,综合考虑了离该点在原图中的映射点最近的4个点。

我们已经知道,对一个像素值待确定的目标点,按照原图和目标图像的映射关系计算,计算的结果肯定是浮点类型,但是图像的像素点索引必须是整数,所以这里求出的坐标可以认为是虚拟坐标,也就是不存在的。但可以确定的是,该点一定可以被四个确定的点围成的矩形框柱。这样就可以根据这四个已知点更加精细的计算出目标点的像素值。

具体的计算思路是什么呢?其实不过是最基本的方法,每个人初中都学过的知识,那就是直线方程。来看下面这张图,我们知道一条直线上任取两个点,这两个点的坐标之间一定满足某种恒定关系,这个关系就是斜率

Pasted image 20240925163010.png

图中显然存在关系 y 1 − y 0 x 1 − x 0 = y − y 0 x − x 0 {{y_1-y_0}\over{x_1-x_0}} = {{y-y_0}\over{x-x_0}} x1x0y1y0=xx0yy0
整理一下得到:
y = x 1 − x x 1 − x 0 y 0 + x − x 0 x 1 − x 0 y 1 y={{x_1-x}\over{x_1-x_0}}y_0+{{x-x_0}\over{x_1-x_0}}y_1 y=x1x0x1xy0+x1x0xx0y1这个式子告诉我们:在一条直线上,可以通过两个已知点的坐标就可以直接求出我们想要的任何点的坐标。

由一维的线性插值很容易拓展到二维图像的双线性插值,每次需要要经过三次一阶线性插值才能获得最终结果。

![[Pasted image 20240925164753.png]]

上图是一个二维双线性插值的定量俯视示意图 (点位稍有变动但不影响),我们换个顺序。先由像素坐标点 (x0, y0) 和 (x1, y0) 在 x 轴向作一维线性插值得到 f(x, y0)、由像素坐标点 (x0, y1) 和 (x1, y1) 在 x 轴向作一维线性插值得到 f(x, y1):
f ( x , y 0 ) = x 1 − x x 1 − x 0 f ( x 0 , y 0 ) + x − x 0 x 1 − x 0 f ( x 1 , y 0 ) f(x,y_0)={{x_1-x}\over{x_1-x_0}}f(x_0,y_0)+{{x-x_0}\over{x_1-x_0}}f(x_1,y_0) f(x,y0)=x1x0x1xf(x0,y0)+x1x0xx0f(x1,y0)
f ( x , y 1 ) = x 1 − x x 1 − x 0 f ( x 0 , y 1 ) + x − x 0 x 1 − x 0 f ( x 1 , y 1 ) f(x,y_1)={{x_1-x}\over{x_1-x_0}}f(x_0,y_1)+{{x-x_0}\over{x_1-x_0}}f(x_1,y_1) f(x,y1)=x1x0x1xf(x0,y1)+x1x0xx0f(x1,y1)

然后再由 (x, y0) 和 (x, y1) 在 y 轴向作一维线性插值得到插值点 (x, y) 的灰度值 f(x, y):
f ( x , y ) = y 1 − y y 1 − y 0 f ( x , y 0 ) + y − y 0 y 1 − y 0 f ( x , y 1 ) f(x,y)={{y_1-y}\over{y_1-y_0}}f(x,y_0)+{{y-y_0}\over{y_1-y_0}}f(x,y_1) f(x,y)=y1y0y1yf(x,y0)+y1y0yy0f(x,y1)
联立以上式子,就可以得到最终的表达式:
![[Pasted image 20240925165622.png]]

实际中,我们使用双线性插值的时候,在计算原图坐标时,如果单纯采用同最近邻插值一样的办法,会导致两幅图的几何中心并不重合。为了解决这个办法,可以将坐标计算公式修改为如下形式:
s r c x = ( d s t x + 0.5 ) ∗ d s i z e x − 0.5 src_x=(dst_x+0.5)*dsize_x-0.5 srcx=(dstx+0.5)dsizex0.5 s r c y = ( d s t y + 0.5 ) ∗ d s i z e y − 0.5 src_y=(dst_y+0.5)*dsize_y-0.5 srcy=(dsty+0.5)dsizey0.5

代码实现

# 双线性插值  
def bilinear_interpolation(src_img, dsize):
  # 获取原图的宽高属性并计算目标图片的宽高  
    height, width = src_img.shape[:2]  
    dst_height = math.ceil(dsize[1] * height)  
    dst_width = math.ceil(dsize[0] * width)  
  
    # 创建新图 
    dst_img = np.zeros((dst_height, dst_width, 3), dtype=np.uint8)  
  
    # 遍历处理
    for r in range(dst_height):  
        for c in range(dst_width):  
            # 计算原图中映射点的坐标  
            src_r = (r + 0.5) * height / dst_height - 0.5  
            src_c = (c + 0.5) * width / dst_width - 0.5  
            # 获取坐标整数部分  
            i, j = int(src_r), int(src_c)  
            # 检查边界  
            if i >= height - 1:  
                i = height - 2  
            if j >= width - 1:  
                j = width - 2  
            # 获取坐标浮点数部分  
            u, v = src_r - i, src_c - j  
            # 根据双线性插值法原理进行插值  
            value = (src_img[i, j] * (1 - u) * (1 - v) +  
                     src_img[i, j + 1] * (1 - u) * v +  
                     src_img[i + 1, j] * u * (1 - v) +  
                     src_img[i + 1, j + 1] * u * v)  
            # 防溢出处理
            value = np.clip(value, 0, 255)  
            dst_img[r, c] = value.astype(np.uint8)

# 返回处理后图像  
    return dst_img

优缺点

双线性插值法相比于最近邻插值,处理效果会更好,但是计算量会更大。不过如果底层进行一些计算优化的话,效率损耗几乎是可以忽略的。经过实测,本文中实现的双线性插值办法与opencv库中的resize方法处理图像效果非常类似,推测resize底层采用的方法就是双线性插值。不过自己写的方法效率方面慢了很多,应该是resize底层采取了很多加速的优化策略。

双三次内插

双三次内插是一种处理效果更好,但是复杂度更高的算法。它计算时考虑的最近邻点更多,高达16个点,这就使其在保留细节方面更加强大,但是效率也更慢。一般比较高端的商用图像处理软件如Photoshop会采用该方法作为标准内插方法。由于思路和实现较为复杂,感兴趣的读者可以自行查阅相关资料。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2164471.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

USB-CAN的使用说明

文章目录 前言一、USB-CAN模块二、产品特性三、引脚说明四、使用说明1.USB驱动安装2.CAN配置工具说明1. 菜单栏:2. 模式选择和收发数据显示:3. 数据发送4. 发送模式 五、AT指令设置参数六、硬件测试 前言 CAN总线协议:一种多主、串行通信协议…

淘客系统开发之卷轴模式系统源码功能分析

随着互联网技术的快速发展,电商行业不断创新,探索更加高效、有趣的用户参与机制。其中,卷轴模式作为一种新兴的商业模式,以其独特的积分兑换和任务系统,在淘客系统开发中得到了广泛应用。本文将从技术角度,…

汽车免拆诊断案例 | 2016 款宾利GT车仪表盘上的多个故障灯点亮

故障现象 一辆2016款宾利欧陆GT车,搭载CYCB发动机,累计行驶里程约为4.5万km。据车主反映,发动机偶尔无法起动,仪表盘上的多个故障灯点亮(图1)。此外,刮水器、电动车窗及空调等电器设备功能失效…

IDC 中国数据安全软件市场报告:顺应平台化趋势,打造综合性的数据安全平台

近期,IDC 发布了针对中国数据安全软件市场规模的预测报告——《中国数据安全软件市场预测,2024-2028》(Doc# CHC51601524,2024年9月)。该报告针对 2024-2028 年中国数据安全软件市场的规模、增长速度、驱动因素、阻碍因…

剧本杀全新体验:线上剧本杀发挥重要优势

剧本杀作为集游戏社交休闲为一体的消费方式,吸引了众多年轻人,让玩家在游戏中体验到各种角色,还能够满足社交需求。当下,剧本杀市场仍然在快速发展中! 剧本杀市场创新 不过,在多年的发展中,剧…

智谱清影 - CogVideoX-2b-部署与使用

🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 体验地址:[丹摩DAMODEL官网](https://www.damodel.com/console/overview) CogVideoX 简介本篇将详细介绍使用丹摩服务器部…

C++20中头文件compare的使用

<compare>是C20中新增加的头文件&#xff0c;此头文件是language support库的一部分。它包括&#xff1a;concepts、classes、customization point objects、functions。 1.concepts&#xff1a;三向比较运算符<>&#xff0c;目的是简化比对对象的过程&#xff0c;…

ant design vue中带勾选表格报Tree missing follow keys: ‘undefined‘解决方法

1、这里一定要给columns和data-source设置key即可。 <div><a-table:row-selection"rowSelection":dataSource"tableList":columns"columns":scroll"{ x: 100% }":pagination"false":loading"loading"&g…

戴尔R750 H755N raid卡数据盘改直通模式

1、重启机器进入配置模式&#xff0c;重启后按F2进入bios模式

计算机网络(九) —— Tcp协议详解

目录 一&#xff0c;关于Tcp协议 二&#xff0c;Tcp报头字段解析 2.0 协议字段图示 2.1 两个老问题 2.2 16位窗口大小 2.3 32位序号和确认序号 2.4 6个标记位 三&#xff0c;Tcp保证可靠性策略 3.1 确认应答机制&#xff08;核心&#xff09; 3.2 超时重传机制 3.3 …

最新最详细的Mastercam安装包下载安装教程(保姆级)

正如大家所熟悉的&#xff0c;Mastercam是一款基于PC平台的CAD/CAM软件&#xff0c;集二维绘图、三维实体造型、曲面设计、体素拼合、数控编程、刀具路径摸拟及真实感摸拟等多种功能于一身。 Mastercam发展至今有许多个版本&#xff0c;目前来说常用的版本有Mastercam V91、20…

Windows同时配置两个jdk环境变量

项目场景&#xff1a; Windows同时配置两个jdk环境变量 解压版那么可以更改JAVA_HOME的值&#xff0c;来决定使用哪个版本。安装版可以两个版本同时使用。 操作步骤 1、配置环境变量 在系统环境变量中添加两个环境变量&#xff0c;根据使用需求更改JAVA_HOME的值 2、修改ja…

mariadb实现冷备份与恢复操作案例(物理冷备份,周期性备份)详解

文章目录 前置环境一、物理冷备份1.备份2.恢复检查结果 补充&#xff1a; 周期性恢复操作 前置环境 主机ipmariadb1192.168.10.11mariadb2192.168.10.12 mairadb1操作 安装mariadb yum -y install mariadb-server启动mariadb systemctl start mariadb这里只是演示备份与恢复…

数据结构不再难懂:带你轻松搞定排序算法

数据结构入门学习&#xff08;全是干货&#xff09;——排序算法&#xff08;下&#xff09; 1 快速排序 1.1 算法概述 快速排序采用分而治之的策略&#xff0c;与归并排序相似。其核心在于选择一个主元&#xff08;pivot&#xff09;作为分割点。 分而治之 主元(pivot)>…

【病毒分析】新兴TOP2勒索软件!存在中国受害者的BianLian勒索软件解密原理剖析

1. 概述 近期&#xff0c;笔者在浏览网络中威胁情报信息的时候&#xff0c;发现美国halcyon.ai公司于2024年3月25日发布了一篇《Ransomware on the Move: LockBit, BianLian, Medusa, Hunters International》报告&#xff0c;此报告对当前勒索软件团伙的实力进行了排名&#…

裸土检测算法实际应用、裸土覆盖检测算法、裸土检测算法

裸土检测算法主要用于环境保护、农业管理、城市规划和土地管理等领域&#xff0c;通过图像识别技术来检测和识别地表上的裸露土壤。这种技术可以帮助管理者实时监控裸土面积&#xff0c;及时采取措施&#xff0c;防止水土流失、环境污染和生态退化。 一、技术实现 裸土检测算…

【第二轮通知】第二届网络、通信与智能计算国际会议(NCIC 2024)

NCIC 2024|第二届网络、通信与智能计算国际会议 2024年11月22日-25日 中国 | 北京 www.icncic.org 重要日期 二轮截稿时间&#xff1a;2024年10月15日 注册截止时间&#xff1a;2024年11月10日 会议日期&#xff1a;2024年11月22日-25日 第二届网络、通信与智能计算国际会…

ProgrammerAI—AI辅助编程学习指南

前言 随着AIGC&#xff08;AI生成内容&#xff09;技术的快速发展&#xff0c;诸如ChatGPT、MidJourney和Claude等大语言模型相继涌现&#xff0c;AI辅助编程工具正逐步改变程序员的工作方式。这些工具不仅可以加速代码编写、调试和优化过程&#xff0c;还能帮助解决复杂的编程…

【深度学习】注意力机制与自注意力机制详解

深度学习中的注意力机制/自注意力机制详解 1. 注意力机制的通俗理解2. 注意力和自注意力机制的区别3. 自注意力机制原理与计算流程3.1 引入自注意力机制的目的与思想3.2 从向量角度理解 [R1]3.3 从Self-Attention核心公式理解 [R3] 4. 多头自注意力机制&#xff08;Multi-head …

网络威慑战略带来的影响

文章目录 前言一、网络威慑的出现1、人工智能带来的机遇二、网络空间的威慑困境1、威慑概念的提出2、网络威慑的限度3、人类对网络威胁的认知变化4、网络空间的脆弱性总结前言 网络威慑是国家为应对网络空间风险和威胁而采取的战略。冷战时期核威慑路径难以有效复制至网络空间…