01 - Wprowadzenie

Przetwarzanie i Analiza Obrazów

Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej

Ćwiczenie laboratoryjne 1: Python i biblioteki - przypomnienie

Powrót do spisu treści ćwiczeń laboratoryjnych

W tym ćwiczeniu: - Poznajemy język programowania Python oraz jego składnię. - Zapoznajemy się z podstawowymi funkcjami i metodami wbudowanymi w Pythonie. - Wprowadzamy biblioteki OpenCV i NumPy, które będą kluczowe dla pracy z obrazami w kolejnych ćwiczeniach.

Wstęp - język programowania Python

Na zajęciach wykorzystywać będziemy język programowania Python oraz biblioteki dedykowane przetwarzaniu obrazów oraz – w mniejszym stopniu – uczeniu maszynowemu.

Python to język programowania wysokiego poziomu ogólnego przeznaczenia, o rozbudowanym pakiecie bibliotek standardowych, którego ideą przewodnią jest czytelność i klarowność kodu źródłowego. Jego składnia cechuje się przejrzystością i zwięzłością. Python wspiera różne paradygmaty programowania: obiektowy, imperatywny oraz w mniejszym stopniu funkcyjny. Posiada w pełni dynamiczny system typów i automatyczne zarządzanie pamięcią, będąc w tym podobnym do języków Perl, Ruby, Scheme czy Tcl. Podobnie jak inne języki dynamiczne jest często używany jako język skryptowy. Interpretery Pythona są dostępne na wiele systemów operacyjnych. Python rozwijany jest jako projekt Open Source zarządzany przez Python Software Foundation, która jest organizacją non-profit. Standardową implementacją języka jest CPython (napisany w C), ale istnieją też inne. (źródło: Wikipedia)

Skrypty pythonowe

Skrypty pythonowe to pliki tekstowe zawierające kod źródłowy napisany w języku Python. Skrypty te mogą być uruchamiane bezpośrednio przez interpreter Pythona, co pozwala na wykonywanie różnych zadań, takich jak automatyzacja, analiza danych, tworzenie aplikacji webowych, czy też przetwarzanie obrazów. Skrypty pythonowe mają rozszerzenie .py i mogą być tworzone i edytowane za pomocą dowolnego edytora tekstu lub zintegrowanego środowiska programistycznego (IDE). Aby uruchomić skrypt pythonowy, wystarczy użyć polecenia python nazwa_skryptu.py w terminalu lub wierszu poleceń, pod warunkiem, że Python jest zainstalowany i skonfigurowany na danym systemie. Skrypty pythonowe są szeroko stosowane w różnych dziedzinach, od nauki danych po tworzenie gier, i stanowią podstawę dla wielu projektów programistycznych.

Wybór środowiska programistycznego

💥 Zadanie do wykonania 💥

Otwórz wybrany edytor kodu i utwórz nowy plik o nazwie main.py. Następnie wpisz poniższy kod:

print("Witaj w świecie przetwarzania i analizy obrazów!")

Zapisz plik i uruchom go, aby zobaczyć efekt działania.

Składnia języka Python

Składnia języka Python jest prosta i czytelna, co czyni go łatwym do nauki dla początkujących programistów. Oto kilka podstawowych elementów składni Pythona:

# To jest komentarz w Pythonie
x = 10
y = "Hello, World!"
z = 3.14
def greet(name):
    return f"Hello, {name}!"
# Pętla for (iteracja po zakresie)
for i in range(5):
    print(i)

# Pętla for (iteracja po liście)
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

# Pętla while
count = 0
while count < 5:
    print(count)
    count += 1
age = 18
if age < 18:
    print("Niepełnoletni")
elif age == 18:
    print("Pełnoletni")
else:
    print("Dorosły")
import numpy as np # Importowanie biblioteki NumPy do obliczeń numerycznych
import cv2 # Importowanie biblioteki OpenCV do przetwarzania obrazów
def example_function():
    print("To jest blok kodu wewnątrz funkcji.")
    if True:
        print("To jest blok kodu wewnątrz instrukcji warunkowej.")
# Lista - mutowalna, uporządkowana kolekcja elementów
my_list = [1, 2, 3, 4, 5]

# Krotka - niemutowalna, uporządkowana kolekcja elementów
my_tuple = (1, 2, 3, 4, 5)

# Słownik - mutowalna, nieuporządkowana kolekcja par klucz-wartość
my_dict = {"name": "Alice", "age": 30, "city": "New York"}

Wybrane metody i funkcje wbudowane

Python oferuje wiele wbudowanych funkcji, które ułatwiają pracę z danymi i kodem. Oto kilka z nich:

print("Hello, World!")
my_list = [1, 2, 3, 4, 5]
print(len(my_list)) # Output: 5
x = 10
print(type(x)) # Output: <class 'int'>
for i in range(5):
    print(i) # Output: 0, 1, 2, 3, 4
