W ramach tego materiału będziemy będziemy zajmować się poznawaniem innych rozwiązań i zagadnień związanych z pracą z obrazem w środowisku Python. Będziemy operować na poniższym zestawie bibliotek:

Do zainstalowania tych bibliotek wykorzystujemy zestaw komend pip:

pip install numpy
pip install Pillow
pip install matplotlib
pip install scikit-image
pip install opencv-contrib-python

W przypadku pracowania na terminalach należy zainstalować je jako wersje tylko dla bieżącego użytkownika:

pip install numpy --user
pip install Pillow --user
pip install matplotlib --user
pip install scikit-image --user
pip install opencv-contrib-python --user

Importujemy je standardowo do środowiska jako:

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import skimage.io as io
import cv2

Obraz wyświetlany na ekranie komputera w modelu kolorów RGB rozumiemy jako siatkę pikseli, gdzie każdy piksel jest opisany przez trzy wartości, odpowiadające kanałom R (czerwony), G (zielony) i B (niebieski). Piksel czarny to \((0, 0, 0)\) dla obrazu uitn8, #000000 w hex lub \((0, 0, 0)\) dla obrazu w float, a piksel biały to \((255, 255, 255)\) dla obrazu uitn8, #FFFFFF w hex lub \((1, 1, 1)\) dla obrazu w float. Wczytywanie obrazów przy użyciu poleceń Pythona może być wykonane na różne sposoby, jednakże dalsze kroki przetwarzania obrazu będą determinować, która biblioteka okaże się najbardziej przydatna. Standardowe operacje geometryczne znane z oprogramowania do obróbki grafiki rastrowej, takie jak obrót czy skalowanie, znajdziemy w bibliotece Pillow. Bardziej zaawansowane przekształcenia, w bibliotekach Scikit-image i OpenCV. Jednakże, gdy spojrzymy na obrazy jak na macierze liczb, wówczas do operacji numerycznych najbardziej przydatna będzie biblioteka NumPy, zaś do wizualizacji danych biblioteka Matplotlib. Za algorytmami przetwarzania obrazów stoi wiele aspektów matematycznych, które będziemy próbować zrozumieć i zaimplementować samodzielnie bez użycia gotowych rozwiązań. Poniżej znajduje się kilka przydatnych poleceń, ze szczególnym uwzględnieniem biblioteki Matplotlib.

Podstawowe informacje i komendy

  1. Wczytywanie obrazów

    #pillow
    obraz = Image.open(‘nazwa_pliku.rozszerzenie’)
    #matplotlib
    obraz = plt.imread(‘nazwa_pliku.rozszerzenie’)
    #skimage
    obraz = io.imread(‘nazwa_pliku.rozszerzenie’)
    #OpenCV
    obraz = cv2.imread(‘nazwa_pliku.rozszerzenie’)
  2. Wyświetlanie obrazów

    #pillow
    obraz.show()
    #matplotlib
    plt.imshow(obraz)
    plt.show()
    #skimage
    io.imshow(obraz)
    #OpenCV
    cv2.imshow('image', obraz)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
  3. Zapisywanie obrazów

    #pillow
    obraz.save(‘nazwa_pliku.rozszerzenie’)
    #matplotlib
    plt.imsave(‘nazwa_pliku.rozszerzenie’, obraz, args)
    #skimage
    io.imsave(‘nazwa_pliku.rozszerzenie’,obraz)
    #OpenCV
    cv2.imwrite(‘nazwa_pliku.rozszerzenie’,obraz)
  4. Sprawdzanie typu danych i rozmiaru wczytanego pliku

    #pillow
    print(obraz.format)
    print(obraz.size)
    #matplotlib
    print(obraz.dtype)
    print(obraz.shape)
  5. Zmiana przestrzeni koloru

    • Przekształcenie obrazu kolorowego do obrazu w skali odcieni szarości:

      Y= 0.299 *R + 0.587* G + 0.114 * B
      Y= 0.2126 *R + 0.7152* G+ 0.0722 * B
      Y = cv2.cvtColor(img_BGR, cv2.COLOR_BGR2GRAY)
      Y = cv2.cvtColor(img_RGB, cv2.COLOR_RGB2GRAY)
    • Zamiana przestrzeni koloru przy wykorzystaniu OpenCV: Zamiana odbywa się przy użyciu odpowiedniej funkcji oraz Flagi określającej przestrzeń koloru zarówno źródła, jak i celu. Zmiany można dokonywać zarówno dla obrazów na uint8 jak i float. Pełna lista flag

      img_BGR = cv2.cvtColor(img_RGB, cv2.COLOR_RGB2BGR)
    • Zamiana przestrzeni koloru przy wykorzystaniu PIL: Poniżej kilka przykładów wykorzystania biblioteki PIL do zmiany przestrzeni koloru. Pełna list przestrzeni.

      # Na Pillow Image
      img.conver('CMYK`)
      # Z i do numpy array na uint8
      np.asarray(Image.fromarray(np.uint8(I), 'RGB').convert('CMYK'))
      # Z i do numpy array na float
      np.asarray(Image.fromarray(np.uint8(I*255), 'RGB').convert('CMYK'))/255
  6. Przydatne przekształcenia

    • Wyświetlanie jednej warstwy/jednego kanału koloru obrazu:

      plt.imshow(obraz[:,:,?])
    • Wyświetlenie obrazu w skali szarości (vmin i vmax są opcjonalne):

      plt.imshow(obraz, cmap=’gray’, vmin=?, vmax=?)
    • Wyświetlanie wielu obrazów w jednym oknie:

      plt.subplot(w, k, n) #wiersze, kolumny, n - który z kolei
    • Sprawdzenie wartości minimalnej/maksymalnej macierzy obrazu:

      print(np.min(Y))
      print(np.max(Y))

Zadania

  1. Zapisz dwa pliki wykorzystywane w ramach dzisiejszych zajęć: Prom kosmiczny oraz astronautkę
  2. Wczytaj oba zdjęcia za pomocą wszystkich bibliotek. Sprawdź, w jakiej formie są one wczytane (rodzaj zmiennej, typ danych).
  3. Spróbuj wyświetlić poszczególne wczytane obrazy za pomocą wszystkich bibliotek (każdy z wczytanych obrazów za pomocą jednej biblioteki można wyświetlić za jej pomocą, jak również za pomocą trzech pozostałych). Zaobserwuj, jakie są z tym problemy.
  4. Wyświetl obraz spacecraft.png w skali szarości – wykorzystaj plt.imshow() z parametrami uzupełniając odpowiednie wartości dla vmin i vmax. Następnie przypisz do zmiennej jeden kanał obrazu i wyświetl w ten sam sposób. Czy obrazy wyświetlają się poprawnie? Porównaj rozmiary obu zmiennych. Następnie przekształć obraz do skali odcieni szarości i porównaj obraz wyświetlony w skali szarości z obrazem przekształconym do skali szarości (Y)
  5. Przekształć oba obrazy do skali odcieni szarości i zapisz je do plików, deklarując odpowiednie parametry. Pliki powinny nazywać się odpowiednio astronaut_gray.jpg i spacecraft_gray.png
  6. Wykorzystując wiedzę ogólną, załączone odnośniki, załączone obrazy i samodzielnie generując dane testowe, odpowiedz na kilka pytań dotyczących innych przestrzeni koloru CMYK, YCbCr, HSV, Lab itd.:
    1. Jak zachowują się, pliki skonwertowane do innych przestrzeni koloru?
    2. Jakie zakresy wartości zajmują poszczególne warstwy?
    3. Jak to sprawdzić?