我正在使用opencv重映射功能将图像映射到另一个坐标系。 但是,我的初步测试表明插值存在一些问题。 在这里,我给出了一个简单的例子,一个图像的恒定0.1像素移位,到处为0,但位置为[50,50]。
import cv2
import numpy as np
prvs = np.zeros((100,80), dtype=np.float32)
prvs[50:51, 50:51] = 1.
grid_x, grid_y = np.meshgrid(np.arange(prvs.shape[1]), np.arange(prvs.shape[0]))
grid_y = grid_y.astype(np.float32)
grid_x = grid_x.astype(np.float32) + 0.1
prvs_remapped = cv2.remap(prvs, grid_x, grid_y, interpolation=cv2.INTER_LINEAR)
print(prvs_remapped[50,50])
print(prvs_remapped[50,49])
给出
0.90625
0.09375
然而,考虑到线性插值方法,我会期望0.9和0.1。我做错了什么还是这个数字问题? 是否有更精确的重映射算法?
感谢。
答案 0 :(得分:8)
很好听。在我看来,您的期望是正确的,例如np.interp
提供0.1
和0.9
值。
让我们绘制金字塔(插入到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
和0.9
作为精确(双)线性插值的结果。
如果由于其他任务而未提交openCV,则可以使用scipy.interpolate
的各个位(即its parts made for 2d interpolation)执行此映射,即2d插值。对于在常规网格上进行线性插值的特殊情况,scipy.interpolate.RegularGridInterpolator
或类似的东西可能是合适的。
甚至更好(但我还没有使用过这个子模块):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()
好多了。