name = input("Podaj swoje imię: ")
print(f"Witaj, {name}!")
numbers = [1, 2, 3, 4, 5]
print(max(numbers)) # Output: 5
print(min(numbers)) # Output: 1
numbers = [5, 2, 3, 1, 4]
print(sorted(numbers)) # Output: [1, 2, 3, 4, 5]

💥 Zadanie do wykonania 💥

Napisz skrypt, który poprosi użytkownika o podanie trzech liczb, a następnie wyświetli największą z nich. Użyj funkcji input(), max() i print().

OpenCV - biblioteka do przetwarzania obrazów

Na tych zajęciach będziemy korzystać z biblioteki OpenCV (Open Source Computer Vision Library), która jest jedną z najpopularniejszych bibliotek do przetwarzania obrazów i analizy wideo. OpenCV oferuje szeroki zakres funkcji do manipulacji obrazami, detekcji obiektów, rozpoznawania twarzy, analizy ruchu i wielu innych zastosowań związanych z wizją komputerową. Jej naukę zaczniemy na kolejnym ćwiczeniu, a tym czasem skupimy się na poznaniu biblioteki NumPy, która jest kluczowa dla pracy z obrazami w Pythonie.

NumPy - podstawowa biblioteka do obliczeń numerycznych

NumPy (Numerical Python) to podstawowa biblioteka Pythona do obliczeń numerycznych. Oferuje ona potężne narzędzia do pracy z dużymi, wielowymiarowymi tablicami i macierzami danych, a także funkcje matematyczne do operacji na tych strukturach.

Bibliotkę tę można zaimportować za pomocą polecenia:

import numpy as np # Importowanie biblioteki NumPy i nadanie jej aliasu 'np' - jest to powszechnie stosowana konwencja w społeczności Pythona.

Uwaga:
Obrazy cyfrowe są często reprezentowane jako tablice numeryczne, gdzie każdy element tablicy odpowiada wartości piksela. Dlatego znajomość biblioteki NumPy jest kluczowa dla przetwarzania i analizy obrazów.

Jak stworzyć tablicę NumPy?

Tablice (macierze, wektory, tensory) w NumPy można tworzyć na wiele sposobów, w zależności od potrzeb. Oto kilka podstawowych metod tworzenia tablic NumPy:

# Tworzenie tablicy NumPy z listy
my_list = [1, 2, 3, 4, 5]
my_array = np.array(my_list)
print(my_array) # Output: [1 2 3 4 5]

# Tworzenie tablicy NumPy z listy list (2D)
my_2d_list = [[1, 2, 3], [4, 5, 6]]
my_2d_array = np.array(my_2d_list)
print(my_2d_array)
# Output:
# [[1 2 3]
#  [4 5 6]]

# Tworzenie tablicy NumPy z zakresu liczb
my_range_array = np.arange(0, 10, 2) # Tworzy tablicę z liczbami od 0 do 10 z krokiem 2
print(my_range_array) # Output: [0 2 4 6 8]

# Tworzenie tablicy NumPy wypełnionej zerami
zeros_array = np.zeros((3, 3)) # Tworzy tablicę 3x3 wypełnioną zerami
print(zeros_array)
# Output:
# [[0. 0. 0.]
#  [0. 0. 0.]
#  [0. 0. 0.]]

# Tworzenie tablicy NumPy wypełnionej wybranym wartością
full_array = np.full((2, 4), 7) # Tworzy tablicę 2x4 wypełnioną wartością 7
print(full_array)
# Output:
# [[7 7 7 7]
#  [7 7 7 7]]

Typy danych w tablicach NumPy

Tablice NumPy mogą przechowywać różne typy danych, takie jak liczby całkowite, liczby zmiennoprzecinkowe, liczby zespolone, a także dane tekstowe. Domyślnie, NumPy dla liczb całkowitych używa typu int64, a dla liczb zmiennoprzecinkowych typu float64. Można jednak określić inny typ danych podczas tworzenia tablicy lub zmienić go później. Typ danych w tablicy NumPy można sprawdzić za pomocą atrybutu dtype, oto kilka przykładów:

print(np.array([1, 2, 3]).dtype) # Output: int64

print(np.array([1.0, 2.0, 3.0]).dtype) # Output: float64

print(np.array(['abc', 'abc', 'abc']).dtype) # Output: <U3 (Unicode string of length 3)>

Typ danych można również określić podczas tworzenia tablicy korzystając z argumentu dtype:

my_array = np.array([1, 2, 3], dtype=np.float32)
print(my_array) # Output: [1. 2. 3.]
print(my_array.dtype) # Output: float32

my_array = np.array([1.0, 2.0, 3.0], dtype=np.int32)
print(my_array) # Output: [1 2 3]
print(my_array.dtype) # Output: int32

