2014-10-01 14 views
11

Znalazłem kilka metod powiększania obrazu, ale nie ma możliwości zmniejszenia obrazu. Obecnie używam metody najbliższego sąsiada. Jak to zrobić z interpolacją dwuliniową bez korzystania z funkcji imresize w programie MATLAB?Zmienianie rozmiaru obrazu za pomocą interpolacji dwuliniowej bez wymazywania

+3

trzeba to zrobić bez korzystania z określonej funkcji? twoim najlepszym podejściem byłoby kodowanie interpolacji biliniowej lub bikubicznej, a następnie tworzenie obrazów. W przeciwnym razie można zginąć piramidalny jist, wykonując połowę obrazu: img = img (1: 2: koniec, 1: 2: koniec) –

+0

Jak to zrobić z interpolacją dwu liniową? – teardrop

+0

Interpolacja dwuliniowa jest dość łatwa do zakodowania. Google trochę i możesz wiedzieć, jak to zakodować. Po uzyskaniu interpolacji, po prostu uzyskaj wartości obrazu. –

Odpowiedz

46

W swoich komentarzach wspomniałeś, że chciałeś zmienić rozmiar obrazu za pomocą interpolacji dwuliniowej. Należy pamiętać, że dwuwymiarowy algorytm interpolacji jest niezależny od rozmiaru. Możesz bardzo dobrze wykorzystać ten sam algorytm do powiększania obrazu i zmniejszania obrazu. Odpowiednie współczynniki skalowania do lokalizacji pikseli zależą od podanych wymiarów wyjściowych. Ten nie zmienia w żaden sposób algorytmu rdzeniowego.

Zanim zacznę od jakiegokolwiek kodu, zamierzam skierować cię do Richard Alan Peters' II digital image processing slides on interpolation, w szczególności slajdu # 59. Ma świetną ilustrację oraz pseudokod na temat interpolacji dwuliniowej, która jest przyjazna dla MATLAB. Aby być samowystarczalny, mam zamiar to jego slajd tu więc możemy podążać i kod go:

enter image description here

Napiszmy funkcję, która zrobi to za nas. Ta funkcja pobiera obraz (odczytany przez imread), który może mieć kolor lub skalę szarości, a także tablicę złożoną z dwóch elementów - Obraz, który ma zostać zmieniony, oraz wymiary wyjściowe w dwuelementowej tablicy ostateczny obraz, który chcesz zmienić. Pierwszym elementem tej tablicy będą wiersze, a drugim elementem tej tablicy będą kolumny. Będziemy po prostu przejść przez ten algorytm i obliczyć wartości kolorów piksela wyjściowego/w skali szarości przy użyciu tego Pseudokod:

function [out] = bilinearInterpolation(im, out_dims) 

    %// Get some necessary variables first 
    in_rows = size(im,1); 
    in_cols = size(im,2); 
    out_rows = out_dims(1); 
    out_cols = out_dims(2); 

    %// Let S_R = R/R'   
    S_R = in_rows/out_rows; 
    %// Let S_C = C/C' 
    S_C = in_cols/out_cols; 

    %// Define grid of co-ordinates in our image 
    %// Generate (x,y) pairs for each point in our image 
    [cf, rf] = meshgrid(1 : out_cols, 1 : out_rows); 

    %// Let r_f = r'*S_R for r = 1,...,R' 
    %// Let c_f = c'*S_C for c = 1,...,C' 
    rf = rf * S_R; 
    cf = cf * S_C; 

    %// Let r = floor(rf) and c = floor(cf) 
    r = floor(rf); 
    c = floor(cf); 

    %// Any values out of range, cap 
    r(r < 1) = 1; 
    c(c < 1) = 1; 
    r(r > in_rows - 1) = in_rows - 1; 
    c(c > in_cols - 1) = in_cols - 1; 

    %// Let delta_R = rf - r and delta_C = cf - c 
    delta_R = rf - r; 
    delta_C = cf - c; 

    %// Final line of algorithm 
    %// Get column major indices for each point we wish 
    %// to access 
    in1_ind = sub2ind([in_rows, in_cols], r, c); 
    in2_ind = sub2ind([in_rows, in_cols], r+1,c); 
    in3_ind = sub2ind([in_rows, in_cols], r, c+1); 
    in4_ind = sub2ind([in_rows, in_cols], r+1, c+1);  

    %// Now interpolate 
    %// Go through each channel for the case of colour 
    %// Create output image that is the same class as input 
    out = zeros(out_rows, out_cols, size(im, 3)); 
    out = cast(out, class(im)); 

    for idx = 1 : size(im, 3) 
     chan = double(im(:,:,idx)); %// Get i'th channel 
     %// Interpolate the channel 
     tmp = chan(in1_ind).*(1 - delta_R).*(1 - delta_C) + ... 
         chan(in2_ind).*(delta_R).*(1 - delta_C) + ... 
         chan(in3_ind).*(1 - delta_R).*(delta_C) + ... 
         chan(in4_ind).*(delta_R).*(delta_C); 
     out(:,:,idx) = cast(tmp, class(im)); 
    end 

