Belle prise. Vos attentes sont correctes à mon avis, comme illustré par np.interp
donnant 0.1
et 0.9
valeurs.
Soit une parcelle de pyramide (interpoler dans la gamme de pixels carrés 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()
quoi que ce soit d'avis au large? Avec une grille de traçage de 200x200, il y a des étapes très visibles sur la pyramide. Jetons un coup d'oeil à la section de notre résultat:
fig,ax = plt.subplots()
ax.plot(prvs_zoommapped[100,:],'x-')
ax.grid('on')
plt.show()
Comme vous pouvez le voir, le résultat est une fonction constante par morceau, à savoir qu'il ya énorme erreur de discrétisation dans la sortie. Pour être précis, nous voyons les étapes de 0.03125 == 1/32
dans le résultat.
Je soupçonne que cv2.remap
n'est pas destiné à être utilisé pour des manipulations de sous-pixels, mais pour un mappage à plus grande échelle d'une grille à l'autre. L'autre option est que la précision interne a été sacrifiée pour améliorer les performances. De toute façon, vous ne devenez pas fou: vous devriez voir 0.1
et 0.9
comme résultat d'une interpolation (bi) linéaire exacte.
Si vous n'êtes pas concerné par openCV en raison d'autres tâches, ce mappage, c'est-à-dire l'interpolation 2d, peut être effectué avec divers bits de scipy.interpolate
, à savoir its parts made for 2d interpolation. Pour votre cas particulier d'interpolation linéaire sur une grille régulière, scipy.interpolate.RegularGridInterpolator
ou quelque chose de similaire pourrait être approprié.
Ou mieux encore (mais je ne l'ai pas utilisé cette sous-module encore): scipy.ndimage.map_coordinates
semble être exactement ce que vous cherchez:
from scipy import ndimage
ndimage.map_coordinates(prvs, [[50.1, 49.1], [50, 50]], order=1)
# output: array([ 0.89999998, 0.1 ], dtype=float32)
appliquée à l'exemple de la pyramide:
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()
Beaucoup mieux.
Merci. ndimage.map_coordinates fonctionne comme prévu. L'erreur d'interpolation semble avoir à voir avec une optimisation des performances comme vous l'avez déjà dit.Voir aussi http://answers.opencv.org/question/123197/how-to-increase-warpperspective-or-warpaffine-precision/ –
@JulianS. Je suis content, et merci pour le lien, semble correct. –
Juste un peu plus de suivi: j'ai recompilé OpenCV et changé INTER_BITS dans imgproc.hpp de 5 à 10 (comme suggéré dans le lien donné ci-dessus). Maintenant, l'erreur descend à 0.00391. L'erreur semble être 1/2^N, avec N étant un entier. Cependant, c'est 1/2^4 dans le cas de INTER_BITS = 5 et 1/2^8 dans le cas de INTER_BITS = 10. Donc ce n'est pas juste 1/2^(INTER_BITS - 1). Mais juste au cas où quelqu'un voudrait augmenter la précision d'OpenCV et ne peut pas changer pour une autre bibliothèque, j'ai pensé que ça pourrait être utile. –