Octave - szybkie klejenie obrazków cz. 2
Pierwszą część skończyłem pytaniem:
A co będzie, jak obrazki sklejane obok siebie będę różnej wysokości, albo sklejane jeden pod drugim będą różnej szerokości?
A jaka jest odpowiedź? Ano taka, że da się zrobić, ale nie ma to już tak dużego sensu. Trwa to dłużej i trzeba w tym celu przyswoić nieco więcej wiedzy. Wpis niniejszy traktujcie więc jako gawędę na temat tego co jak w Octave'ie wygląda.
Przyjmijmy, że mamy dwa obrazki: a.png i b.png, pierwszy z nich ma rozmiary 640x480, a drugi 600x400 pikseli. Wczytajmy je: "a=imread('a.png'); b=imread('b.png');" i sprawdźmy ich rozmiar funkcją size:
octave-3.2.4:1> size(a) ans = 480 640 3 octave-3.2.4:2> size(b) ans = 400 600 3
Wynik może odbiegać od oczekiwań. Rozmiary macierzy zawsze podawane są w tej kolejności: najpierw liczba wierszy, potem liczba kolumn. Zawsze!(i jeszcze parę wykrzykników) W sprawach związanych z wyświetlaniem w komputerze, oś "x" jest pozioma, zorientowana w prawo, a oś "y" pionowa, zorientowana w dół. Kłócą się tu dwie konwencje, stąd ten "rozjazd". Konwencja macierzowa ma wyższy priorytet choćby z racji wieku. Dlatego "480 640", zamiast spodziewanych "640 480". A co robi tam jeszcze trójka? Wysokość, szerokość, głębokość? Trójka oznacza trzy warstwy kolorystyczne: pierwsza warstwa, to kolor czerwony, druga to zielony, trzecia - niebieski. W poprzednim odcinku napisałem, że macierze wzięte z obrazków zawierają liczby z od 0 do 255. Te liczby to oczywiście składowe RGB. Jeden piksel to wektor trzech składowych - wektor brany "wgłąb" z macierzy. No i jeszcze "ans" trzeba wyjaśnić: jest to zmienna tworzona automagicznie, jej nazwa to skrót od "answer".
Trochę teorii
Zanim pójdziemy dalej, trochę o macierzach i środowisku w ogóle. W Octave'ie wszystko (no, prawie wszystko) jest macierzą. Octave jest liberalny, jeśli chodzi o typy danych. Octave numeruje po ludzku - od 1. Dlatego możliwe jest takie coś: tworzymy zmienną całkowitoliczbową, przerabiamy ją na wektor liczb (pseudo)rzeczywistych, następnie na macierz dwuwymiarową i w końcu trójwymiarową:
octave-3.2.4:2> p=1 p = 1 octave-3.2.4:3> p(3)=1/2 p = 1 0 0.5 octave-3.2.4:4> p(4,4)=0.5 p = 1 0 0.5 0 0 0 0 0 0 0 0 0 0 0 0 0.5 octave-3.2.4:5> p(5,5,3)=0 p = ans(:,:,1) = 1 0 0.5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0 0 0 0 0 0 ans(:,:,2) = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ans(:,:,3) = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Jak widać, macierz trójwymiarowa wyświetlana jest warstwami, wygodnie.
Wiedząc to wszystko, możemy przygotować klej, nożyczki i brać się za robotę.
Klejenie
W przypadku klejenia wzdłuż poziomej krawędzi, obrazek wynikowy ma mieć wysokość 880 i szerokość 640 pikseli. W przypadku klejenia wzdłuż pionowej krawędzi, obrazek wynikowy ma mieć wysokość 480 i szerokość 1240 pikseli. W obu przypadkach problemem jest drugi obrazek. Sposobów na to jest kilka. 1. Dolepienie trzeciej macierzy, która uzupełni brakujący kawałek. 2. Rozszerzenie drugiego obrazka o odpowiedni kawałek (to nie to samo, co 1.). 3. Utworzenie macierzy, która będzie pełniła funkcję "podkładu" pod klejone obrazki.
Omówię wszystkie te sposoby.
Trzecia macierz
Wywołanie dla łączenia obok siebie będzie takie:
c=[a,[b;d]]
a dla łączenia w pionie:
c=[a;b,e]
gdzie d i e to wypełniacze. Wypełniacz e, jeśli ma być czarny, będzie macierzą samych zer, o wymiarach 400 na 40 na 3, więc wpisujemy:
e=zeros(400,40,3);
jeśli biały, to potrzebujemy wszędzie 255:
e=255*ones(400,40,3);
a jeśli inny kolor (o składowych R, G i B), to trzeba kombinować z notacją dwukropkową:
e=R*ones(400,40); e(1:400,1:40,2)=G*ones(400,40); e(1:400,1:40,3)=B*ones(400,40);
gdzie "m:n" oznacza "od m do n co jeden".
Rozszerzenie macierzy
Tu sprawa jest prostsza, ale ma to sens tylko dla czarnego paska:
b(640,400,1)=0; c=[a;b];
Macierz-tło Tworzymy macierz z wybranym kolorem, o rozmiarach docelowych (dla uproszczenia biorę czarny):
c=zeros(840,640,3);
i żeby nie było potem problemów, zmieniamy na siłę jej typ, z "double" na "uint8" (w razie jakichś problemów, których nie przewidziałem, to może pomóc):
c=uint8(c);
Następnie wklejamy do niej a i b:
c(1:480,1:640,:)=a; c(481:880,1:600,:)=b;
gdzie ":" oznacza "od początku do końca" i jest równoważne "1:end".
Pozostaje zapisać.
Na koniec dwie ciekawostki: 1. są obrazki, które dają macierz o trzecim wymiarze równym 4 - kto wie czemu, ręka do góry ;) 2. pewne formaty graficzne można importować do innej postaci: macierz dwuwymiarowa z numerami kolorów + mapa z kolorami. Tematem obrazków jeszcze Was z raz pomęczę.