Take powyższy kod, skopiuj i wklej go do pliku o nazwie bilinearInterpolation.m i zapisz go. Upewnij się, że zmieniłeś katalog roboczy, w którym zapisałeś ten plik.


wyjątkiem sub2ind a może meshgrid, wszystko wydaje się być zgodne z algorytmem. meshgrid jest bardzo łatwy do wytłumaczenia. Wszystko, co robisz, to określanie współrzędnych 2D o współrzędnych (x,y), gdzie każda lokalizacja na obrazku ma parę (x,y) lub współrzędnych kolumny i wiersza. Tworzenie siatki przez meshgrid pozwala uniknąć pętli for, ponieważ będziemy generować wszystkie właściwe lokalizacje pikseli z algorytmu, który jest nam potrzebny, zanim będziemy kontynuować.

Jak sub2ind dzieła jest to, że odbywa się w miejscu wiersza i kolumny w matrycy 2D (no ... to może być naprawdę dowolny ilość wymiarów chcesz), a to generuje pojedynczy indeks liniowej. Jeśli nie wiesz, w jaki sposób MATLAB indeksuje do macierzy, istnieją dwa sposoby uzyskania dostępu do elementu w macierzy. Możesz użyć wiersza i kolumny, aby uzyskać to, co chcesz, lub możesz użyć indeksu kolumna-major. Spójrz na ten przykład macierzy Mam poniżej:

A = 

1 2 3 4 5 
6 7 8 9 10 
11 12 13 14 15 

Jeśli chcemy uzyskać dostęp do numeru 9, możemy zrobić A(2,4) który jest co większość ludzi zazwyczaj domyślnie. Istnieje inny sposób uzyskania dostępu do numeru 9 za pomocą jednego numeru, który jest A(11) ... jak to się dzieje? MATLAB określa pamięć swoich matryc w formacie kolumna-major.Oznacza to, że jeśli były do ​​podjęcia tej matrycy i stack wszystkich swoich kolumn razem w jednej tablicy, to będzie wyglądać następująco:

A = 

1 
6 
11 
2 
7 
12 
3 
8 
13 
4 
9 
14 
5 
10 
15 

Teraz, jeśli chcesz uzyskać dostęp do elementu numer 9, byś Potrzebuję dostępu do 11 elementu tej tablicy. Powrót do bitu interpolacji, sub2ind ma kluczowe znaczenie, jeśli chcesz uzyskać dostęp do elementów w obrazie w celu utworzenia interpolacji bez wykonywania pętli for. W związku z tym, jeśli spojrzysz na ostatni wiersz pseudokodu, chcemy uzyskać dostęp do elementów pod r, c, r+1 i c+1. Zauważ, że wszystkie z nich to tablice 2D, gdzie każdy element w każdej z pasujących lokalizacji we wszystkich tych tablicach informuje nas o czterech pikselach, z których musimy pobrać próbki, aby uzyskać końcowy piksel wyjściowy. Dane wyjściowe z sub2ind będą również tablicami 2D o tym samym rozmiarze co obraz wyjściowy. Kluczem tutaj jest to, że każdy element 2D tablice r, c, r+1 i c+1 da nam kolumny główne indeksy do obrazu, który chcemy uzyskać dostęp, a rzucając to jako wkład do obrazu do indeksowania , otrzymamy dokładnie te lokalizacje pikseli, które chcemy.


