opencv - OpenCV resize() 中的 INTER_LINEAR 插值如何工作?
问题描述
我正在弄清楚当我们设置fx=2
和时 OpenCV resize() 函数如何计算线性插值fy=1
。我写了以下最小工作示例,
import cv2
import numpy as np
pattern_img = np.zeros((6, 6), np.uint8)
pattern_img[:, 0::2] = 255
patteen_img_x2 = cv2.resize(pattern_img, None, fx=2, fy=1, interpolation=cv2.INTER_LINEAR)
如果我们查看 and 的第一行pattern_img
,pattern_img_x2
我们将有,
pattern_img[0, :]
> array([255, 0, 255, 0, 255, 0], dtype=uint8)
pattern_img_x2[0, :]
> array([[255, 191, 64, 64, 191, 191, 64, 64, 191, 191, 64, 0]], dtype=uint8)
我无法弄清楚数字 191 和 64 是如何计算的。我知道它实现了bilinear
算法,但在这种情况下我们已经设置fy=1
了,所以它应该是一个简单的沿 x 轴的线性插值。但我无法弄清楚如何resize()
计算这些插值。有人可以帮我理解背后的算法吗?
解决方案
这与像素“网格”有关。
0,0 是第一个像素的中心,还是它的左上角?像素的角在哪里?计算机图形学中的一个常见问题。
插值增加了另一个复杂性。一个像素是否定义了它的整个正方形区域?然后你得到最近邻插值。还是仅仅定义了中心点?然后,从技术上讲,介于两者之间的任何内容都是undefined,并且插值将决定如何填充空间。
通常在 OpenCV 中,像素中心位于整数坐标处。这意味着第一个像素的左上角位于 (-0.5, -0.5),所以这就是图片左上角的起点。
现在,如果您要使用 fx=1 进行采样,即恒等变换,您将从 -0.5 开始,这应该是像素的左边缘,并且输出像素的宽度为 1,因此第一个输出像素跨越 -0.5 到 +0.5,其中心位于 0.0。
由于您想要 fx=2,因此您的输出像素为 0.5 宽。您仍然从 -0.5 开始,并且您的输出像素跨度... -0.5 到 0.0、0.0 到 +0.5、0.5 到 1.0、1.0 到 1.5...
他们的中心位于 -0.25, +0.25, +0.75, +1.25, ...
这就是你获得那些 1/4 和 3/4 值的方式。64 是 255 的四分之一,191 是 255 的四分之三。这也是第一个输出像素为 255 的原因。它位于第一个输入像素的左侧,因此这是它的唯一支持,并确定其值的 100%。
你可以“索引移位”这一切,所以它更容易可视化。那么图片的左上角像素的左上角在(0,0),像素延伸到(1,1),中心在(0.5,0.5)。输出像素网格相应地位于,左上像素从 0 到 0.5,中心在 0.25,其右侧的邻居跨越 0.5 到 1.0,中心在 0.75,依此类推。
如果您想完全控制这种疯狂,请构建自己的仿射变换(我建议使用 3x3 矩阵,易于组合/矩阵乘法),然后使用warpAffine
. 它将采用整数坐标作为输出,使用您的矩阵对其进行转换(它隐式反转它),并在源图像中查找结果坐标,包括在源图像空间中的插值。
在这里做了一个小图形(点击查看完整尺寸)。黑色方块是输入像素,黑点是它们的中心。红色方块和圆点是输出像素及其中心。你看,如果你在红点位置采样,你会坐在输入像素中心之间的四分之三。
推荐阅读
- flutter - Flutter showModalBottomSheet 不改变状态需要重新打开才能看到变化
- python - 在 asyncio 函数中产生对象
- html - 这里我想根据类别选择提示一个组件
- javascript - Javascript按钮单击另一个网址
- c# - 你知道如何在不改变其他元素顺序的情况下将元素移动到第一个位置吗?
- java - 阿拉伯语发音符号未正确显示
- python - python在excel中读取大整数
- android - Kotlin 对象内变量的安全重新初始化
- graphql - Gatsby 警告构建“查询时间过长”
- google-sheets-formula - 如何为以下销售目标概念制定公式