Jądro (przetwarzanie obrazu) - Kernel (image processing)
W przetwarzaniu obrazu , w jądrze , matrycy splotu lub maska jest mała matryca wykorzystywane do zatarcia, ostrzenia, wytłaczanie, detekcja krawędzi i innych. Osiąga się to poprzez splot pomiędzy jądrem a obrazem .
Detale
Ogólnym wyrazem splotu jest
gdzie jest filtrowany obraz, jest oryginalnym obrazem, jest jądrem filtra. Każdy element jądra filtru jest rozpatrywany przez i .
W zależności od wartości pierwiastków jądro może wywołać szeroki zakres efektów.
Operacja | Jądro | Wynik obrazu g(x,y) |
---|---|---|
Tożsamość | ||
Wykrywanie krawędzi | ||
Wyostrzyć | ||
Rozmycie pola ( znormalizowane ) |
||
Rozmycie Gaussa 3 × 3 (przybliżenie) |
||
Rozmycie Gaussa 5 × 5 (przybliżenie) |
||
Maskowanie wyostrzające 5 × 5 Na podstawie rozmycia Gaussa z wartością 1 i progiem 0 (bez maski obrazu ) |
|
Powyższe to tylko kilka przykładów efektów, które można osiągnąć dzięki splataniu jąder i obrazów.
Początek
Pochodzenie to pozycja jądra, która znajduje się powyżej (konceptualnie) bieżącego piksela wyjściowego. Może to być poza samym jądrem, chociaż zwykle odpowiada jednemu z elementów jądra. W przypadku jądra symetrycznego pochodzenie jest zwykle elementem centralnym.
Skręt
Konwolucja to proces dodawania każdego elementu obrazu do jego lokalnych sąsiadów, ważonych przez jądro. Wiąże się to z formą splotu matematycznego . Wykonywana operacja macierzowa — splot — nie jest tradycyjnym mnożeniem macierzy, mimo że jest podobnie oznaczona przez *.
Na przykład, jeśli mamy dwie macierze trzy na trzy, pierwsza jest jądrem, a druga fragmentem obrazu, splot jest procesem odwracania zarówno wierszy, jak i kolumn jądra oraz mnożenia lokalnie podobnych wpisów i sumowania. Element o współrzędnych [2, 2] (czyli element centralny) wynikowego obrazu byłby ważoną kombinacją wszystkich wpisów macierzy obrazu, z wagami podanymi przez jądro:
Pozostałe wpisy byłyby podobnie ważone, gdzie umieszczamy środek jądra na każdym z punktów granicznych obrazu i obliczamy sumę ważoną.
Wartości danego piksela w obrazie wyjściowym są obliczane przez pomnożenie każdej wartości jądra przez odpowiednie wartości pikseli obrazu wejściowego. Można to opisać algorytmicznie za pomocą następującego pseudokodu:
for each image row in input image: for each pixel in image row: set accumulator to zero for each kernel row in kernel: for each element in kernel row: if element position corresponding* to pixel position then multiply element value corresponding* to pixel value add result to accumulator endif set output image pixel to accumulator
- *odpowiadające piksele obrazu wejściowego są znalezione w stosunku do źródła jądra.
Jeśli jądro jest symetryczne, umieść środek (początek) jądra na bieżącym pikselu. Jądro nałoży się na sąsiednie piksele wokół punktu początkowego. Każdy element jądra należy pomnożyć przez wartość piksela, na którą się nakłada, a wszystkie otrzymane wartości należy zsumować. Ta wynikowa suma będzie nową wartością dla bieżącego piksela, który aktualnie nakłada się na środek jądra.
Jeśli jądro nie jest symetryczne, przed obliczeniem splotu jak powyżej należy je odwrócić zarówno wokół osi poziomej, jak i pionowej.
Ogólna postać splotu macierzy to
Obsługa krawędzi
Splot jądra zwykle wymaga wartości z pikseli znajdujących się poza granicami obrazu. Istnieje wiele metod obsługi krawędzi obrazu.
- Rozszerzyć
- Najbliższe piksele obramowania są koncepcyjnie rozciągnięte na tyle, na ile jest to konieczne, aby zapewnić wartości dla splotu. Piksele narożne są rozciągane w klinach 90°. Inne piksele krawędzi są rozciągane liniami.
- Zawinąć
- Obraz jest koncepcyjnie zawinięty (lub kafelkowany), a wartości są pobierane z przeciwległej krawędzi lub narożnika.
- Lustro
- Obraz jest koncepcyjnie lustrzany na krawędziach. Na przykład próba odczytania pikseli 3 jednostek poza krawędzią odczytuje zamiast tego jedną 3 jednostki wewnątrz krawędzi.
- Przyciąć
- Każdy piksel w obrazie wyjściowym, który wymagałby wartości spoza krawędzi, jest pomijany. Ta metoda może spowodować, że obraz wyjściowy będzie nieco mniejszy, a krawędzie zostaną przycięte.
- Uprawa jądra
- Żaden piksel w jądrze, który wykracza poza obraz wejściowy, nie jest używany, a normalizacja jest dostosowywana w celu kompensacji.
Normalizacja
Normalizacja jest definiowana jako podział każdego elementu jądra przez sumę wszystkich elementów jądra, tak aby suma elementów znormalizowanego jądra była jednością. Dzięki temu średni piksel w zmodyfikowanym obrazie będzie tak jasny, jak przeciętny piksel w oryginalnym obrazie.
Konkretna realizacja
Oto konkretna implementacja konwolucji wykonana za pomocą języka cieniowania GLSL :
// author : csblo
// Work made just by consulting :
// https://en.wikipedia.org/wiki/Kernel_(image_processing)
// Define kernels
#define identity mat3(0, 0, 0, 0, 1, 0, 0, 0, 0)
#define edge0 mat3(1, 0, -1, 0, 0, 0, -1, 0, 1)
#define edge1 mat3(0, 1, 0, 1, -4, 1, 0, 1, 0)
#define edge2 mat3(-1, -1, -1, -1, 8, -1, -1, -1, -1)
#define sharpen mat3(0, -1, 0, -1, 5, -1, 0, -1, 0)
#define box_blur mat3(1, 1, 1, 1, 1, 1, 1, 1, 1) * 0.1111
#define gaussian_blur mat3(1, 2, 1, 2, 4, 2, 1, 2, 1) * 0.0625
#define emboss mat3(-2, -1, 0, -1, 1, 1, 0, 1, 2)
// Find coordinate of matrix element from index
vec2 kpos(int index)
{
return vec2[9] (
vec2(-1, -1), vec2(0, -1), vec2(1, -1),
vec2(-1, 0), vec2(0, 0), vec2(1, 0),
vec2(-1, 1), vec2(0, 1), vec2(1, 1)
)[index] / iResolution.xy;
}
// Extract region of dimension 3x3 from sampler centered in uv
// sampler : texture sampler
// uv : current coordinates on sampler
// return : an array of mat3, each index corresponding with a color channel
mat3[3] region3x3(sampler2D sampler, vec2 uv)
{
// Create each pixels for region
vec4[9] region;
for (int i = 0; i < 9; i++)
region[i] = texture(sampler, uv + kpos(i));
// Create 3x3 region with 3 color channels (red, green, blue)
mat3[3] mRegion;
for (int i = 0; i < 3; i++)
mRegion[i] = mat3(
region[0][i], region[1][i], region[2][i],
region[3][i], region[4][i], region[5][i],
region[6][i], region[7][i], region[8][i]
);
return mRegion;
}
// Convolve a texture with kernel
// kernel : kernel used for convolution
// sampler : texture sampler
// uv : current coordinates on sampler
vec3 convolution(mat3 kernel, sampler2D sampler, vec2 uv)
{
vec3 fragment;
// Extract a 3x3 region centered in uv
mat3[3] region = region3x3(sampler, uv);
// for each color channel of region
for (int i = 0; i < 3; i++)
{
// get region channel
mat3 rc = region[i];
// component wise multiplication of kernel by region channel
mat3 c = matrixCompMult(kernel, rc);
// add each component of matrix
float r = c[0][0] + c[1][0] + c[2][0]
+ c[0][1] + c[1][1] + c[2][1]
+ c[0][2] + c[1][2] + c[2][2];
// for fragment at channel i, set result
fragment[i] = r;
}
return fragment;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
// Convolve kernel with texture
vec3 col = convolution(emboss, iChannel0, uv);
// Output to screen
fragColor = vec4(col, 1.0);
}
Bibliografia
- Ludwig, Jamie (nd). Konwolucja obrazu (PDF) . Uniwersytet Stanowy w Portland .
- Lecarme, Olivier; Delvare, Karine (styczeń 2013). Księga GIMP: kompletny przewodnik po prawie wszystkim . Bez skrobi Prasa . P. 429. ISBN 978-1593273835.
- Gumster, Jason van; Szymoński, Robert (marzec 2012). Biblia GIMP-a . Wiley . s. 438–442. Numer ISBN 978-0470523971.
- Shapiro, Linda G .; Stockman, George C. (luty 2001). Wizja komputerowa . Sala urzędnicza . s. 53–54. Numer ISBN 978-0130307965.
Zobacz też
Zewnętrzne linki
- Implementacja konwolucji 2D na FPGA
- Przewodnik programowania vImage: Wykonywanie operacji splotu
- Przetwarzanie obrazu za pomocą konwolucji 2D
- Program do manipulacji obrazem GNU - Podręcznik użytkownika - 8.2. Macierz konwolucji
- GLSL Demonstracja jąder konwolucji 3x3
- Kompletny projekt open source C++