1. 图片缩小

比例缩放前后两点 \(P_0(x_0, y_0)\)\(P(x,y)\) 之间的关系用矩阵形式可以表示为

\[\left[\begin{matrix} x \\ y \\ 1 \end{matrix}\right] = \left[\begin{matrix} f_x & 0 & 0\\ 0 & f_y & 0\\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_0 \\ y_0 \\ 1 \end{matrix}\right] \]

在数字图像中,图像缩小是通过减少像素个数实现,关键在于怎么去掉一部分像素点,而尽可能保持原有图像的概貌特征。下面介绍两种简单的图像缩小技术。
为了理解算法,应该先把图像想成是连续的,然后再四舍五入取离散值。比如计算后得出,缩小后的图像点 \((2,2)\) 的像素值与原图像 \((2.1, 2.8)\) 处相等,就四舍五入取原图像 \((2,3)\) 处的坐标。
为了便于叙述,放大或缩小前的图像为原图像 \(R\),可理解为单词 \(raw\),放大或缩小后的图像为新图像 \(S\)\(R\)的后面一个字母。

  • 最近邻采样
    原图像为 \(R(x, y)\),新图像为 \(S(x, y)\),设原图像和新图像 \(x\) 方向和 \(y\) 方向比例分别为 \(r_x, r_y\),这个 \(r_x, r_y\) 也可以看作是下采样的采样间隔。
    为了方便理解缩小,把原图像看作是新图像的放大,则新图像在 \((x,y)\) 处的灰度值 \(S(x,y)\),有

\[S(x,y) = R(r_x\cdot x, r_y\cdot y) \]

如果 \(r_x\cdot x\) 算出来是小数,四舍五入即可,其余同理。其实新图像的坐标

  • 局部平均值采样
    找出两次采样间的子块,然后求平均值为当前像素值。比如原图像大小为 \(4\times 4\),要缩小为 \(2\times 2\),则缩小后图像 \((1,1)\) 的值就是原图像的左上角的 \(2\times 2\) 的局部单元像素的平均值。对于小数也差不多,四舍五入。在实际编程中,都是直接调用函数,不必为各种繁琐的四舍五入操心。

2. 图像放大

  • 最近邻采样
    和上面所述的差不多,举例说明。比如原来 \(10\times 10\) 的图片,放大到 \(15\times 15\),即放大了 \(1.5\) 倍,要计算新图像在 \((10, 11)\), 则对应原图像 \((10/1.5, 11/1.5)=(6.7, 7.3)\) 处的像素值,四舍五入取整原图像 \((7, 7)\) 处的像素值即可。

  • 线性插值法
    线性插值法就是找周围最近的几个点,线性组合取值。举个简单的例子说明。和刚刚的最近邻采样条件一样,也求 \((10,11)\) 处的坐标。上面求处该坐标对应原图像 \(R(6.7, 7.3)\) 处的值,此时应找距离 \(R(6.7, 7.3)\) 最近的几个点,即 \((6,7), (6,8), (7,7), (7,8)\) 四点加权来算新图像的像素值,距离近则权值大。大家可以自己在纸上画个图,可以先看 \(x\) 方向,再看 \(y\) 方向。
    \(x\) 方向,根据距离远的权值小,有:

\[R(6.7,y) = (1-0.7)R(6,y) + 0.7R(7,y) \]

则可以算出 \(R(6.7, 7)\), \(R(6.7, 8)\)。再次使用加权可求 \(R(6.7, 7.3)\)
即有:

\[R(6.7, 7.3) = (1-0.3)R(6.7, 7) + 0.3R(6.7, 8) \]

最终算出原图像 \(R(6.7, 7.3)\) 处的像素值,也即新图像 \((10,11)\) 处的像素值。

OpenCv实战

直接用 resize 函数即可实现放大缩小。

cv.resize(img, dsize, [interpolation])
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

def show(img):
    plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB), cmap='gray', vmin=0, vmax=255)
    plt.show()

img = cv.imread('pic/rabbit50x33.jpg') # 路径更换成新的图片
img_resize1 = cv.resize(img, (330, 500), interpolation=cv.INTER_NEAREST)
img_resize2 = cv.resize(img, (330, 500), interpolation=cv.INTER_LINEAR)

show(img)
show(np.hstack([img_resize1, img_resize2]))

说明:

  1. 未经许可,谢绝转载。
  2. 本教程为《数字图像处理Python OpenCV实战》的配套代码相关内容。
    免费视频教程为0-6章(标题号≤6),可在此处点击观看。
    所有课件及源代码可在此处下载:
    链接:https://pan.baidu.com/s/198PySe_vebO3e06idHSQ6g
    提取码:11o4
    有问题可在QQ群(1079300899)指出,进群答案:数字图像处理。