在本教程中,您将学习如何使用 OpenCV 和 cv2.resize 功能。
缩放或简单地调整大小是在宽度和高度方面增加或减小图像大小的过程。
调整图像大小时,重要的是要记住纵横比- 即图像的宽度与其高度的比率。忽略纵横比可能会导致调整大小的图像看起来压缩和扭曲:
在左边,我们有我们的原始图像。在右侧,我们有两张因不保留纵横比而失真的图像。它们已通过忽略图像的宽度与高度的比率来调整大小。
通常,您需要在调整大小时保留图像的纵横比——尤其是当这些图像作为输出呈现给用户时。不过,例外情况肯定适用。当我们探索机器学习/深度学习技术时,我们会发现我们的内部算法经常忽略图像的纵横比;但是一旦我们了解了计算机视觉的基础知识,就会有更多的了解。
我们还需要记住调整大小函数的插值方法。插值的正式定义是:
在一组离散的已知数据点的范围内构建新数据点的方法。
一般来说,减小图像的大小会更有益(并且在视觉上更吸引人)。这是因为插值函数只需从图像中删除像素。另一方面,如果我们要增加图像的尺寸,插值函数就必须“填补”以前不存在的像素之间的空隙。
例如,看一下下图中的图像:
在左边,我们有我们的原始图像。在中间,我们将图像大小调整为原来的一半——除了图像被调整大小之外,图像“质量”没有任何损失。但是,在右侧,我们显着增加了图像大小。它现在看起来“像素化”。
正如我上面提到的,您通常会减小图像的大小而不是增加(当然,例外情况确实适用)。通过减小图像尺寸,我们可以处理更少的像素(更不用说处理的“噪音”更少),这导致更快、更准确的图像处理算法。
请记住,虽然高分辨率图像在视觉上对人眼有吸引力,但它们会损害计算机视觉和图像处理管道:
在本教程的第一部分中,我们将配置我们的开发环境并查看我们的项目目录结构。
通过博文末尾或此处的的代码:下载.
下载本博文对应的代码项目,以下是下载解压后的项目结构:
我们的 opencv_resize.py 文件将加载输入 .png 图像,然后执行几个调整大小的操作,从而演示如何使用 OpenCV 的 cv2.resize 调整图像尺寸的功能。
使用 OpenCV 实现基本的图像大小调整
到目前为止,在本相关博文中,我已经介绍了两种图像变换:平移和旋转。现在,我们将探讨如何调整图像大小。
也许,毫不奇怪,我们使用 cv2.resize功能来调整我们的图像。正如我上面提到的,我们在使用这个函数时需要记住图像的纵横比。
第 7-10 行解析我们的命令行参数。我们只需要一个参数,- image,即我们要调整大小的输入图像的路径。
现在让我们从磁盘加载这个图像:
第 13 和 14 行加载我们的输入图像 从磁盘并将其显示在我们的屏幕上:
调整图像大小时,我们需要记住图像的纵横比。纵横比是图像的宽度和高度的比例关系:
纵横比 = 图像宽度 / 图像高度
如果我们不注意纵横比,我们调整大小将返回看起来失真的结果。
计算调整大小的比率在第 19 行处理。在这行代码中,我们将新的图像宽度定义为150像素。要计算新高度与旧高度的比例,我们只需定义我们的比例r 是新宽度(150 像素)除以旧宽度,我们使用 image.shape [ 1 ].
现在我们有了比例,我们可以在第 20 行计算图像的新尺寸。同样,新图像的宽度将为 150 像素。然后通过将旧高度乘以我们的比率并将其转换为整数来计算高度。通过执行此操作,我们保留了图像的原始纵横比。
图像的实际调整发生在第 23 行。第一个参数是我们希望调整大小的图像,第二个参数是我们为新图像计算的尺寸。最后一个参数是我们的插值方法,它是在幕后处理我们如何调整实际图像大小的算法。
最后,我们在第 24 行显示调整后的图像:
在我们探索的示例中,我们仅通过指定宽度来调整图像的大小。但是如果我们想通过设置高度来调整图像大小呢?所需要的只是更改用于保持纵横比的调整大小比率的计算:
在第 28 行,我们重新定义我们的比率,r. 我们的新图像的高度为 50 像素。为了确定新高度与旧高度的比率,我们将 50 除以旧高度。
然后,我们定义新图像的尺寸。我们已经知道新图像的高度为 50 像素。新宽度是通过将旧宽度乘以比率获得的,使我们能够保持图像的原始纵横比。
然后我们在第 32 行执行图像的实际调整大小并在第 33行显示它:
在这里,我们可以看到我们在保持纵横比的同时,在宽度和高度方面都调整了原始图像的大小。如果我们不保留纵横比,我们的图像看起来会失真。
调整图像大小很简单,但必须计算纵横比,定义新图像的尺寸,然后执行调整大小需要三行代码。这三行代码虽然看起来并不多,但可以使我们的代码变得非常冗长和混乱。
相反,我们可以使用 imutils.resize 功能,可自动为我们处理计算和维护宽高比:
在此示例中,您可以看到单个函数处理图像大小调整: imutils.resize.
我们传入的第一个参数是 图像我们想调整大小。然后,我们指定关键字参数宽度,这是我们新图像的目标宽度。然后该函数为我们处理调整大小:
当然,我们也可以通过将函数调用更改为:
请注意,我们的输出调整大小的图像现在明显小于原始图像,但纵横比仍然保持不变。
到目前为止,我们只使用了 cv2.INTER_AREA插值方法。正如我在本文开头提到的,插值函数的目标是检查像素的邻域并使用这些邻域在不引入失真(或至少尽可能少的失真)的情况下以光学方式增加或减小图像的大小。
第一种方法是最近邻插值,由 cv2.INTER_NEAREST 。这种方法是最简单的插值方法。这种方法不是计算相邻像素的加权平均值或应用复杂的规则,而是简单地找到“最近”的相邻像素并假设强度值。尽管此方法既快速又简单,但调整大小后的图像质量往往相对较差,并可能导致“块状”伪像。
其次,我们有 cv2.INTER_LINEAR方法,它执行双线性插值——这是 OpenCV 在调整图像大小时默认使用的方法。双线性插值背后的一般思想可以在任何小学数学教科书中找到——斜率截距形式:
y = mx + b
显然,我概括了很多。尽管如此,我们要做的不仅仅是找到“最近的”像素并假设它的值(如最近邻插值)。我们现在取相邻像素并使用该邻域来计算插值(而不是仅假设最近的像素值)。
第三,我们有 cv2.INTER_AREA插值法。对该方法的工作原理进行全面审查超出了本教程的范围。不过,我建议您阅读这篇文章,它提供了此方法的一般系数规则的高级概述。
最后,我们有 cv2.INTER_CUBIC 和 cv2.INTER_LANCZOS4.
这些方法速度较慢(因为它们不再使用简单的线性插值,而是使用样条)并在方形像素邻域上使用双三次插值。
这 cv2.INTER_CUBIC该方法在4 x 4像素的邻居上运行,并且cv2.INTER_LANCZOS4超过8 x 8像素的邻域。一般来说,我很少看到cv2.INTER_LANCZOS4 实践中使用的方法。
既然我们已经讨论了 OpenCV 提供的插值方法,让我们编写一些代码来测试它们:
从那里开始,我们遍历每种插值方法,并在第57和58行上调整图像的大小(向上采样,使其比原始图像大3倍)。
然后调整大小的结果显示在我们的屏幕上的第 60 行。
我们来看看最近邻插值的输出:
块状工件又回来了。据我所知,cv2.INTER_AREA 表现非常相似 cv2.INTER_NEAREST.
然后我们继续进行双三次插值
双三次插值进一步消除了块状伪影。
最后, cv2.LANCOSZ4 方法,这似乎与双三次方法非常相似:
要使用 OpenCV 调整图像大小,请务必访问本教程的“下载”部分以检索源代码和示例图像。
我们已经审查了我们的结果 opencv_resize.py 脚本,但如果您想通过终端执行此脚本,只需使用以下命令:
下载.