机器视觉零基础入门:(三)图像上采样
本文介绍了图像上采样的原理与实现方法。首先解释了图像分辨率、上采样等基本概念,指出上采样是通过增加像素数量提升图像分辨率的过程。文章详细阐述了上采样的三个步骤:1)确定目标尺寸,建议采用整数倍放大;2)通过坐标映射公式计算目标像素在原图中的位置,强调像素中心化的重要性;3)使用插值算法填充新像素,重点讲解了最邻近插值和双线性插值两种方法及其数学原理。最后提供了Python代码实现,包括最邻近插值和
前言
本文先讲述图像的上采样,与之相对的下采样因为涉及到滤波的知识,会在图像滤波器结束之后继续更新。上采样的底层原理涉及到一些数学计算,如果是正常学习视觉知识,建议跟着文章的步骤过一遍计算思路。如果是辅助验证需要代码,仅需到文章最后自取即可。
一、名词介绍
在开始之前,我们先补充介绍几个视觉中常见的名词。
图像分辨率(Image Resolution):单位英寸内的像素点数。单位为PPI(Pixels Per Inch),通常叫做像素每英寸。
幅值(Amplitude):“某个物理量偏离‘基准值’的最大程度”。举个例子:假设我们现在以黑色(255)设为基准值,某个像素点的像素值是200,那么他的幅值为黑色基准值与像素点之间的差,即200。
上采样(Upsampling):通过增加图像像素数量,提高图像分辨率。比如一张图像是512×512,现在增加到1024×1024,即为上采样。
下采样(Downsampling):通过减少图像像素数量,降低图像分辨率的过程。比如一张图像是1024×1024,现在减少到512×512,即为下采样。
二、上采样
1.底层逻辑定义
上采样本质是 “通过算法增加图像的像素数量,将低分辨率图像(像素少、细节粗)转换为高分辨率图像(像素多、细节更连贯)” 的过程。需要注意的是,上采样的核心不是 “简单放大画面”,而是“为新增的空白像素填充‘符合原图像特征的合理信息”。简单来说,就是对现有图像进行内插值处理。整体步骤我们可以大致分成三步来进行。
(1)定尺寸
先明确 “要把低分辨率图像放大到多少像素”。这个要根据实际情况来定,但是有几点需要注意。
I:优先采用整数倍放大(如2倍、4倍),避免非整数倍导致像素位置错位,否则后续插值算法容易存在计算误差与细节失真;
II:结合原图像细节密度定尺寸:若原图细节少(如纯色图标),可适度放大;若原图模糊 / 噪声多,避免过度放大(如>4倍),防止生成假细节加重失真。
III:彩色图需确保 R、G、B 三通道同步放大,防止通道尺寸不一致引发颜色错位,破坏色彩准确性。
我们还是以经典的lenna图像为例:原图像是512×512像素,要上采样到1024×1024像素。
(2)找空位
我们定好目标尺寸了,现在我们需要的做的是,在一张512×512的找到我要填充的像素空格,使其扩充到1024×1024。
给每个 “像素空格” 算 “原图像对应位置”。对目标图像中每一个像素,用坐标公式算出它在原512×512图像中的 “理论对应坐标”,公式为:
其中srcX(Y)为原图像X(Y)坐标,dstX(Y)为目标图像X(Y)坐标,srcWidth为(原图像宽-1),dstWidth为(目标图像宽-1),srcHeight为(原图像高-1),dstHeight为(目标图像高-1)。
其中需要注意三点:
I:(原图像宽度 - 1)/(目标图像宽度 - 1) 是坐标映射的比例因子。
II:(原图像宽度 - 1)/(目标图像宽度 - 1)中的-1是因为图像像素坐标从 “0” 开始计数,而非从 “1” 开始。
III:为了让原始像素在新网格中保持对称位置,确保插值计算的准确性和结果的视觉一致性,避免图像偏移或失真。我们需要进行像素点中心化。那么为什么要做中心化处理,我们看图理解:
将一个3×3的图像进行上采样处理,得到一张6×6的图像。对比上采样时像素点中心化与不中心化的情况。中间做中心化的图像原始像素位于新网格对应区域中心,能保证插值计算时原始像素与周围新像素距离对称;右侧是不做中心化的上采样,原始像素处于新网格对应区域的非中心位置(如 (0,0) 在左上角),会导致原始像素与周围新像素距离不均,使上采样后图像出现偏移或视觉失真。那么怎么做像素点中心化处理?这边需要一个小的计算,如下:
由此我们可以得知,只需要在等式两边加上0.5,即可使变换前后图像对齐。
(3)填像素
上面的定尺寸和找空位是大部分上采样算法的通解,而不同算法的主要区别在于填像素这一步。在这边我们介绍两种常见的算法:最邻近插值、双线性插值。
I:最邻近插值:
在上面的基础上,最邻近插值就是给新像素 “选最近的原像素”。在刚才算的理论位置有一个问题,就是该位置可能是小数(比如算出来是 75.3、40.6),这时候不用复杂计算,直接把小数四舍五入取整 —— 比如 75.3≈75,40.6≈41,就选原图里 (75, 41) 这个像素当 “邻居”。“直接复制邻居的颜色”。如果原图 (75, 41) 是浅红色,就把1024×1024大图里 (150, 80) 这个新像素也填成浅红色,这一步就是 “填像素” 的核心,没有任何额外计算,纯复制。
II:双线性插值:
在讲解双线性插值之前,我们先来看看单线性插值。如图所示,在这样的一个绿色三角形中,我们已知x0,y0和x1,y1的位置,对于三角形中,任意x,y,我们都能根据相似三角形的定理推导出最后y的表达式。
再来看双线性插值,所谓双线性,即进行两次单线性。双线性插值计算过程如下:
这里的f(x,y)即为该像素点的像素值。
三、代码实现
1.最邻近插值
import cv2
import numpy as np
def nearest_interpolation(src):
height, width, channels = src.shape
dst_img = np.zeros((1024, 1024, channels), np.uint8)
# 计算缩放比例
scale_h = height / 1024
scale_w = width / 1024
# 遍历目标图像
for i in range(1024):
for j in range(1024):
x = (i + 0.5) * scale_h - 0.5
y = (j + 0.5) * scale_w - 0.5
# 注意,在python中,int(),是转为整型,向下取整,为了达到四舍五入的效果,我们需要在后面加上0.5。
x = int(i * scale_h + 0.5)
y = int(j * scale_w + 0.5)
# 防止越界
x = min(max(x, 0), height - 1)
y = min(max(y, 0), width - 1)
dst_img[i, j] = src[x, y]
return dst_img
src = cv2.imread("lenna.png")
dst = nearest_interpolation(src)
cv2.imshow("nearest_interpolation", dst)
cv2.imshow("image", src)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.双线性插值
import numpy as np
import cv2
def bilinear_interpolation(img, out_dim):
src_h, src_w, channel = img.shape
dst_h, dst_w = out_dim[1], out_dim[0]
dst_img = np.zeros((dst_h, dst_w, 3), dtype=np.uint8)
scale_w, scale_h = float(src_w) / dst_w, float(src_h) / dst_h
for i in range(channel):
for dst_y in range(dst_h):
for dst_x in range(dst_w):
src_x = (dst_x + 0.5) * scale_w - 0.5
src_y = (dst_y + 0.5) * scale_h - 0.5
src_x0 = int(np.floor(src_x))
src_x1 = min(src_x0 + 1, src_w - 1)
src_y0 = int(np.floor(src_y))
src_y1 = min(src_y0 + 1, src_h - 1)
# 按照公式来,双线性插值计算
temp0 = (src_x1 - src_x) * img[src_y0, src_x0, i] + (src_x - src_x0) * img[src_y0, src_x1, i]
temp1 = (src_x1 - src_x) * img[src_y1, src_x0, i] + (src_x - src_x0) * img[src_y1, src_x1, i]
dst_img[dst_y, dst_x, i] = int((src_y1 - src_y) * temp0 + (src_y - src_y0) * temp1)
return dst_img
if __name__ == '__main__':
src = cv2.imread('lenna.png')
dst = bilinear_interpolation(src, (1024, 1024))
cv2.imshow('bilinear_interpolation', dst)
cv2.imshow("image", src)
cv2.waitKey()
cv2.destroyAllWindows()
总结
上采样在工程中应用广泛,核心是将低分辨率数据提升至更高分辨率以满足需求:比如计算机视觉领域用于图像显示适配、目标检测预处理及医学影像细节增强;多媒体与游戏领域实现画质修复、实时渲染优化;工业检测中助力微小缺陷识别。上述为比较常见的两种上采样算法,除此以外还有很多类似的算法,例如双三次插值、样条插值、Lanczos插值等等,本文就不一一介绍了。
(总目录跳转链接)
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)