2017-03-18 15 views
3

私は画像を別の座標系に写像するためにopencvリマップ関数を使用しています。 しかし、私の最初のテストは補間にいくつかの問題があることを示しています。 ここでは、どこでも0で、位置[50,50]にある画像に対して一定の0.1ピクセルシフトの簡単な例を示します。OpenCVリマップ補間エラー?

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を期待。私は何か間違っているのですか、これはいくつかの数値的な問題ですか? さらに正確な再マッピングアルゴリズムがありますか?

ありがとうございました。

答えて

5

ニースキャッチ。私の意見では、np.interpのように、0.10.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() 

result: pyramid with jagged edges

お知らせ何でもオフ? 200x200のプロットグリッドでは、ピラミッド上に非常に目に見えるステップがあります。私たちの結果の断面を見てみましょう:

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

result: clearly piecewise-constant function

あなたが見ることができるように、結果は区分的定数関数である、すなわち、出力の大きな離散化誤差があります。正確には、結果に0.03125 == 1/32という手順があります。

疑問に思うのは、cv2.remapはサブピクセルの操作ではなく、あるグリッドから別のグリッドへの大規模なマッピングに使用することです。もう1つの選択肢は、性能向上のために内部精度が犠牲にされていることです。いずれにせよ、あなたは狂っていません。正確な(双)線形補間の結果として、0.10.9が表示されるはずです。

他のタスクのためにopenCVにコミットしていない場合は、このマッピング、つまりscipy.interpolateのさまざまなビット、つまりits parts made for 2d interpolationのさまざまなビットを使用してこのマッピングを実行できます。通常のグリッド上の特殊な線形補間の場合は、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() 

pretty smooth pyramid

さらに優れています。

+1

ありがとうございました。 ndimage.map_coordinatesは期待通りに動作します。 既に述べたように、補間エラーはパフォーマンスの最適化と関係があるようです。http://answers.opencv.org/question/123197/how-to-increase-warpperspective-or-warpaffine-precision/ –

+0

@JulianSも参照してください。私はそれがうれしいですし、リンクのおかげで、右のようです。 –

+2

ちょっとフォローアップ:私はOpenCVを再コンパイルし、imgproc.hppのINTER_BITSを5から10に変更しました(上記のリンクに示唆されているように)。今、エラーは0.00391に下がります。エラーは1/2^Nで、Nは整数です。ただし、INTER_BITS = 5の場合は1/2^4、INTER_BITS = 10の場合は1/2^8です。だからちょうど1/2 ^(INTER_BITS - 1)ではありません。しかし、ちょうど誰かがOpenCVの精度を少し上げたいと思って、別のライブラリに変更できない場合、私はそれが役に立つかもしれないと思った。 –