Vorrei segnalarvi questo grafico molto perspicace da Wikipedia che illustra come fare l’interpolazione bilineare per un punto:
Fonte: Wikipedia
Come potete vedere, i quattro punti rossi sono quelli noti. Questi punti si conoscono in anticipo e P
è il punto che vogliamo interpolare. Come tale, dobbiamo fare due passi (come hai indicato nel tuo post). Per gestire la coordinata x
(orizzontale), dobbiamo calcolare qual è il valore interpolato in base alla fila di punti rossi in alto e alla fila di punti rossi in basso. Questo risulta nei due punti blu R1
e R2
. Per gestire la coordinata y
(verticale), usiamo i due punti blu e interpoliamo verticalmente per ottenere il punto finale P
.
Quando ridimensionate un’immagine, anche se non vediamo visivamente quello che sto per dire, ma immaginate che questa immagine sia un segnale 3D f
. Ogni punto della matrice è infatti una coordinata 3D dove la posizione della colonna è il valore x
, la posizione della riga è il valore y
e il valore z
è la quantità / valore della scala di grigi della matrice stessa. Quindi, fare z = f(x,y)
è il valore della matrice alla posizione (x,y)
nella matrice. Nel nostro caso, dato che si tratta di immagini, ogni valore di (x,y)
sono numeri interi che vanno da 1 fino a tante righe/colonne quante ne abbiamo a seconda di quale dimensione stai guardando.
Pertanto, data la coordinata che vuoi interpolare a (x,y)
, e date le coordinate rosse nell’immagine sopra, che chiamiamo x1,y1,x2,y2
come da schema – in particolare andando con la convenzione dello schema e facendo riferimento a come si accede alle immagini: x1 = 1, x2 = 2, y1 = 2, y2 = 1
, le coordinate blu R1
e R2
sono calcolate tramite interpolazione 1D in colonna utilizzando la stessa riga su cui entrambi i punti coincidono:
R1 = f(x1,y1) + (x - x1)/(x2 - x1)*(f(x2,y1) - f(x1,y1))R2 = f(x1,y2) + (x - x1)/(x2 - x1)*(f(x2,y2) - f(x1,y2))
È importante notare che (x - x1) / (x2 - x1)
è un peso / proporzione di quanto l’output consiste in un mix tra i due valori visti a f(x1,y1)
e f(x2,y1)
per R1
o f(x1,y2)
e f(x2,y2)
per R2
. In particolare, x1
è il punto di partenza e (x2 - x1)
è la differenza dei valori x
. Si può verificare che sostituendo x1
con x
si ottiene 0 mentre x2
con x
si ottiene 1. Questo peso oscilla tra che è necessario per far funzionare i calcoli.
Si noti che l’origine dell’immagine è in alto a sinistra, e quindi (1,1)
è in alto a sinistra. Una volta trovati R1
e R2
, possiamo trovare P
interpolando per righe:
P = R2 + (y - y2)/(y2 - y1)*(R1 - R2)
Anche (y - y2) / (y2 - y1)
denota la proporzione/miscela di quanto R1
e R2
contribuiscono all’output finale P
. Come tale, hai calcolato f5
correttamente perché hai usato quattro punti noti: In alto a sinistra è 100, in alto a destra è 50, in basso a sinistra è 70 e in basso a destra è 20. In particolare, se vuoi calcolare f5
, questo significa che (x,y) = (1.5,1.5)
perché siamo a metà strada tra 100 e 50 a causa del fatto che stai scalando l’immagine di due. Se inserite questi valori nel calcolo di cui sopra, otterrete il valore di 60 come vi aspettavate. I pesi per entrambi i calcoli risulteranno anche in 0.5
, che è quello che hai ottenuto nei tuoi calcoli ed è quello che ci aspettiamo.
Se calcolate f1
, questo corrisponde a (x,y) = (1.5,1)
e se lo sostituite nell’equazione precedente, vedrete che (y - y2)/(y2 - y1)
vi dà 0 o il peso è 0, e quindi ciò che viene calcolato è solo R2
, corrispondente all’interpolazione lineare solo lungo la riga superiore. Allo stesso modo, se abbiamo calcolato f7
, ciò significa che vogliamo interpolare a (x,y) = (1.5,2)
. In questo caso, vedrete che (y - y2) / (y2 - y1)
è 1 o il peso è 1 e quindi P = R2 + (R1 - R2)
, che si semplifica in R1
ed è l’interpolazione lineare solo lungo la fila inferiore.
Ora c’è il caso di f3
e f5
. Entrambi corrispondono rispettivamente a (x,y) = (1,1.5)
e (x,y) = (2,1.5)
. Sostituendo questi valori per R1
e R2
e P
per entrambi i casi si ottiene:
f3
R1 = f(1,2) + (1 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(1,2)R2 = f(1,1) + (1 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,1)P = R1 + (1.5 - 1)*(R1 - R2) = f(1,2) + 0.5*(f(1,2) - f(1,1))P = 70 + 0.5*(100 - 70) = 85
f5
R1 = f(1,2) + (2 - 1)/(2 - 1)*(f(2,2) - f(1,2)) = f(2,2)R2 = f(1,1) + (2 - 1)/(2 - 1)*(f(1,2) - f(1,1)) = f(1,2)P = R1 + (1.5 - 1)*(R1 - R2) = f(2,2) + 0.5*(f(2,2) - f(1,2))P = 20 + 0.5*(50 - 20) = 35
Quindi cosa ci dice questo? Significa che si sta interpolando solo lungo la direzione y. Questo è evidente quando diamo un’occhiata a P
. Esaminando più a fondo i calcoli di P
per ciascuno di f3
e f5
, si vede che stiamo considerando i valori solo lungo la direzione verticale.
Così, se vuoi una risposta definitiva, f1
e f7
si trovano interpolando lungo la direzione x
/ colonna solo lungo la stessa riga. f3
e f5
si trovano interpolando y
/ direzione della riga lungo la stessa colonna. f4
usa una miscela di f1
e f7
per calcolare il valore finale come hai già visto.
Per rispondere alla tua domanda finale, f2
, f6
e f8
sono compilati in base alle preferenze personali. Questi valori sono considerati fuori dai limiti, con i valori x
e y
che sono entrambi 2.5
e che sono fuori dalla nostra griglia per
(x,y)
. In MATLAB, l’implementazione predefinita di questo è di riempire qualsiasi valore al di fuori dei confini definiti per non essere un numero (NaN
), ma a volte, le persone estrapolano usando l’interpolazione lineare, copiano i valori di confine, o eseguono qualche imbottitura elaborata come l’imbottitura simmetrica o circolare. Dipende dalla situazione in cui ti trovi, ma non c’è una risposta corretta e definitiva su come riempire f2
, f6
e f8
– tutto dipende dalla tua applicazione e da ciò che ha più senso per te.
Come bonus, possiamo verificare che i miei calcoli sono corretti in MATLAB. Definiamo prima una griglia di (x,y)
punti nell’intervallo , poi ridimensioniamo l’immagine in modo che sia due volte più grande dove specifichiamo una risoluzione di 0,5 per punto invece di 1. Chiamerò la tua matrice definita
A
:
A = ; %// Define original matrix = meshgrid(1:2,1:2); %// Define original grid of points = meshgrid(1:0.5:2.5,1:0.5:2.5) %// Define expanded grid of pointsB = interp2(X,Y,A,X2,Y2,'linear'); %// Perform bilinear interpolation
La griglia originale (x,y)
di punti assomiglia a:
>> XX = 1 2 1 2>> YY = 1 1 2 2
La griglia espansa per espandere la dimensione della matrice del doppio assomiglia a:
>> X2X2 = 1.0000 1.5000 2.0000 2.5000 1.0000 1.5000 2.0000 2.5000 1.0000 1.5000 2.0000 2.5000 1.0000 1.5000 2.0000 2.5000>> Y2Y2 = 1.0000 1.0000 1.0000 1.0000 1.5000 1.5000 1.5000 1.5000 2.0000 2.0000 2.0000 2.0000 2.5000 2.5000 2.5000 2.5000
B
è l’output usando X
e Y
come griglia originale di punti e X2
e Y2
sono i punti che vogliamo interpolare.
otteniamo:
>> BB = 100 75 50 NaN 85 60 35 NaN 70 45 20 NaN NaN NaN NaN NaN