Bilinear bildinterpolering/skalering – Ett beräkningsexempel

Jag skulle vilja peka på denna mycket insiktsfulla grafik från Wikipedia som illustrerar hur man gör bilinjär interpolering för en punkt:

Källa: Som du kan se är de fyra röda punkterna det som är känt. Dessa punkter känner du till i förväg och P är den punkt som vi vill interpolera. Som sådan måste vi göra två steg (som du har angett i ditt inlägg). För att hantera koordinaten x (horisontell) måste vi beräkna vad det interpolerade värdet är radvis för den översta raden av röda punkter och den nedersta raden av röda punkter. Detta resulterar i de två blå punkterna R1 och R2. För att hantera koordinaten y (vertikalt) använder vi de två blå punkterna och interpolerar vertikalt för att få fram den slutliga punkten P.

När du ändrar storleken på en bild, även om vi inte visuellt ser vad jag ska säga, men tänk dig att den här bilden är en 3D-signal f. Varje punkt i matrisen är i själva verket en 3D-koordinat där kolumnplaceringen är x-värdet, radplaceringen är y-värdet och z-värdet är kvantiteten/gråskalevärdet för själva matrisen. Därför är gör z = f(x,y) värdet av matrisen på plats (x,y) i matrisen. I vårt fall, eftersom du har att göra med bilder, är varje värde av (x,y) heltal som går från 1 upp till så många rader/kolumner som vi har beroende på vilken dimension du tittar på.

Därmed, givet den koordinat du vill interpolera vid (x,y), och givet de röda koordinaterna i bilden ovan, som vi kallar dem x1,y1,x2,y2 enligt diagrammet – specifikt att gå med konventionen i diagrammet och referera till hur bilder är åtkomliga: x1 = 1, x2 = 2, y1 = 2, y2 = 1, beräknas de blå koordinaterna R1 och R2 via 1D-interpolation kolumnvis med hjälp av samma rad som båda punkterna sammanfaller på:

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))

Det är viktigt att notera att (x - x1) / (x2 - x1) är en vikt/proportion av hur mycket av en blandning som utmatningen består av mellan de två värdena som ses vid f(x1,y1) och f(x2,y1) för R1 eller f(x1,y2) och f(x2,y2) för R2. Specifikt är x1 utgångspunkten och (x2 - x1) är skillnaden mellan x-värdena. Du kan kontrollera att om du ersätter x1 med x får vi 0 medan x2 med x ger oss 1. Denna vikt fluktuerar mellan vilket krävs för att beräkningarna ska fungera.

Det bör noteras att bildens ursprung ligger i det övre vänstra hörnet, och därför ligger (1,1) i det övre vänstra hörnet. När man har hittat R1 och R2 kan vi hitta P genom att interpolera radvis:

P = R2 + (y - y2)/(y2 - y1)*(R1 - R2)

Också (y - y2) / (y2 - y1) betecknar proportionen/blandningen av hur mycket R1 och R2 bidrar till slutresultatet P. Som sådan beräknade du f5 korrekt eftersom du använde fyra kända punkter: Överst till vänster är 100, överst till höger är 50, nederst till vänster är 70 och nederst till höger är 20. Om du specifikt vill beräkna f5 innebär detta att (x,y) = (1.5,1.5) eftersom vi befinner oss halvvägs mellan 100 och 50 på grund av att du skalar bilden med två. Om du sätter in dessa värden i ovanstående beräkning får du värdet 60 som du förväntade dig. Vikterna för båda beräkningarna kommer också att resultera i 0.5, vilket är vad du fick i dina beräkningar och det är vad vi förväntar oss.

Om du beräknar f1 motsvarar detta (x,y) = (1.5,1) och om du sätter in detta i ekvationen ovan kommer du att se att (y - y2)/(y2 - y1) ger dig 0 eller vikten är 0, och det som beräknas är alltså bara R2, vilket motsvarar den linjära interpolationen endast längs den översta raden. På samma sätt, om vi beräknade f7, betyder det att vi vill interpolera vid (x,y) = (1.5,2). I det här fallet ser du att (y - y2) / (y2 - y1) är 1 eller att vikten är 1 och därmed P = R2 + (R1 - R2), vilket förenklas till R1 och motsvarar den linjära interpolationen längs endast den nedre raden.

Nu har vi fallet med f3 och f5. Dessa motsvarar båda (x,y) = (1,1.5) respektive (x,y) = (2,1.5). Genom att ersätta dessa värden med R1 och R2 och P för båda fallen får man:

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

Så vad säger oss detta? Det betyder att du interpolerar endast längs y-ledet. Detta är uppenbart när vi tar en titt på P. Om man undersöker beräkningarna mer noggrant av P för var och en av f3 och f5 ser man att vi endast tar hänsyn till värden längs den vertikala riktningen.

Som sådan, om du vill ha ett slutgiltigt svar, hittas f1 och f7 genom att interpolera längs x / kolumnriktningen endast längs samma rad. f3 och f5 hittas genom att interpolera y / radriktningen längs samma kolumn. f4 använder en blandning av f1 och f7 för att beräkna slutvärdet som du redan har sett.

För att besvara din sista fråga fylls f2, f6 och f8 i utifrån personliga preferenser. Dessa värden anses vara utanför gränserna, med x och y värden som båda är 2.5 och det är utanför vårt rutnät för (x,y). I MATLAB är standardimplementationen av detta att alla värden utanför de definierade gränserna fylls med värden som inte är ett nummer (NaN), men ibland extrapolerar folk med hjälp av linjär interpolation, kopierar gränsvärdena eller utför någon utarbetad utfyllnad som symmetrisk eller cirkulär utfyllnad. Det beror på vilken situation du befinner dig i, men det finns inget korrekt och slutgiltigt svar på hur f2, f6 och f8 ska fyllas i – allt beror på din tillämpning och vad som är mest meningsfullt för dig.

Som bonus kan vi verifiera att mina beräkningar är korrekta i MATLAB. Vi definierar först ett rutnät med (x,y) punkter i intervallet, sedan ändrar vi storleken på bilden så att den blir dubbelt så stor där vi anger en upplösning på 0,5 per punkt i stället för 1. Jag kommer att kalla din definierade matris 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

Det ursprungliga (x,y)gallret av punkter ser ut som:

>> XX = 1 2 1 2>> YY = 1 1 2 2

Det expanderade gallret för att utöka matrisens storlek med dubbelt så mycket ser ut som:

>> 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 är utfallet med X och Y som det ursprungliga gallret av punkter och X2 och Y2 är de punkter som vi vill interpolera på.

Vi får:

>> BB = 100 75 50 NaN 85 60 35 NaN 70 45 20 NaN NaN NaN NaN NaN

Lämna en kommentar