插值方法
在图像处理和计算机图形学中,插值(Interpolation)是一种通过已知数据点之间的推断或估计来获取新数据点的方法。它在图像处理中常用于处理图像的放大、缩小、旋转、变形等操作,以及处理图像中的像素值。
图像插值算法是为了解决图像缩放或者旋转等操作时,由于像素之间的间隔不一致而导致的信息丢失和图像质量下降的问题。当我们对图像进行缩放或旋转等操作时,需要在新的像素位置上计算出对应的像素值,而插值算法的作用就是根据已知的像素值来推测未知位置的像素值。
最近邻插值
cv2.INTER_NEAREST
目标点与原图像点之间成比例
语法格式:new_img1=cv.warpAffine(img,M,(w,h),flags=cv.INTER_NEAREST)
最近邻插值的原则是:目标像素点的像素值与经过该公式计算出来的对应的像素点的像素值相同,如出现小数部分需要进行取整。
双线性插值
cv2.INTER_LINEAR
双线性插值是一种图像缩放、旋转或平移时进行像素值估计的插值方法。当需要对图像进行变换时,特别是尺寸变化时,原始图像的某些像素坐标可能不再是新图像中的整数位置,这时就需要使用插值算法来确定这些非整数坐标的像素值。
双线性插值的工作原理是这样的:
-
假设要查找目标图像上坐标为
(x', y')
的像素值,在原图像上对应的浮点坐标为(x, y)
。 -
在原图像上找到四个最接近
(x, y)
的像素点,通常记作P00(x0, y0)
,P01(x0, y1)
,P10(x1, y0)
,P11(x1, y1)
,它们构成一个2x2的邻域矩阵。 -
分别在水平方向和垂直方向上做线性插值:
-
水平方向:根据
x
与x0
和x1
的关系计算出P00
和P10
、P01
和P11
之间的插值结果。 -
垂直方向:将第一步的结果与
y
与y0
和y1
的关系结合,再在垂直方向上做一次线性插值。
- 综合上述两次线性插值的结果,得到最终位于
(x', y')
处的新像素的估计值。
总结: 4乘4的图像 变成6乘6的图像 那么目标图像的(3,3)点的像素是原图中(1.8333,1.8333)的像素颜色,但是坐标必须是整数 它周围有四个像素点 该取谁呢? 按照到各自的距离比例 来分配颜色值

像素区域插值
cv2.INTER_AREA
像素区域插值主要分两种情况,缩小图像和放大图像的工作原理并不相同。
- 当使用像素区域插值方法进行缩小图像时,它就会变成一个均值滤波器(滤波器其实就是一个核,这里只做简单了解,后面实验中会介绍),其工作原理可以理解为对一个区域内的像素值取平均值。
-
当使用像素区域插值方法进行放大图像时
-
如果图像放大的比例是整数倍,那么其工作原理与最近邻插值类似;
-
如果放大的比例不是整数倍,那么就会调用双线性插值进行放大。
-
双三次插值
cv2.INTER_CUBIC
与双线性插值法相同,该方法也是通过映射,在映射点的邻域内通过加权来得到放大图像中的像素值。不同的是,双三次插值法需要原图像中近邻的16个点来加权,也就是4x4的网格。
BiCubic基函数也就是双三次插值的权重函数,它决定了如何根据距离对周围像素进行加权平均。
假设原图像A大小为m*n,缩放后的目标图像B的大小为M*N。其中A的每一个像素点是已知的,B是未知的,我们想要求出目标图像B中每一个像素点(X,Y)的值,必须先找出像素(X,Y)在原图像A中对应的像素(x,y),再根据原图像A距离像素(x,y)最近的16个像素点作为计算目标图像B(X,Y)处像素值的参数,利用BiCubic基函数求出16个像素点的权重,图B像素(x,y)的值就等于16个像素点的加权叠加。

我们要做的就是将上面的16个点相较于p点的位置距离算出来,获取16像素所对应的权重W(d)。
Lanczos插值
cv2.INTER_LANCZOS4
Lanczos插值方法与双三次插值的思想是一样的,不同的就是其需要的原图像周围的像素点的范围变成了8*8,并且不再使用BiCubic函数来计算权重,而是换了一个公式计算权重。
小结:
最近邻插值的计算速度最快,但是可能会导致图像出现锯齿状边缘和失真,效果较差。双线性插值的计算速度慢一点,但效果有了大幅度的提高,适用于大多数场景。双三次插值、Lanczos插值的计算速度都很慢,但是效果都很好。
在OpenCV中,关于插值方法默认选择的都是双线性插值,且一般情况下双线性插值已经能满足大部分需求。
边缘填充
边界复制(BORDER_REPLICATE)
边界复制会将边界处的像素值进行复制,然后作为边界填充的像素值,如下图所示,可以看到四周的像素值都一样。
语法格式:
new_img=cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,
borderMode=cv.BORDER_REPLICATE)
边界反射(BORDER_REFLECT)
语法格式:
new_img=cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_REFLECT)
会根据原图的边缘进行反射。