Istnieje kilka ważnych subtelności, które chciałbym dodać podczas realizacji algorytmu:

  1. Musisz upewnić się, że wszelkie indeksy dostępu do obrazu podczas interpolacji poza obrazem są albo ustaw na 1 lub liczbę wierszy lub kolumn, aby upewnić się, że nie wyjdziesz poza granice. W rzeczywistości, jeśli rozciągasz się w prawo lub pod obrazem, musisz ustawić tę wartość na jedną poniżej na maksimum, ponieważ interpolacja wymaga dostępu do pikseli do jednego z prawej lub poniżej. Zapewni to, że nadal jesteś w granicach.

  2. Należy również upewnić się, że obraz wyjściowy jest rzutowany na tę samą klasę, co obraz wejściowy.

  3. Przebiegłem pętlę for, aby interpolować każdy kanał na własną rękę. Możesz to zrobić inteligentnie, używając bsxfun, ale zdecydowałem się użyć pętli for dla uproszczenia, abyś mógł podążać za algorytmem.


Jako przykład, aby pokazać to działa, użyjmy onion.png obraz, który jest częścią ścieżki systemowej Matlaba. Oryginalne wymiary tego obrazu to 135 x 198. Załóżmy interpolacji tego obrazu przez co większe, będzie 270 x 396 który jest dwukrotnie większy od oryginalnego obrazu:

im = imread('onion.png'); 
out = bilinearInterpolation(im, [270 396]); 
figure; 
imshow(im); 
figure; 
imshow(out); 

Powyższy kod interpolacji obrazu poprzez zwiększenie każdy wymiar przez dwa razy tyle, a następnie przedstawiają postać z oryginalny obraz i inna postać ze skalowanym obrazem.To, co mam do obu:

enter image description here

enter image description here


Podobnie, niech zmniejszyć obraz w dół o połowę za dużo:

im = imread('onion.png'); 
out = bilinearInterpolation(im, [68 99]); 
figure; 
imshow(im); 
figure; 
imshow(out); 

Należy zauważyć, że połowa z 135 67,5 dla wierszy, ale zaokrąglono do 68. Otrzymuję:

enter image description here

enter image description here


Jedno zauważyłem jest to, że w praktyce z Upsampling bilinear ma przyzwoitą wydajność w porównaniu do innych systemów, takich jak bicubic ... lub nawet Lanczos. Jednak podczas zmniejszania obrazu, ponieważ usuwasz szczegóły, najbliższy sąsiad jest bardzo wystarczający. Uważam, że bilinear lub bicubic to przesada. Nie jestem pewien co to jest twoja aplikacja, ale korzystaj z różnych algorytmów interpolacji i zobacz, co ci się podoba w wynikach. Bicubic to kolejna historia, a ja zostawię to jako ćwiczenie. Te slajdy, do których cię poleciłem, mają materiał na temat interpubacji bikubicznej, jeśli jesteś zainteresowany.


Powodzenia!

+0

możesz wyjaśnić sub2ind ([in_rows, in_cols], r, c); ... Dziękuję bardzo! – teardrop

+1

@teardrop - będę edytować mój post, aby dać ci bardziej szczegółowe wyjaśnienie, co robi 'sub2ind'. – rayryeng

+0

Wykłady (Richard Alan Peters II) są świetne. Ten link jednak już nie działa. Znalazłem slajdy [tutaj] (https://archive.org/details/Lectures_on_Image_Processing). Pokazany slajd pojawia się w 15. wykładzie, slajd numer 58. – ADB

Powiązane problemy