不错的收获。我认为您的期望是正确的,例如np.interp
giving 0.1
and 0.9
values.
让我们绘制一个金字塔(插值到 49:51 的方形像素范围内):
import numpy as np
import cv2
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
prvs = np.zeros((100,80), dtype=np.float32)
prvs[50:51, 50:51] = 1
lin = np.linspace(49,51,200)
grid_x,grid_y = np.meshgrid(lin,lin)
grid_x = grid_x.astype(np.float32)
grid_y = grid_y.astype(np.float32)
prvs_zoommapped = cv2.remap(prvs, grid_x, grid_y, interpolation=cv2.INTER_LINEAR)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(grid_x,grid_y,prvs_zoommapped,cmap='viridis')
plt.show()
注意到什么了吗?绘图网格为 200x200,金字塔上有非常明显的台阶。让我们看一下结果的横截面:
fig,ax = plt.subplots()
ax.plot(prvs_zoommapped[100,:],'x-')
ax.grid('on')
plt.show()
正如您所看到的,结果是一个分段常数函数,即输出中存在巨大的离散化误差。准确地说,我们看到的步骤是0.03125 == 1/32
在结果中。
我的怀疑是cv2.remap
并不是用于子像素操作,而是用于从一个网格到另一个网格的更大规模映射。另一种选择是牺牲内部精度来提高性能。不管怎样,你都不会发疯:你应该看到0.1
and 0.9
作为精确(双)线性插值的结果。
如果您由于其他任务而没有致力于 openCV,则可以使用各种位来执行此映射(即 2d 插值)scipy.interpolate https://docs.scipy.org/doc/scipy/reference/interpolate.html,即它的部分是为二维插值而设计的 https://stackoverflow.com/q/37872171/5067311。对于规则网格上线性插值的特殊情况,scipy.interpolate.RegularGridInterpolator https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.RegularGridInterpolator.html#scipy.interpolate.RegularGridInterpolator或者类似的东西可能是合适的。
或者甚至更好(但我还没有使用这个子模块):scipy.ndimage.map_coordinates https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.map_coordinates.html#scipy.ndimage.map_coordinates看起来正是您正在寻找的:
from scipy import ndimage
ndimage.map_coordinates(prvs, [[50.1, 49.1], [50, 50]], order=1)
# output: array([ 0.89999998, 0.1 ], dtype=float32)
应用于金字塔的例子:
import numpy as np
import cv2
from scipy import ndimage
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
prvs = np.zeros((100,80), dtype=np.float32)
prvs[50:51, 50:51] = 1
lin = np.linspace(49,51,200)
grid_x,grid_y = np.meshgrid(lin,lin)
prvs_zoommapped = ndimage.map_coordinates(prvs, [grid_x, grid_y], order=1)
fig = plt.figure()
ax = fig.add_subplot(111,projection='3d')
ax.plot_surface(grid_x,grid_y,prvs_zoommapped,cmap='viridis')
plt.show()
好多了。