OpenCV重映射插值错误? [英] OpenCV remap interpolation error?

查看:112
本文介绍了OpenCV重映射插值错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用opencv remap函数将图像映射到另一个坐标系. 但是,我的初步测试表明插值存在一些问题. 在这里,我举一个简单的例子,即对于一个在位置[50,50]处均为0的图像,其像素偏移恒定为0.1.

I'm using opencv remap function to map an image to another coordinate system. However, my initial tests indicate that there are some issues with the interpolation. Here, I give a simple example of a constant 0.1 pixel shift for a image that is 0 everywhere but at position [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代替.我是在做错什么还是这是数字问题? 周围还有更精确的重映射算法吗?

However, I would expect 0.9 and 0.1 instead, given the linear interpolation method. Am I doing something wrong or is this some numeric issue? Are there any more precise remapping algorithms around?

谢谢.

推荐答案

很好.在我看来,您的期望是正确的,例如np.interp给出0.10.9值.

Nice catch. Your expectations are correct in my opinion, as exemplified by np.interp giving 0.1 and 0.9 values.

让我们绘制一个金字塔(内插到49:51平方像素范围内):

Let's plot a pyramid (interpolating into the 49:51 square pixel range):

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的绘图网格时,金字塔上有非常明显的台阶.让我们看一下结果的横截面:

Notice anything off? With a plotting grid of 200x200, there are very visible steps on the pyramid. Let's take a look at the cross-section of our result:

fig,ax = plt.subplots()
ax.plot(prvs_zoommapped[100,:],'x-')
ax.grid('on')
plt.show()

如您所见,结果是一个分段常数函数,即输出中存在巨大的离散化误差.确切地说,我们在结果中看到了0.03125 == 1/32的步骤.

As you can see, the result is a piece-wise constant function, i.e. there's huge discretization error in the output. To be precise, we see steps of 0.03125 == 1/32 in the result.

我怀疑cv2.remap并不是要用于子像素操作,而是要用于从一个网格到另一个网格的更大比例的映射.另一个选择是为了提高性能而牺牲了内部精度.无论哪种方式,您都不会发疯:您应该看到0.10.9是精确(双)线性插值的结果.

My suspicion is that cv2.remap is not meant to be used for sub-pixel manipulations, but for a larger-scale mapping from one grid to another. The other option is that internally precision has been sacrificed for performance improvements. Either way, you're not going crazy: you should be seeing 0.1 and 0.9 as the result of exact (bi)linear interpolation.

如果由于其他任务而没有承诺使用openCV,则可以使用其零件是为2d插值制作的.对于您在常规网格上进行线性插值的特殊情况, scipy.interpolate.RegularGridInterpolator 或类似的内容可能合适.

If you're not committed to openCV due to other tasks, this mapping i.e. 2d interpolation can be performed with various bits of scipy.interpolate, namely its parts made for 2d interpolation. For your special case of linear interpolation on a regular grid, scipy.interpolate.RegularGridInterpolator or something similar might be appropriate.

甚至更好(但我还没有使用过此子模块):

Or even better (but I haven't used this submodule yet): scipy.ndimage.map_coordinates seems like exactly what you're looking for:

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()

好多了.

这篇关于OpenCV重映射插值错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