边界反射101(BORDER_REFLECT_101)
与边界反射不同的是,不再反射边缘的像素点。

边界常数(BORDER_CONSTANT)
当选择边界常数时,还要指定常数值是多少,默认的填充常数值为0
边界包裹(BORDER_WRAP)

语法格式:
new_img=cv.warpAffine(img,M,(w,h),cv.INTER_LANCZOS4,borderMode=cv.BORDER_WRAP)
图像色彩空间转换
OpenCV中,图像色彩空间转换是一个非常基础且重要的操作,就是将图像从一种颜色表示形式转换为另一种表示形式的过程。通过将图像从一个色彩空间转换到另一个色彩空间,可以更好地进行特定类型的图像处理和分析任务。常见的颜色空间包括RGB、HSV、YUV等。
RGB颜色空间

注意:在OpenCV中,颜色是以BGR的方式进行存储的,而不是RGB,这也是上面红色的像素值是(0,0,255)而不是(255,0,0)的原因。
颜色加法
你可以使用OpenCV的cv.add()函数把两幅图像相加,或者可以简单地通过numpy操作添加两个图像,如res = img1 + img2。两个图像应该具有相同的大小和类型。
OpenCV加法和Numpy加法之间存在差异。OpenCV的加法是饱和操作,而Numpy添加是模运算。
示例:
pig = cv.imread('./images/pig.png')
pig1 = cv.resize(pig,(480,480))
cao = cv.imread('./images/cao.png')
cao1 = cv.resize(cao,(480,480))
# add()函数
img = cv.add(pig1,cao1)
cv.imshow('img',img)
颜色加权加法
cv2.addWeighted(src1,alpha,src2,deta,gamma)
-
src1
、src2
:输入图像。 -
alpha
、beta
:两张图象权重。 -
gamma
:亮度调整值。
这其实也是加法,但是不同的是两幅图像的权重不同,这就会给人一种混合或者透明的感觉。
示例:现在我们把两幅图混合在一起。第一幅图的权重是0.7,第二幅图的权重是0.3。
# 颜色加权加法 cv.addweighted()
img2 = cv.addWeighted(pig,0.7,cao,0.3,0)
HSV颜色空间
HSV颜色空间指的是HSV颜色模型,这是一种与RGB颜色模型并列的颜色空间表示法。RGB颜色模型使用红、绿、蓝三原色的强度来表示颜色,是一种加色法模型,即颜色的混合是添加三原色的强度。而HSV颜色空间使用色调(Hue)、饱和度(Saturation)和亮度(Value)三个参数来表示颜色,色调H表示颜色的种类,如红色、绿色、蓝色等;饱和度表示颜色的纯度或强度,如红色越纯,饱和度就越高;亮度表示颜色的明暗程度,如黑色比白色亮度低。
一般对颜色空间的图像进行有效处理都是在HSV空间进行的,然后对于基本色中对应的HSV分量需要给定一个严格的范围,下面是通过实验计算的模糊范围(准确的范围在网上都没有给出)。
色调H: 0--- 180
饱和度S: 0--- 255
亮度V: 0--- 255
为什么有了RGB颜色空间我们还是需要转换成HSV颜色空间来进行图像处理呢?
-
符合人类对颜色的感知方式:人类对颜色的感知是基于色调、饱和度和亮度三个维度的,而HSV颜色空间恰好就是通过这三个维度来描述颜色的。因此,使用HSV空间处理图像可以更直观地调整颜色和进行色彩平衡等操作,更符合人类的感知习惯。
-
颜色调整更加直观:在HSV颜色空间中,色调、饱和度和亮度的调整都是直观的,而在RGB颜色空间中调整颜色不那么直观。例如,在RGB空间中要调整红色系的颜色,需要同时调整R、G、B三个通道的数值,而在HSV空间中只需要调整色调和饱和度即可。
-
降维处理有利于计算:在图像处理中,降维处理可以减少计算的复杂性和计算量。HSV颜色空间相对于RGB颜色空间,减少了两个维度(红、绿、蓝),这有利于进行一些计算和处理任务,比如色彩分割、匹配等。
因此,在进行图片颜色识别时,我们会将RGB图像转换到HSV颜色空间,然后根据颜色区间来识别目标颜色。
RGB转Gray(灰度)
cv2.cvtColor
是OpenCV中的一个函数,用于图像颜色空间的转换。可以将一个图像从一个颜色空间转换为另一个颜色空间,比如从RGB到灰度图,或者从RGB到HSV的转换等。
cv2.cvtColor(img,code)
-
img
:输入图像,可以是一个Numpy数组绘着一个OpenCV的Mat对象 -
code
:指定转换的类型,可以使用预定义的转换代码。