Dies ist eine Art Nachgang zu Ihrer previousquestions über den Unterschied zwischen imresize
in MATLAB und cv::resize
in OpenCV eine bikubische Interpolation gegeben.
Ich war selbst daran interessiert herauszufinden, warum es einen Unterschied gibt.Das sind meine Ergebnisse (wie ich die Algorithmen verstanden habe, korrigiere mich bitte, wenn ich Fehler mache).
denkt, dass ein Bild als eine planar-Transformation von einem Eingangsbild der Größe der Größenänderung M-by-N
zu einem Ausgabebild der Größe scaledM-by-scaledN
.
Das Problem ist, dass die Punkte nicht unbedingt auf das diskrete Gitter passen, daher müssen wir, um Intensitäten von Pixeln im Ausgabebild zu erhalten, die Werte einiger benachbarter Proben interpolieren (normalerweise in umgekehrter Reihenfolge), Das heißt, für jedes Ausgabepixel finden wir den entsprechenden nicht-ganzzahligen Punkt im Eingabefeld und interpolieren ihn().
Hier unterscheiden sich die Interpolationsalgorithmen, indem die Größe der Nachbarschaft und die Gewichtungskoeffizienten für jeden Punkt in dieser Umgebung ausgewählt werden. Die Beziehung kann von erster oder höherer Ordnung sein (wobei die involvierte Variable die Entfernung von der invers abgebildeten nicht ganzzahligen Probe zu den diskreten Punkten auf dem Originalbildgitter ist). In der Regel weisen Sie engeren Punkten höhere Gewichte zu.
bei imresize
in MATLAB Sehen, hier sind die Gewicht Funktionen für die linearen und kubischen Kern:
function f = triangle(x)
% or simply: 1-abs(x) for x in [-1,1]
f = (1+x) .* ((-1 <= x) & (x < 0)) + ...
(1-x) .* ((0 <= x) & (x <= 1));
end
function f = cubic(x)
absx = abs(x);
absx2 = absx.^2;
absx3 = absx.^3;
f = (1.5*absx3 - 2.5*absx2 + 1) .* (absx <= 1) + ...
(-0.5*absx3 + 2.5*absx2 - 4*absx + 2) .* ((1 < absx) & (absx <= 2));
end
(Diese im Grunde die Interpolation Gewicht einer Probe zurückkehrt basierend darauf, wie weit es von einem interpolierten Punkt ist.)
Dies ist, wie diese Funktionen wie folgt aussehen:
>> subplot(121), ezplot(@triangle,[-2 2]) % triangle
>> subplot(122), ezplot(@cubic,[-3 3]) % Mexican hat
Beachten Sie, dass der lineare Kern (stückweise lineare Funktionen auf [-1,0] und [0,1] Intervallen, und Nullen anderswo) an den 2-benachbarten Punkten arbeitet, während der kubische Kern (stückweise kubische Funktionen in den Intervallen [-2, -1], [-1,1] und [1,2], und Nullen anderswo) arbeiten an 4 benachbarten Punkten.
Hier ist eine Darstellung für die 1-dimensionalen Fall, das zeigt, wie der Wert x
von den diskreten Punkten f(x_k)
unter Verwendung eines kubischen kernel zu interpolieren: bei x
,
Die Kernfunktion h(x)
zentriert die Position des zu interpolierenden Punktes. Der interpolierte Wert f(x)
ist die gewichtete Summe der diskreten benachbarten Punkte (2 links und 2 rechts), skaliert durch den Wert der Interpolationsfunktion an diesen diskreten Punkten.
sagen, wenn der Abstand zwischen x
und dem nächstgelegenen Punkt d
(0 <= d < 1
) ist, an der Stelle der interpolierte Wert x
wird:
f(x) = f(x1)*h(-d-1) + f(x2)*h(-d) + f(x3)*h(-d+1) + f(x4)*h(-d+2)
wo die Reihenfolge der Punkte wird unten dargestellt (man beachte, dass x(k+1)-x(k) = 1
):
Da nun die Punkte diskret sind und in gleichmäßigen Intervallen abgetastet werden und die Kernbreite normalerweise klein ist, kann die Interpolation formuliert werden prägnanter als Faltungsoperation:
das Konzept zu 2 Dimensionen erstreckt einfach, indem zuerst entlang einer Dimension interpoliert, und dann über die andere Dimension der Ergebnisse des vorherigen Schrittes unter Verwendung von interpoliert wird. Hier
ist ein Beispiel für eine bilineare Interpolation, die in 2D 4 benachbarte Punkte betrachtet:
Die bikubische Interpolation in 2D verwendet 16 benachbarten Punkten:
Zuerst wir interpoliere entlang der Zeilen (die roten Punkte) mit den 16 Rasterproben (pink). Dann interpolieren wir entlang der anderen Dimension (rote Linie) mit den interpolierten Punkten aus dem vorherigen Schritt. In jedem Schritt wird eine reguläre 1D-Interpolation durchgeführt. In diesem Fall sind die Gleichungen zu lang und zu kompliziert für mich, um mit der Hand zu arbeiten!
Wenn wir nun auf die cubic
Funktion in MATLAB gehen zurück, sie paßt eigentlich die Definition des Faltungskernes in den reference paper als Gleichung (4) gezeigt. Hier ist die gleiche Sache aus Wikipedia genommen:
Sie können sehen, dass in der obigen Definition, MATLAB einen Wert von a=-0.5
gewählt hat.
Jetzt ist der Unterschied zwischen der Implementierung in MATLAB und OpenCV OpenCV wählte einen Wert von a=-0.75
.
static inline void interpolateCubic(float x, float* coeffs)
{
const float A = -0.75f;
coeffs[0] = ((A*(x + 1) - 5*A)*(x + 1) + 8*A)*(x + 1) - 4*A;
coeffs[1] = ((A + 2)*x - (A + 3))*x*x + 1;
coeffs[2] = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
coeffs[3] = 1.f - coeffs[0] - coeffs[1] - coeffs[2];
}
Dies nicht sofort offensichtlich sein könnte, aber der Code die Bedingungen der kubischen Faltungsfunktion nicht berechnen (rechts nach Gleichung (25) in dem Papier aufgeführt):
Wir mit Hilfe der Symbolic Math Toolbox kann man erkennen, überprüfen:
A = -0.5;
syms x
c0 = ((A*(x + 1) - 5*A)*(x + 1) + 8*A)*(x + 1) - 4*A;
c1 = ((A + 2)*x - (A + 3))*x*x + 1;
c2 = ((A + 2)*(1 - x) - (A + 3))*(1 - x)*(1 - x) + 1;
c3 = 1 - c0 - c1 - c2;
Diese Ausdrücke wie folgt umgeschrieben werden:
>> expand([c0;c1;c2;c3])
ans =
- x^3/2 + x^2 - x/2
(3*x^3)/2 - (5*x^2)/2 + 1
- (3*x^3)/2 + 2*x^2 + x/2
x^3/2 - x^2/2
die mit den Termen aus der obigen Gleichung übereinstimmen.
Offensichtlich läuft der Unterschied zwischen MATLAB und OpenCV darauf hinaus, einen anderen Wert für den freien Begriff a
zu verwenden. Den Autoren der Arbeit zufolge ist ein Wert von 0.5
die bevorzugte Wahl, weil er bessere Eigenschaften für den Approximationsfehler als jede andere Wahl für a
impliziert.
+1 - Cool! ... da kamen die Schlüssel her! – rayryeng
@Gilad Ich erinnere mich, dass Sie MATLAB vs OpenCV kubische Interpolation untersucht haben und es scheint, dass der Unterschied a = -0,5 für MATLAB und [a = -0,75 für OpenCV] ist (https://github.com/Itseez/opencv/ Blob/Master/Module/imgproc/src/imgwarp.cpp # L155). – chappjc
@chappjc: +1 gute finden. Ich schrieb tatsächlich eine Antwort darüber :) – Amro