Bilinear image interpolation / scaling – A calculation example

Chciałbym skierować Cię do tej bardzo wnikliwej grafiki z Wikipedii, która ilustruje, jak zrobić interpolację bilinearną dla jednego punktu:

Source: Wikipedia

Jak widać, cztery czerwone punkty są tym, co jest znane. Te punkty znasz wcześniej, a P jest punktem, który chcemy interpolować. Jako takie, musimy wykonać dwa kroki (jak wskazałeś w swoim poście). Aby obsłużyć współrzędną x (poziomą), musimy obliczyć, co interpolowana wartość jest wiersz mądry dla górnego rzędu czerwonych punktów i dolnego rzędu czerwonych punktów. Wynikiem tego są dwa niebieskie punkty R1 i R2. Aby obsłużyć współrzędną y (pionową), używamy dwóch niebieskich punktów i interpolujemy pionowo, aby uzyskać ostateczny punkt P.

Gdy zmieniasz rozmiar obrazu, nawet jeśli nie widzimy wizualnie tego, co mam zamiar powiedzieć, ale wyobraź sobie, że ten obraz jest sygnałem 3D f. Każdy punkt w macierzy jest w rzeczywistości współrzędną 3D, gdzie lokalizacja kolumny jest wartością x, lokalizacja wiersza jest wartością y, a wartość z jest ilością / wartością skali szarości samej macierzy. Dlatego robienie z = f(x,y) jest wartością macierzy w lokalizacji (x,y) w macierzy. W naszym przypadku, ponieważ masz do czynienia z obrazami, każda wartość (x,y) są liczbami całkowitymi, które idą od 1 do tylu wierszy / kolumn, ile mamy w zależności od tego, na jaki wymiar patrzysz.

Dlatego, biorąc pod uwagę współrzędną, którą chcesz interpolować w (x,y), i biorąc pod uwagę czerwone współrzędne na powyższym obrazie, które nazywamy je x1,y1,x2,y2 zgodnie z diagramem – konkretnie idąc z konwencją diagramu i odnosząc się do tego, jak obrazy są dostępne: x1 = 1, x2 = 2, y1 = 2, y2 = 1, niebieskie współrzędne R1 i R2 są obliczane poprzez interpolację 1D column wise przy użyciu tego samego wiersza, na którym zbiegają się oba punkty:

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

Ważne jest, aby zauważyć, że (x - x1) / (x2 - x1) jest wagą / proporcją tego, ile miksu składa się z wyjścia pomiędzy dwiema wartościami widocznymi na f(x1,y1) i f(x2,y1) dla R1 lub f(x1,y2) i f(x2,y2) dla R2. Konkretnie, x1 jest punktem początkowym, a (x2 - x1) jest różnicą wartości x. Można sprawdzić, że podstawienie x1 jako x daje nam 0, podczas gdy x2 jako x daje nam 1. Waga ta waha się w granicach , co jest wymagane, aby obliczenia działały.

Należy zauważyć, że początek obrazu jest w lewym górnym rogu, a więc (1,1) jest w lewym górnym rogu. Po znalezieniu R1 i R2, możemy znaleźć P przez interpolację wiersza mądrze:

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

Again, (y - y2) / (y2 - y1) oznaczają proporcję / mieszankę tego, ile R1 i R2 przyczyniają się do ostatecznego wyjścia P. Jako takie, obliczyłeś f5 poprawnie, ponieważ użyłeś czterech znanych punktów: Górna lewa to 100, górna prawa to 50, dolna lewa to 70 i dolna prawa to 20. Konkretnie, jeśli chcesz obliczyć f5, oznacza to, że (x,y) = (1.5,1.5), ponieważ jesteśmy w połowie drogi między 100 i 50 ze względu na fakt, że skalujesz obraz przez dwa. Jeśli podłączysz te wartości do powyższych obliczeń, otrzymasz wartość 60, jak się spodziewałeś. Wagi dla obu obliczeń będą również skutkować 0.5, co jest tym, co otrzymałeś w swoich obliczeniach i tego właśnie oczekujemy.

Jeśli obliczysz f1, odpowiada to (x,y) = (1.5,1) i jeśli podstawisz to do powyższego równania, zobaczysz, że (y - y2)/(y2 - y1) daje ci 0 lub waga wynosi 0, a więc to, co jest obliczane, to tylko R2, odpowiadające interpolacji liniowej tylko wzdłuż górnego rzędu. Podobnie, jeśli obliczyliśmy f7, oznacza to, że chcemy interpolować w (x,y) = (1.5,2). W tym przypadku zobaczysz, że (y - y2) / (y2 - y1) wynosi 1 lub waga wynosi 1, a więc P = R2 + (R1 - R2), co upraszcza się do R1 i jest interpolacją liniową tylko wzdłuż dolnego rzędu.

Teraz mamy przypadek f3 i f5. Oba odpowiadają odpowiednio (x,y) = (1,1.5) i (x,y) = (2,1.5). Podstawiając te wartości do R1 i R2 oraz P dla obu przypadków otrzymujemy:

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

Co nam to mówi? Oznacza to, że interpolujesz tylko wzdłuż kierunku y. Jest to widoczne, gdy spojrzymy na P. Badając obliczenia bardziej dokładnie P dla każdego z f3 i f5, widzisz, że rozważamy wartości wzdłuż kierunku pionowego tylko.

Jako takie, jeśli chcesz uzyskać ostateczną odpowiedź, f1 i f7 są znalezione przez interpolację wzdłuż x / kierunku kolumny tylko wzdłuż tego samego wiersza. f3 i f5 są znalezione przez interpolację y / kierunek wiersza wzdłuż tej samej kolumny. f4 używa mieszaniny f1 i f7 do obliczenia wartości końcowej, jak już widziałeś.

Aby odpowiedzieć na twoje ostatnie pytanie, f2, f6 i f8 są wypełnione w oparciu o osobiste preferencje. Wartości te są uważane za poza granicami, przy czym wartości x i y zarówno są 2.5, a to jest poza naszą siatką dla (x,y). W MATLABie, domyślną implementacją tego jest wypełnienie wszystkich wartości poza zdefiniowanymi granicami, aby nie były liczbami (NaN), ale czasami ludzie ekstrapolują używając interpolacji liniowej, kopiują wartości graniczne lub wykonują jakieś skomplikowane wypełnienia, takie jak symetryczne lub kołowe wypełnienia. To zależy od tego, w jakiej sytuacji się znajdujesz, ale nie ma poprawnej i ostatecznej odpowiedzi na to, jak wypełnić f2, f6 i f8 – wszystko zależy od twojej aplikacji i tego, co ma dla ciebie największy sens.

Jako bonus możemy sprawdzić, czy moje obliczenia są poprawne w MATLABie. Najpierw definiujemy siatkę (x,y) punktów w zakresie , a następnie zmieniamy rozmiar obrazu tak, aby był dwukrotnie większy, gdzie określamy rozdzielczość 0,5 na punkt, a nie 1. Nazwę twoją zdefiniowaną macierz 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

Oryginalna siatka punktów (x,y) wygląda jak:

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

Rozszerzona siatka w celu zwiększenia rozmiaru macierzy o dwa razy więcej wygląda jak:

>> 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 jest wyjściem przy użyciu X i Y jako oryginalnej siatki punktów, a X2 i Y2 są punktami, które chcemy interpolować.

Otrzymujemy:

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

.

Dodaj komentarz