Uwaga:
Wybór odpowiedniego typu danych jest ważny, ponieważ wpływa na zużycie pamięci i wydajność operacji na tablicach. Na przykład, jeśli potrzebujesz przechowywać tylko liczby całkowite w zakresie od 0 do 255 (np. wartości pikseli obrazu), możesz użyć typu np.uint8, który jest domyślnie używany do reprezentacji obrazów w OpenCV.

Podstawowe operacje na tablicach NumPy

NumPy oferuje szeroki zakres operacji na tablicach, które są zoptymalizowane pod kątem wydajności. Oto kilka podstawowych operacji, które można wykonywać na tablicach NumPy:

# Tworzenie dwóch tablic NumPy
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# Rozmiar tablicy
print(a.shape) # Output: (3,)

# Dodawanie tablic
c = a + b
print(c) # Output: [5 7 9]

# Mnożenie tablic (element-wise)
d = a * b
print(d) # Output: [ 4 10 18]

# Dzielenie tablic (element-wise)
e = b / a
print(e) # Output: [4. 2.5 2.]

# Potęgowanie tablic (element-wise)
f = a ** 2
print(f) # Output: [1 4 9]

# Operacje na macierzach (dot product)
g = np.dot(a, b)
print(g) # Output: 32 (1*4 + 2*5 + 3*6)

# Transpozycja macierzy
h = np.array([[1, 2], [3, 4]])
print(h.T)
# Output:
# [[1 3]
#  [2 4]]

# Agregacja danych (np. suma, średnia)
print(np.sum(a)) # Output: 6
print(np.mean(a)) # Output: 2.0
print(np.max(a)) # Output: 3
print(np.min(a)) # Output: 1

Indeksowanie i slicing tablic NumPy

Indeksowanie i slicing w NumPy pozwala na dostęp do poszczególnych elementów, wierszy, kolumn lub podtablic w tablicy. Oto kilka przykładów:

# Tworzenie tablicy 2D
my_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# Sprawdzenie kształtu tablicy
print(my_array.shape) # Output: (3, 3)

# Indeksowanie pojedynczego elementu
print(my_array[0, 1]) # Output: 2 (element w pierwszym wierszu, drugiej kolumnie)

# Indeksowanie całego wiersza
print(my_array[1]) # Output: [4 5 6] (drugi wiersz)

# Indeksowanie całej kolumny
print(my_array[:, 2]) # Output: [3 6 9] (trzecia kolumna)

# Slicing (wycinanie) podtablicy
print(my_array[0:2, 1:3])
# Output:
# [[2 3]
#  [5 6]] 

Operacje logiczne i maskowanie tablic NumPy

NumPy umożliwia wykonywanie operacji logicznych na tablicach, co pozwala na tworzenie masek i filtrowanie danych. Oto kilka przykładów:

# Tworzenie tablicy NumPy
my_array = np.full((3, 3), 5, dtype=np.int32) # Tworzy tablicę 3x3 wypełnioną wartością 5

# Wpiszmy do tablicy kilka innych wartości
my_array[0, 0] = 1
my_array[1, 1] = 2
my_array[2, 2] = 3

print(my_array)
# Output:
# [[1 5 5]
#  [5 2 5]
#  [5 5 3]]

# Tworzenie maski logicznej (np. elementy większe niż 4)
mask = my_array > 4
print(mask)
# Output:
# [[False  True  True]
#  [ True False  True]
#  [ True  True False]]

# Filtrowanie danych za pomocą maski, np. zerowanie elementów mniejszych lub równych 4
filtered_array = np.where(mask, my_array, 0)
print(filtered_array)
# Output:
# [[0 5 5]
#  [5 0 5]
#  [5 5 0]]

Uwaga:
Operacje logiczne i maskowanie są szczególnie przydatne w przetwarzaniu obrazów, gdzie można łatwo filtrować piksele na podstawie ich wartości lub innych kryteriów, co jest kluczowe dla wielu algorytmów analizy obrazów. Jednocześnie, korzystanie z wbudowanych funkcji NumPy do operacji na tablicach jest znacznie bardziej wydajne niż ręczne iterowanie po elementach, co jest ważne przy pracy z dużymi obrazami.

💥 Zadanie do wykonania 💥

Napisz skrypt, który tworzy tablicę NumPy o wymiarach 5x5 wypełnioną wybranymi przez Ciebie wartościami. Następnie stwórz maskę logiczną, która zaznaczy elementy większe niż 10, i użyj tej maski do stworzenia nowej tablicy, w której elementy większe niż 10 pozostaną bez zmian, a pozostałe zostaną zastąpione zerami. Wyświetl obie tablice: oryginalną i przefiltrowaną.

💥 Zadanie do wykonania 💥

Mając listę średnich temperatur z ostatniego tygodnia: [20, 22, 19, 24, 21, 18, 23], użyj funkcji NumPy do obliczenia średniej temperatury, Następnie przelicz podaną temperaturę na skalę Fahrenheita i wyświetl wynik. (Wzór do przeliczenia: F = (C * 9/5) + 32).