Schöner Fang. Ihre Erwartungen sind meiner Meinung nach richtig, wie zum Beispiel np.interp
, geben 0.1
und 0.9
Werte.
Lassen Sie sich Grundstück eine Pyramide (in den 49:51 quadratischen Pixelbereich interpoliert):
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()
Hinweis etwas aus? Bei einem Plot-Raster von 200x200 gibt es sehr sichtbare Stufen auf der Pyramide. Schauen wir uns den Querschnitt unseres Ergebnis einen Blick:
fig,ax = plt.subplots()
ax.plot(prvs_zoommapped[100,:],'x-')
ax.grid('on')
plt.show()
Wie Sie sehen können, ist das Ergebnis eine stückweise konstante Funktion, das heißt es in der Ausgabe riesige Diskretisierungsfehlers ist. Um genau zu sein, sehen wir Schritte von 0.03125 == 1/32
im Ergebnis.
Mein Verdacht ist, dass cv2.remap
nicht für Sub-Pixel-Manipulationen, sondern für eine größere Mapping von einem Raster zu einem anderen gedacht ist. Die andere Möglichkeit besteht darin, dass die interne Genauigkeit für Leistungsverbesserungen geopfert wurde. So oder so, Sie werden nicht verrückt: Sie sollten 0.1
und 0.9
als Ergebnis der genauen (Bi) lineare Interpolation sehen.
Wenn Sie aufgrund anderer Aufgaben nicht zu openCV verpflichtet sind, kann diese Kartierung, d. H. 2D-Interpolation, mit verschiedenen Bits von scipy.interpolate
, nämlich ausgeführt werden. Für Ihren speziellen Fall der linearen Interpolation in einem regelmäßigen Raster könnte scipy.interpolate.RegularGridInterpolator
oder etwas ähnliches angebracht sein.
Oder noch besser (aber ich habe dieses Modul noch nicht verwendet): scipy.ndimage.map_coordinates
scheint, wie genau das, was Sie suchen:
from scipy import ndimage
ndimage.map_coordinates(prvs, [[50.1, 49.1], [50, 50]], order=1)
# output: array([ 0.89999998, 0.1 ], dtype=float32)
zur Pyramide Beispiel angewendet:
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()
Viel besser.
Danke. ndimage.map_coordinates funktioniert wie erwartet. Der Interpolationsfehler scheint mit etwas Leistungsoptimierung zu tun zu haben, wie Sie bereits sagten.Siehe auch http://answers.opencv.org/question/123197/how-to-increase-warperspective-o-warpaffin-precision/ –
@JulianS. Ich bin froh, dass es so ist, und danke für den Link, scheint richtig. –
Nur ein paar weitere Follow-up: Ich habe OpenCV neu kompiliert und INTER_BITS in imgproc.hpp von 5 auf 10 geändert (wie in dem oben angegebenen Link vorgeschlagen). Jetzt sinkt der Fehler auf 0,00391. Der Fehler scheint 1/2^N zu sein, wobei N eine ganze Zahl ist. Es ist jedoch 1/2^4 im Fall von INTER_BITS = 5 und 1/2^8 im Fall von INTER_BITS = 10. Es ist also nicht nur 1/2^(INTER_BITS - 1). Aber nur für den Fall, dass jemand die Genauigkeit von OpenCV ein wenig erhöhen möchte und nicht in eine andere Bibliothek wechseln kann, dachte ich, dass es hilfreich sein könnte. –