diff --git a/.gitignore b/.gitignore index 0d2150a..62bea33 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ __pycache__/ .Python build/ virtual/ +wirtualka/ develop-eggs/ dist/ downloads/ diff --git a/dane_aj.csv b/dane_aj.csv new file mode 100644 index 0000000..fe94ffa --- /dev/null +++ b/dane_aj.csv @@ -0,0 +1,60 @@ +"pan Tymoteusz Fornalik","3579454591527662","PPUH Opioła-Franków i syn s.c.","plac Jaśminowa 42/38 ~ 82-249 Zambrów" +"Anastazja Kobza","4597865459252406","Oleksak-Nicewicz Sp.j.","pl. Rzeczna 028 ~ 78-208 Piotrków Trybunalski" +"pan Igor Madzia","213174349909859","Fundacja Kulis Sp. z o.o.","pl. Lelewela 03/08 ~ 93-852 Mielec" +"Miłosz Lenarcik","213113678367743","Dybaś Sp.k.","al. Szewska 90/80 ~ 78-042 Oświęcim" +"Cyprian Troć","213179982678067","Ruszczak-Ruszczak S.A.","aleja Źródlana 13 ~ 95-829 Sochaczew" +"pan Mariusz Rycerz","180061535819365","Cyrulik-Kuświk S.A.","plac Glówna 55 ~ 18-830 Ostrów Wielkopolski" +"Eliza Wikło","213142435307718","Fundacja Flaga","ulica Kochanowskiego 36 ~ 95-595 Sopot" +"Radosław Burza","6011363834691624","Fundacja Hrabia Sp. z o.o. Sp.k.","al. Targowa 08/52 ~ 21-002 Wągrowiec" +"Natan Janowiak","3593567621055321","Żuchowicz i syn s.c.","plac Ogrodowa 61/02 ~ 23-192 Malbork" +"Maksymilian Kieca","377417377811550","PPUH Bilewicz","plac Kopernika 36/61 ~ 48-407 Legionowo" +"pani Dorota Wieczerzak","6596262282704702","PPUH Plona-Lenc Sp.k.","ul. Wieniawskiego 773 ~ 45-722 Nowa Ruda" +"Dagmara Haponiuk","30572635788401","Czajor-Kozłowicz i syn s.c.","plac Czereśniowa 42/85 ~ 64-701 Ruda Śląska" +"Ksawery Michalkiewicz","2720067801981675","Gabinety Mikiciuk-Jędrzejek S.A.","pl. Porzeczkowa 656 ~ 78-965 Grudziądz" +"Dagmara Mikus","4926843824626","Sendor-Pianka s.c.","ulica Bociania 865 ~ 14-918 Pruszków" +"Lidia Czosnyka","4654299725117636938","Kuryłowicz-Brodawka Sp.k.","al. Kołłątaja 93/97 ~ 53-732 Brzeg" +"pan Bruno Startek","6011844466007999","Roch S.A.","ul. Partyzantów 721 ~ 47-570 Żory" +"Radosław Troć","676319474810","FPUH Łukasz Sp. z o.o. Sp.k.","ul. Porzeczkowa 56 ~ 28-009 Bielawa" +"Blanka Tadla","341704652423174","FPUH Cyman-Białach i syn s.c.","al. Nowa 526 ~ 21-033 Piła" +"Konrad Toma","3519664242836923","Gryga Sp. z o.o. Sp.k.","ul. Partyzantów 698 ~ 33-849 Suwałki" +"pan Mikołaj Lepak","2246616556310947","Fundacja Suszko","ulica Azaliowa 384 ~ 03-897 Bielsk Podlaski" +"Paweł Salach","180059547928299","Fundacja Małysiak-Dyja i syn s.c.","ul. Lwowska 55/66 ~ 22-570 Siemianowice Śląskie" +"pani Gaja Czuj","4389757006142895","Grupa Łabaj","plac Kraszewskiego 09 ~ 06-308 Swarzędz" +"Marianna Chorążewicz","4174174208112086622","Jarosik Sp. z o.o.","ul. Częstochowska 53/98 ~ 23-231 Luboń" +"Alex Nałęcz","4143163965298694","Szajner Sp.k.","aleja Poniatowskiego 97 ~ 12-132 Goleniów" +"pan Jacek Piegza","4474623156971045315","Stowarzyszenie Śmieszek-Kunert s.c.","pl. Kamienna 59/75 ~ 15-194 Kraśnik" +"Andrzej Wieja","2238009374691336","PPUH Pyś","ul. Boczna 79/53 ~ 69-572 Jarocin" +"Kacper Lew","2463778200660725","Gabinety Drywa Sp.j.","plac Lotnicza 167 ~ 62-855 Bartoszyce" +"pani Kornelia Smykla","6011299674289634","Grupa Makoś","pl. Jana 19/69 ~ 59-451 Włocławek" +"Monika Grądziel","4748102815949568","Drewniok Sp.j.","pl. Szpitalna 24/46 ~ 62-902 Ełk" +"Sebastian Wąsiewicz","2372377796167979","Brodawka-Kruzel i syn s.c.","al. Pogodna 26/32 ~ 98-571 Bielawa" +"Artur Sobisz","502092509400","Spółdzielnia Dziurla-Sprawka i syn s.c.","al. Konarskiego 89 ~ 70-206 Gniezno" +"Aleks Klama","378734565638473","Spółdzielnia Juśkiewicz-Kosz i syn s.c.","pl. Kościuszki 120 ~ 93-546 Świdnik" +"Jacek Lenarcik","376258200817229","FPUH Bors Sp.k.","pl. Urocza 88/84 ~ 09-291 Nowy Targ" +"Marcin Pyda","4669896962095423","Stowarzyszenie Gradek-Samoraj Sp. z o.o. Sp.k.","ul. Konwaliowa 555 ~ 07-657 Nowa Ruda" +"Dorota Matejczyk","6539652147472497","Spółdzielnia Roda","al. Zamkowa 831 ~ 57-579 Zgorzelec" +"Ewa Jeżyna","4097364985845102","Nowotnik-Welc Sp. z o.o. Sp.k.","al. Dąbrowskiej 13/41 ~ 76-645 Żagań" +"Mieszko Prokopiak","2263482666892193","Wójs Sp.j.","plac Okrzei 83/70 ~ 70-345 Szczecinek" +"Róża Dziób","4855572717299","Nieradzik-Trzcionka Sp. z o.o.","plac Nadrzeczna 934 ~ 61-453 Swarzędz" +"pan Jan Lamch","4502391994143798","Fundacja Florian","aleja Zwycięstwa 694 ~ 34-759 Łaziska Górne" +"Jan Murach","3593771038771088","Kyc Sp. z o.o. Sp.k.","pl. Sowia 465 ~ 13-673 Szczecin" +"Elżbieta Towarek","4667302067260428","FPUH Paliga","aleja Wiatraczna 54/94 ~ 67-755 Zgierz" +"pani Dorota Pasiut","378563891230360","Stowarzyszenie Starzak-Częścik S.A.","aleja Orla 72 ~ 20-575 Ząbki" +"pani Blanka Ptok","370541417282287","Fundacja Hadam i syn s.c.","pl. Maczka 59/48 ~ 24-166 Łaziska Górne" +"pan Julian Hnat","3579541640930739","Kajdan-Szmajda S.A.","plac Agrestowa 98/92 ~ 13-643 Ostrów Wielkopolski" +"pan Ignacy Znojek","6542009648451071","Gramza-Szatko Sp.k.","ul. Szmaragdowa 36/71 ~ 65-328 Sopot" +"Olaf Zamora","6011860315859596","Stowarzyszenie Styn i syn s.c.","ulica Zbożowa 01/42 ~ 02-874 Ostrowiec Świętokrzyski" +"Gustaw Kapka","180038930766375","Spółdzielnia Ostapczuk-Cieciora Sp.j.","aleja Porzeczkowa 741 ~ 48-066 Radom" +"Błażej Broszkiewicz","213127797448648","Frycz i syn s.c.","pl. Zdrojowa 89 ~ 70-635 Turek" +"Anna Maria Gendera","5298861480970198","PPUH Karpik Sp. z o.o. Sp.k.","ul. Wojska Polskiego 699 ~ 56-951 Koło" +"Natasza Litwinowicz","375165883159673","Gabinety Mikita-Podsiadła S.A.","aleja Konarskiego 796 ~ 08-952 Piaseczno" +"pan Daniel Ficner","377979875476186","FPUH Szyma Sp. z o.o.","ul. Szeroka 08 ~ 80-356 Kutno" +"Justyna Małyszka","4355469743417","Grupa Lizoń","al. Dąbrowskiego 57/35 ~ 90-380 Swarzędz" +"Iwo Mirgos","4997687699233202","Friedrich-Sieczko i syn s.c.","ulica Zdrojowa 31/55 ~ 43-995 Bochnia" +"Julian Kozdrój","30434364978861","Bela-Kanarek Sp. z o.o. Sp.k.","plac Szarych Szeregów 89/77 ~ 07-575 Lębork" +"Aleksander Miecznik","3521088600665714","Stowarzyszenie Owsiany","ulica Daszyńskiego 62 ~ 92-483 Malbork" +"Michał Balcewicz","675968012087","Saczuk-Matla Sp.j.","al. Szczęśliwa 05/00 ~ 09-246 Świecie" +"Aleksander Kościk","581893943703","Rudolf Sp. z o.o.","plac Klonowa 92/99 ~ 08-621 Lubin" +"Julian Sapała","6544987846408225","Spółdzielnia Aleksiejuk","aleja Słowackiego 49 ~ 18-405 Katowice" +"Antoni Kość","3582058987733167","Spółdzielnia Puto","ul. Władysława Łokietka 93 ~ 30-757 Gdańsk" +"Jan Majorek","3535423261750899","Stowarzyszenie Gumieniak s.c.","pl. Harcerska 46/67 ~ 11-093 Stalowa Wola" diff --git a/dzien_04/fake_data.py b/dzien_04/fake_data.py new file mode 100644 index 0000000..5c62dac --- /dev/null +++ b/dzien_04/fake_data.py @@ -0,0 +1,22 @@ +from faker import Faker +from random import randint +import csv + +fake_data = Faker("pl_PL") + +tabela = [] + +for _ in range(60): + wiersz = [] + wiersz.append(fake_data.name()) + wiersz.append(randint(10,6000)) + wiersz.append(fake_data.credit_card_number()) + wiersz.append(fake_data.company()) + wiersz.append(fake_data.address().replace('\n',' ~ ')) + tabela.append(wiersz) + +print(tabela) +with open("dane_aj.csv", "w", newline="") as plik_csv: + dane_writer = csv.writer(plik_csv, delimiter=",", \ + quotechar='"', quoting=csv.QUOTE_NONNUMERIC) + dane_writer.writerows(tabela) \ No newline at end of file diff --git a/dzien_05/przyklady/adam.jpg b/dzien_05/przyklady/adam.jpg new file mode 100644 index 0000000..002ffba Binary files /dev/null and b/dzien_05/przyklady/adam.jpg differ diff --git a/dzien_05/przyklady/boat.jpg b/dzien_05/przyklady/boat.jpg new file mode 100644 index 0000000..8a03b99 Binary files /dev/null and b/dzien_05/przyklady/boat.jpg differ diff --git a/dzien_05/przyklady/obraz.py b/dzien_05/przyklady/obraz.py new file mode 100644 index 0000000..da1ceb6 --- /dev/null +++ b/dzien_05/przyklady/obraz.py @@ -0,0 +1,94 @@ +import os + +import cv2 +import cv2 as cv +import os + +class Obraz: + def __init__(self, filename:str, mode:int = cv.IMREAD_COLOR_BGR): + self.filename = filename + self.mode = mode + self.loaded = False + self.img = None + self.img_other = None + self.transform_name = "NOTHING" + + def load_image(self): + if self.loaded: + return True + if not os.path.exists(self.filename): + return False + # raise FileNotFoundError(self.filename) + try: + self.img = cv.imread(self.filename, flags=self.mode) + self.loaded = True + except Exception as e: + print(e) + + return True + + def show_image(self, window_name:str="Window"): + if not self.loaded: + return False + window_name += f" - {self.filename}" + cv.imshow(window_name, self.img) + cv.waitKey(0) + cv.destroyAllWindows() + return None + + def show_image_other(self, window_name:str="Window after "): + if not self.loaded: + return False + if self.img_other is None: + return False + window_name += f" - {self.filename} - {self.transform_name}" + combined = cv.hconcat([self.img, self.img_other]) + cv.imshow(window_name, combined) + cv.waitKey(0) + cv.destroyAllWindows() + return None + + def transform_equalize_histogram(self): + if not self.loaded: + return False + if self.mode == cv.IMREAD_COLOR or self.mode == cv.IMREAD_COLOR_BGR: + gray_image = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) + self.img_other = cv.equalizeHist(gray_image) + self.transform_name = "Equalize Histogram" + return True + + def transform_smoothing(self, smoothing_type="GaussianBlur"): + """ + + :param smoothing_type: GaussianBlur (default) or medianBlur + :return: True or False + """ + if not self.loaded: + return False + try: + if smoothing_type == "GaussianBlur": + self.img_other = cv.GaussianBlur(self.img, (5, 5), 0) + else: + self.img_other = cv.medianBlur(self.img, 5) + self.transform_name = smoothing_type + return True + except Exception as e: + print(e) + return False + + def return_image_stream(self, type:str="other"): + """ + + :param type: other | original + :return: + """ + if not self.loaded: + return None + if type == "original": + return self.img + elif type == "other": + if self.img_other is None: + return None + return self.img_other + else: + return None diff --git a/dzien_05/przyklady/ocv_01.py b/dzien_05/przyklady/ocv_01.py new file mode 100644 index 0000000..1c6d397 --- /dev/null +++ b/dzien_05/przyklady/ocv_01.py @@ -0,0 +1,15 @@ +import os +from exif import Image + +file_name = "adam.jpg" + +if not os.path.exists(file_name): + print(f"Brak pliku: {file_name}") + # kod błedu na podstawie https://questdb.com/docs/troubleshooting/os-error-codes/ + exit(5) + +with open(file_name, 'rb') as image_file: + image = Image(image_file) + +print(image.list_all()) + diff --git a/dzien_05/przyklady/ocv_02.py b/dzien_05/przyklady/ocv_02.py new file mode 100644 index 0000000..6a0e4c1 --- /dev/null +++ b/dzien_05/przyklady/ocv_02.py @@ -0,0 +1,28 @@ +import os +import cv2 +from exif import Image + +file_name = "adam.jpg" + +if not os.path.exists(file_name): + print(f"Brak pliku: {file_name}") + # kod błedu na podstawie https://questdb.com/docs/troubleshooting/os-error-codes/ + exit(5) + +with open(file_name, 'rb') as image_file: + image = Image(image_file) + +print(image.list_all()) + +# czytamy plik +flags = cv2.IMREAD_COLOR +img = cv2.imread(file_name, flags) +print(f"Rozmiary obrazka to: {img.shape=}") +rozmiary_exif = f""" +Wymiary to {image.x_resolution} x {image.y_resolution} +Unit {image.resolution_unit=} +""" +print(rozmiary_exif) +cv2.imshow("nazwa okienka", img) +cv2.waitKey(0) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/dzien_05/przyklady/pies.jpg b/dzien_05/przyklady/pies.jpg new file mode 100644 index 0000000..2a77674 Binary files /dev/null and b/dzien_05/przyklady/pies.jpg differ diff --git a/dzien_05/przyklady/requirements.txt b/dzien_05/przyklady/requirements.txt new file mode 100644 index 0000000..19188d1 --- /dev/null +++ b/dzien_05/przyklady/requirements.txt @@ -0,0 +1,3 @@ +matplotlib +opencv-python +exif \ No newline at end of file diff --git a/dzien_05/przyklady/skrypt_01.py b/dzien_05/przyklady/skrypt_01.py new file mode 100644 index 0000000..88000ff --- /dev/null +++ b/dzien_05/przyklady/skrypt_01.py @@ -0,0 +1,5 @@ +import cv2 + +print(cv2.__version__) +print(f"To jest to {cv2.__version__}") +print(f"To też {cv2.__version__=}") \ No newline at end of file diff --git a/dzien_05/przyklady/test_klasy_01.py b/dzien_05/przyklady/test_klasy_01.py new file mode 100644 index 0000000..fefcb04 --- /dev/null +++ b/dzien_05/przyklady/test_klasy_01.py @@ -0,0 +1,11 @@ +from funkcje.obraz import Obraz + +obrazek = Obraz("/home/adasiek/Documents/03_foto/00_adam_amerigo_small.png") +if obrazek.load_image(): + obrazek.show_image() + # obrazek.transform_equalize_histogram() + # obrazek.show_image_other() + obrazek.transform_smoothing() + obrazek.show_image_other() +else: + print("Some error") \ No newline at end of file diff --git a/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.md b/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.md new file mode 100644 index 0000000..31609d3 --- /dev/null +++ b/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.md @@ -0,0 +1,466 @@ +# Instrukcja Obsługi - Program Transformacji i Detekcji Obrazów + +## Spis treści +1. [Uruchomienie programu](#uruchomienie-programu) +2. [Wybór źródła obrazu](#wybór-źródła-obrazu) +3. [Menu główne](#menu-główne) +4. [Opis transformacji](#opis-transformacji) +5. [Detekcja obiektów YOLO](#detekcja-obiektów-yolo) +6. [Skróty klawiszowe](#skróty-klawiszowe) +7. [Rozwiązywanie problemów](#rozwiązywanie-problemów) + +--- + +## Uruchomienie programu + +### Krok 1: Instalacja zależności (jednorazowo) +```bash +cd C:\Praca\ProjektyPython\2025_11_elektryk\dzien_02 +pip install -r requirements.txt +``` + +### Krok 2: Uruchomienie +```bash +python test_transform.py +``` + +--- + +## Wybór źródła obrazu + +Po uruchomieniu programu zobaczysz menu wyboru źródła obrazu: + +``` +WYBÓR ŹRÓDŁA OBRAZU +============================================================ +1. Wybierz plik z dysku (okno dialogowe) +2. Podaj URL do obrazu w internecie +3. Użyj domyślnego obrazu z katalogu dzien_01 +0. Anuluj +============================================================ +``` + +### Opcja 1: Plik z dysku +- Otwiera okno dialogowe do wyboru pliku +- Obsługuje formaty: JPG, JPEG, PNG, BMP, GIF, TIFF +- Możesz wybrać dowolny obraz z komputera + +### Opcja 2: URL z internetu +- Wpisz adres URL obrazu (np. z Unsplash, Pixabay) +- Przykład: `https://picsum.photos/800/600` +- Obraz zostanie pobrany i zapisany tymczasowo + +### Opcja 3: Domyślny obraz +- Używa pierwszego obrazu z katalogu `dzien_01` +- Szybka opcja do testowania + +--- + +## Menu główne + +Po wyborze obrazu zobaczysz menu z 18 dostępnymi transformacjami: + +``` +DOSTĘPNE TRANSFORMACJE OBRAZU +============================================================ + 1. GRAY + 2. BLUR_GAUSSIAN + 3. BLUR_MEDIAN + 4. BLUR_BILATERAL + 5. CANNY + 6. EDGE_DETECTION + 7. THRESHOLD + 8. ADAPTIVE + 9. SOBEL +10. LAPLACIAN +11. CONTOURS +12. FACE_DETECTION +13. SHARPEN +14. EMBOSS +15. YOLO_DETECT +16. YOLO_DETECT_MEDIUM +17. YOLO_DETECT_LARGE +18. YOLO_SEGMENT +------------------------------------------------------------ + C. Zmień obraz (wybierz inny plik) + 0. Wyjście z programu +============================================================ +``` + +### Jak używać: +1. Wpisz numer transformacji (1-18) +2. Naciśnij ENTER +3. Poczekaj na przetworzenie obrazu +4. Zobaczysz okno z porównaniem: **Oryginalny obraz | Przetworzony obraz** +5. Naciśnij dowolny klawisz w oknie obrazu, aby zamknąć +6. Naciśnij ENTER w konsoli, aby wrócić do menu +7. Wybierz kolejną transformację lub '0' aby zakończyć + +--- + +## Opis transformacji + +### 1. GRAY - Skala szarości +**Co robi:** Konwertuje kolorowy obraz do skali szarości (czarno-biały). + +**Zastosowanie:** +- Uproszczenie obrazu +- Przygotowanie do dalszego przetwarzania +- Redukcja ilości danych + +**Przykład użycia:** Analiza tekstur, detekcja krawędzi + +--- + +### 2. BLUR_GAUSSIAN - Rozmycie Gaussa +**Co robi:** Rozmywa obraz używając filtru Gaussa (jądro 15x15). + +**Zastosowanie:** +- Redukcja szumu +- Wygładzenie obrazu +- Usunięcie drobnych szczegółów + +**Parametry:** Rozmiar jądra 15x15 pikseli + +**Przykład użycia:** Przygotowanie obrazu przed detekcją krawędzi + +--- + +### 3. BLUR_MEDIAN - Rozmycie medianowe +**Co robi:** Rozmywa obraz używając filtru medianowego. + +**Zastosowanie:** +- Usuwanie szumu typu "sól i pieprz" +- Zachowanie krawędzi lepiej niż Gaussian +- Wygładzenie obrazu + +**Przykład użycia:** Czyszczenie zaszumionych zdjęć + +--- + +### 4. BLUR_BILATERAL - Rozmycie bilateralne +**Co robi:** Rozmywa obraz zachowując ostre krawędzie. + +**Zastosowanie:** +- Redukcja szumu z zachowaniem szczegółów +- Efekt "wygładzenia skóry" w fotografii +- Przygotowanie do segmentacji + +**Zaleta:** Nie rozmywa krawędzi obiektów + +--- + +### 5. CANNY - Detekcja krawędzi Canny +**Co robi:** Wykrywa krawędzie w obrazie metodą Canny'ego. + +**Zastosowanie:** +- Detekcja konturów obiektów +- Analiza kształtów +- Segmentacja obrazu + +**Parametry:** Progi 100 i 200 + +**Wynik:** Biały obraz z czarnymi krawędziami + +--- + +### 6. EDGE_DETECTION - Zaawansowana detekcja krawędzi +**Co robi:** Wykrywa krawędzie z wcześniejszym rozmyciem Gaussa. + +**Zastosowanie:** +- Detekcja krawędzi z redukcją szumu +- Lepsza jakość niż zwykły Canny +- Analiza struktury obrazu + +**Parametry:** Gaussian blur (5x5), Canny (50, 150) + +--- + +### 7. THRESHOLD - Progowanie binarne +**Co robi:** Konwertuje obraz do czarno-białego (0 lub 255). + +**Zastosowanie:** +- Segmentacja obiektów +- Wykrywanie tekstu +- Analiza binarna + +**Parametry:** Próg 127 + +**Wynik:** Piksele poniżej progu = czarne, powyżej = białe + +--- + +### 8. ADAPTIVE - Progowanie adaptacyjne +**Co robi:** Progowanie z lokalnie dostosowanym progiem. + +**Zastosowanie:** +- Segmentacja przy nierównym oświetleniu +- Wykrywanie tekstu w trudnych warunkach +- Lepsza jakość niż zwykłe progowanie + +**Zaleta:** Działa dobrze przy zmiennym oświetleniu + +--- + +### 9. SOBEL - Detekcja krawędzi Sobel +**Co robi:** Wykrywa krawędzie używając operatora Sobela (gradient). + +**Zastosowanie:** +- Detekcja krawędzi poziomych i pionowych +- Analiza gradientu obrazu +- Wykrywanie zmian intensywności + +**Wynik:** Obraz gradientu (jasne = silne krawędzie) + +--- + +### 10. LAPLACIAN - Detekcja krawędzi Laplacian +**Co robi:** Wykrywa krawędzie używając operatora Laplace'a. + +**Zastosowanie:** +- Detekcja krawędzi we wszystkich kierunkach +- Wykrywanie ostrości obrazu +- Analiza drugiej pochodnej + +**Wynik:** Podkreślone krawędzie + +--- + +### 11. CONTOURS - Detekcja konturów +**Co robi:** Znajduje i rysuje kontury obiektów na obrazie. + +**Zastosowanie:** +- Wykrywanie kształtów obiektów +- Liczenie obiektów +- Analiza geometrii + +**Wynik:** Zielone kontury narysowane na oryginalnym obrazie + +--- + +### 12. FACE_DETECTION - Detekcja twarzy +**Co robi:** Wykrywa twarze używając klasyfikatora Haar Cascade. + +**Zastosowanie:** +- Wykrywanie twarzy na zdjęciach +- Rozpoznawanie ludzi +- Analiza portretów + +**Wynik:** Zielone prostokąty wokół wykrytych twarzy z etykietą "Face" + +**Uwaga:** Działa najlepiej z twarzami en face (z przodu) + +--- + +### 13. SHARPEN - Wyostrzenie +**Co robi:** Wyostrza obraz podkreślając szczegóły. + +**Zastosowanie:** +- Poprawa ostrości rozmytych zdjęć +- Podkreślenie detali +- Poprawa jakości obrazu + +**Efekt:** Obraz staje się bardziej wyrazisty + +--- + +### 14. EMBOSS - Efekt wytłoczenia +**Co robi:** Tworzy efekt 3D wytłoczenia/rzeźby. + +**Zastosowanie:** +- Efekty artystyczne +- Podkreślenie struktury +- Wizualizacja głębi + +**Wynik:** Obraz wygląda jak wytłoczony w metalu + +--- + +## Detekcja obiektów YOLO + +### 15. YOLO_DETECT - Detekcja obiektów (szybka) +**Model:** YOLOv8n (nano) + +**Co robi:** Wykrywa i klasyfikuje 80 klas obiektów (ludzie, zwierzęta, pojazdy, przedmioty). + +**Zastosowanie:** +- Szybka detekcja obiektów w czasie rzeczywistym +- Analiza zawartości obrazu +- Liczenie obiektów + +**Wynik:** +- Kolorowe prostokąty wokół obiektów +- Etykiety z nazwą klasy i pewnością (np. "person: 0.95") +- Lista wykrytych obiektów w konsoli + +**Czas:** ~50-100ms + +**Wykrywane klasy:** person, car, dog, cat, bicycle, motorcycle, airplane, bus, train, truck, boat, chair, table, laptop, phone, book, bottle, cup, fork, knife, spoon, bowl, banana, apple, sandwich, orange, pizza, donut, cake i wiele innych (80 klas COCO) + +--- + +### 16. YOLO_DETECT_MEDIUM - Detekcja obiektów (średnia) +**Model:** YOLOv8s (small) + +**Co robi:** Dokładniejsza detekcja obiektów niż wersja szybka. + +**Zastosowanie:** +- Balans między szybkością a dokładnością +- Detekcja mniejszych obiektów +- Lepsza klasyfikacja + +**Czas:** ~100-200ms + +**Zaleta:** Wykrywa więcej obiektów i z większą pewnością + +--- + +### 17. YOLO_DETECT_LARGE - Detekcja obiektów (dokładna) +**Model:** YOLOv8m (medium) + +**Co robi:** Najdokładniejsza detekcja obiektów. + +**Zastosowanie:** +- Profesjonalna analiza obrazu +- Wykrywanie małych i trudnych obiektów +- Maksymalna dokładność + +**Czas:** ~200-400ms + +**Zaleta:** Najwyższa dokładność i najmniej fałszywych detekcji + +--- + +### 18. YOLO_SEGMENT - Segmentacja obiektów +**Model:** YOLOv8n-seg + +**Co robi:** Wykrywa obiekty i tworzy precyzyjne maski segmentacji. + +**Zastosowanie:** +- Precyzyjna segmentacja obiektów +- Wydzielanie tła +- Analiza kształtów + +**Wynik:** +- Kolorowe, półprzezroczyste maski na obiektach +- Kontury obiektów +- Etykiety z nazwą i pewnością + +**Czas:** ~100-200ms + +**Zaleta:** Dokładne wyznaczenie granic obiektów (nie tylko prostokąty) + +--- + +## Skróty klawiszowe + +### W konsoli: +- **0** - Wyjście z programu +- **1-18** - Wybór transformacji +- **C** - Zmiana obrazu +- **ENTER** - Potwierdzenie/powrót do menu +- **Ctrl+C** - Awaryjne przerwanie programu + +### W oknie obrazu: +- **Dowolny klawisz** - Zamknięcie okna i powrót do menu +- **ESC** - Zamknięcie okna + +--- + +## Rozwiązywanie problemów + +### Problem: "YOLO nie jest dostępne" +**Rozwiązanie:** +```bash +pip install ultralytics +``` + +### Problem: Okno obrazu nie pojawia się +**Rozwiązanie:** +1. Sprawdź czy obraz został poprawnie wczytany +2. Upewnij się, że ścieżka do obrazu jest prawidłowa +3. Spróbuj innego obrazu + +### Problem: Detekcja twarzy nie działa +**Rozwiązanie:** +- Upewnij się, że twarze są widoczne z przodu +- Użyj obrazu o dobrej jakości +- Twarze powinny być wyraźne i dobrze oświetlone + +### Problem: YOLO nie wykrywa obiektów +**Rozwiązanie:** +1. Spróbuj użyć YOLO_DETECT_LARGE (opcja 17) dla lepszej dokładności +2. Upewnij się, że obiekty należą do 80 klas COCO +3. Sprawdź jakość i rozdzielczość obrazu + +### Problem: Program działa wolno +**Rozwiązanie:** +1. Użyj YOLO_DETECT (opcja 15) zamiast LARGE +2. Zmniejsz rozmiar obrazu +3. Użyj prostszych transformacji (1-14) + +### Problem: Błąd przy pobieraniu obrazu z URL +**Rozwiązanie:** +1. Sprawdź połączenie internetowe +2. Upewnij się, że URL prowadzi bezpośrednio do pliku obrazu +3. Spróbuj innego URL + +--- + +## Przykładowe scenariusze użycia + +### Scenariusz 1: Analiza zdjęcia z wakacji +1. Wybierz opcję **1** (plik z dysku) +2. Wybierz zdjęcie z wakacji +3. Użyj **YOLO_DETECT** (opcja 15) aby zobaczyć co jest na zdjęciu +4. Użyj **FACE_DETECTION** (opcja 12) aby wykryć twarze + +### Scenariusz 2: Poprawa jakości starego zdjęcia +1. Wczytaj stare, rozmyte zdjęcie +2. Użyj **SHARPEN** (opcja 13) aby wyostrzyć +3. Porównaj z oryginałem + +### Scenariusz 3: Analiza obrazu z internetu +1. Wybierz opcję **2** (URL) +2. Wklej link do obrazu (np. z Unsplash) +3. Użyj **YOLO_SEGMENT** (opcja 18) aby zobaczyć segmentację + +### Scenariusz 4: Detekcja krawędzi +1. Wczytaj dowolny obraz +2. Użyj **CANNY** (opcja 5) dla podstawowej detekcji +3. Porównaj z **EDGE_DETECTION** (opcja 6) +4. Porównaj z **SOBEL** (opcja 9) + +--- + +## Wskazówki + +✅ **Najlepsze praktyki:** +- Używaj obrazów o dobrej jakości (min. 640x480) +- Dla detekcji YOLO używaj obrazów z wyraźnymi obiektami +- Eksperymentuj z różnymi transformacjami na tym samym obrazie +- Zapisuj ciekawe wyniki (zrzut ekranu) + +⚠️ **Uwagi:** +- Pierwsze uruchomienie YOLO pobierze modele (~6-50 MB) +- YOLO działa najlepiej na obrazach z dobrym oświetleniem +- Niektóre transformacje wymagają obrazu w skali szarości (automatyczna konwersja) + +📝 **Zalecane formaty obrazów:** +- JPG/JPEG - najczęstszy, dobra kompresja +- PNG - bez strat, przezroczystość +- BMP - bez kompresji, duże pliki + +--- + +## Kontakt i wsparcie + +W razie problemów sprawdź: +- `README_YOLO.md` - szczegółowe informacje o YOLO +- `requirements.txt` - lista wymaganych bibliotek + +--- + +**Wersja:** 1.0 +**Data:** 2025-11-04 +**Autor:** Program transformacji i detekcji obrazów diff --git a/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.pdf b/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.pdf new file mode 100644 index 0000000..ac0e863 Binary files /dev/null and b/dzien_05/przyklady/yolo_test/INSTRUKCJA_OBSLUGI.pdf differ diff --git a/dzien_05/przyklady/yolo_test/README_YOLO.md b/dzien_05/przyklady/yolo_test/README_YOLO.md new file mode 100644 index 0000000..30715a0 --- /dev/null +++ b/dzien_05/przyklady/yolo_test/README_YOLO.md @@ -0,0 +1,137 @@ +https://www.ultralytics.com/ + +# Instrukcja instalacji YOLO dla projektu transformacji obrazów + +## Wymagania + +Aby używać funkcji detekcji i segmentacji obiektów YOLO, musisz zainstalować bibliotekę `ultralytics`. + +## Instalacja + +### Krok 1: Zainstaluj bibliotekę ultralytics + +```bash +pip install ultralytics +``` + +### Krok 2: Zainstaluj dodatkowe zależności (opcjonalnie) + +Jeśli chcesz używać GPU (NVIDIA CUDA): + +```bash +pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 +``` + +Dla CPU (wystarczy podstawowa instalacja): + +```bash +pip install torch torchvision torchaudio +``` + +## Dostępne modele YOLO w programie + +### 1. YOLO_DETECT (Opcja 15) +- **Model**: YOLOv8n (nano - najszybszy) +- **Zastosowanie**: Szybka detekcja obiektów +- **Czas**: ~50-100ms na obraz +- **Dokładność**: Dobra +- **Klasy**: 80 klas obiektów (COCO dataset) + +### 2. YOLO_DETECT_MEDIUM (Opcja 16) +- **Model**: YOLOv8s (small - średni) +- **Zastosowanie**: Balans między szybkością a dokładnością +- **Czas**: ~100-200ms na obraz +- **Dokładność**: Bardzo dobra + +### 3. YOLO_DETECT_LARGE (Opcja 17) +- **Model**: YOLOv8m (medium - duży) +- **Zastosowanie**: Wysoka dokładność detekcji +- **Czas**: ~200-400ms na obraz +- **Dokładność**: Doskonała + +### 4. YOLO_SEGMENT (Opcja 18) +- **Model**: YOLOv8n-seg (segmentacja) +- **Zastosowanie**: Segmentacja obiektów (dokładne kontury) +- **Czas**: ~100-200ms na obraz +- **Wizualizacja**: Kolorowe maski na obiektach + +## Wykrywane klasy obiektów (COCO dataset) + +YOLO wykrywa 80 klas obiektów, w tym: + +**Osoby i zwierzęta:** +- person, cat, dog, horse, sheep, cow, elephant, bear, zebra, giraffe + +**Pojazdy:** +- bicycle, car, motorcycle, airplane, bus, train, truck, boat + +**Przedmioty codziennego użytku:** +- bottle, wine glass, cup, fork, knife, spoon, bowl +- chair, couch, bed, dining table, toilet +- tv, laptop, mouse, remote, keyboard, cell phone + +**Sport i rekreacja:** +- frisbee, skis, snowboard, sports ball, kite, baseball bat +- skateboard, surfboard, tennis racket + +**Jedzenie:** +- banana, apple, sandwich, orange, broccoli, carrot, hot dog, pizza, donut, cake + +I wiele innych... + +## Jak działa wizualizacja + +### Detekcja obiektów (YOLO_DETECT*) +- Prostokąty wokół wykrytych obiektów +- Różne kolory dla różnych klas +- Etykiety z nazwą klasy i pewnością detekcji (np. "person: 0.95") +- Wyświetlenie listy wykrytych obiektów w konsoli + +### Segmentacja obiektów (YOLO_SEGMENT) +- Kolorowe maski nakładane na obiekty (40% przezroczystości) +- Kontury obiektów +- Etykiety z nazwą klasy i pewnością +- Precyzyjne wyznaczenie granic obiektów + +## Pierwsze uruchomienie + +Przy pierwszym uruchomieniu każdej opcji YOLO: +1. Model zostanie automatycznie pobrany z internetu (~6-50 MB w zależności od modelu) +2. Model zostanie zapisany lokalnie w katalogu użytkownika +3. Kolejne uruchomienia będą używały zapisanego modelu (szybsze) + +## Przykład użycia + +1. Uruchom program: `python test_transform.py` +2. Wybierz źródło obrazu (plik, URL lub domyślny) +3. Wybierz opcję 15-18 (YOLO) +4. Poczekaj na przetworzenie (pierwsze uruchomienie może potrwać dłużej) +5. Zobacz wyniki w oknie porównawczym i w konsoli + +## Rozwiązywanie problemów + +### Błąd: "YOLO nie jest dostępne" +```bash +pip install ultralytics +``` + +### Błąd: "No module named 'torch'" +```bash +pip install torch torchvision +``` + +### Wolne działanie +- Użyj YOLO_DETECT (opcja 15) zamiast YOLO_DETECT_LARGE +- Zmniejsz rozmiar obrazu przed przetwarzaniem +- Rozważ użycie GPU (wymaga NVIDIA CUDA) + +### Brak wykrytych obiektów +- Upewnij się, że obraz zawiera obiekty z listy COCO +- Spróbuj użyć modelu YOLO_DETECT_LARGE (opcja 17) dla lepszej dokładności +- Sprawdź jakość i rozdzielczość obrazu + +## Więcej informacji + +- Dokumentacja Ultralytics: https://docs.ultralytics.com/ +- YOLOv8 GitHub: https://github.com/ultralytics/ultralytics +- COCO Dataset: https://cocodataset.org/ diff --git a/dzien_05/przyklady/yolo_test/README_YOLO.pdf b/dzien_05/przyklady/yolo_test/README_YOLO.pdf new file mode 100644 index 0000000..ec66377 Binary files /dev/null and b/dzien_05/przyklady/yolo_test/README_YOLO.pdf differ diff --git a/dzien_05/przyklady/yolo_test/funkcje/__init__.py b/dzien_05/przyklady/yolo_test/funkcje/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dzien_05/przyklady/yolo_test/funkcje/obraz.py b/dzien_05/przyklady/yolo_test/funkcje/obraz.py new file mode 100644 index 0000000..2c8cae7 --- /dev/null +++ b/dzien_05/przyklady/yolo_test/funkcje/obraz.py @@ -0,0 +1,470 @@ +import cv2 as cv +import numpy as np +import os +try: + from ultralytics import YOLO + YOLO_AVAILABLE = True +except ImportError: + YOLO_AVAILABLE = False + print("Uwaga: Biblioteka ultralytics (YOLO) nie jest zainstalowana.") + print("Aby używać detekcji YOLO, zainstaluj: pip install ultralytics") + +class Obraz: + def __init__(self, filename: str, mode: int = cv.IMREAD_COLOR_BGR): + self.filename = os.path.abspath(filename) + self.mode = mode + self.loaded = False + self.img = None + self.img_other = None + self.transform_name = "NOTHING" + + def load_image(self): + if self.loaded: + return True + if not os.path.exists(self.filename): + raise FileNotFoundError(f"Nie udało się wczytać pliku: {self.filename}") + try: + self.img = cv.imread(self.filename, flags=self.mode) + self.loaded = True + except Exception as e: + print(e) + + return self.img + + def show_image(self, window_name = "Window"): + if not self.loaded: + raise ValueError("Obraz nie został wczytany") + window_name += f"-{os.path.basename(self.filename)} ({self.filename})" + cv.imshow(window_name, self.img) + cv.waitKey(0) + cv.destroyAllWindows() + return None + + def show_side_by_side(self, window_name="Original vs Transformed"): + """ + Wyświetla oryginalny i przetworzony obraz obok siebie w jednym oknie. + + Args: + window_name (str): Nazwa okna + """ + if not self.loaded: + raise ValueError("Obraz nie został wczytany") + if self.img_other is None: + raise ValueError("Nie wykonano jeszcze żadnej transformacji") + + try: + # Przygotuj obrazy do wyświetlenia + if len(self.img.shape) == 2: # Jeśli obraz jest w skali szarości + img_display = cv.cvtColor(self.img, cv.COLOR_GRAY2BGR) + else: + img_display = self.img.copy() + + if len(self.img_other.shape) == 2: # Jeśli obraz przetworzony jest w skali szarości + img_other_display = cv.cvtColor(self.img_other, cv.COLOR_GRAY2BGR) + else: + img_other_display = self.img_other.copy() + + # Upewnij się, że oba obrazy mają ten sam rozmiar + if img_display.shape != img_other_display.shape: + # Jeśli rozmiary są różne, przeskaluj drugi obraz do rozmiaru pierwszego + img_other_display = cv.resize(img_other_display, (img_display.shape[1], img_display.shape[0])) + + # Dodaj etykiety + cv.putText(img_display, "Original", (10, 30), cv.FONT_HERSHEY_SIMPLEX, + 1, (0, 255, 0), 2, cv.LINE_AA) + cv.putText(img_other_display, f"{self.transform_name}", (10, 30), + cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2, cv.LINE_AA) + + # Połącz obrazy obok siebie + combined = cv.hconcat([img_display, img_other_display]) + + # Domyślne rozmiary ekranu + screen_width = 1920 + screen_height = 1080 + + # Dostosuj rozmiar obrazu do ekranu (80% rozmiaru ekranu) + max_width = int(screen_width * 0.8) + max_height = int(screen_height * 0.8) + + h, w = combined.shape[:2] + + # Oblicz skalę, jeśli obraz jest większy niż maksymalne wymiary + if w > max_width or h > max_height: + scale = min(max_width / w, max_height / h) + new_width = int(w * scale) + new_height = int(h * scale) + combined = cv.resize(combined, (new_width, new_height)) + + # Wyświetl połączony obraz + cv.namedWindow(window_name, cv.WINDOW_AUTOSIZE) + cv.imshow(window_name, combined) + + # Poczekaj chwilę, aby okno się wyrenderowało + cv.waitKey(1) + + # Poczekaj na naciśnięcie klawisza + print(f"Wyświetlono obraz. Naciśnij dowolny klawisz w oknie obrazu, aby zamknąć...") + cv.waitKey(0) + cv.destroyAllWindows() + + except Exception as e: + print(f"Błąd podczas wyświetlania obrazów: {str(e)}") + raise + + return None + + def transform(self, transform_name: str, show_side_by_side=True): + """ + Metoda transformuje obrazek na podstawie przekazanej nazwy transformacji. + + Parameters + ---------- + transform_name : str + Nazwa transformacji, która ma być zastosowana do obrazka. + show_side_by_side : bool + Czy wyświetlić obrazy obok siebie po transformacji. + + Returns + ------- + numpy.ndarray + Przetworzony obraz. + + Raises + ------- + ValueError + Jeśli obrazek nie został wczytany lub transformacja nie jest obsługiwana. + """ + if not self.loaded: + raise ValueError("Obraz nie został wczytany") + + # Zresetuj poprzedni wynik transformacji + self.img_other = None + self.transform_name = transform_name + + if transform_name == "NOTHING": + self.img_other = self.img.copy() + + elif transform_name == "GRAY": + self.img_other = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) + + elif transform_name == "BLUR_GAUSSIAN": + # Rozmycie Gaussa + self.img_other = cv.GaussianBlur(self.img, (15, 15), 0) + + elif transform_name == "BLUR_MEDIAN": + # Rozmycie medianowe + self.img_other = cv.medianBlur(self.img, 5) + + elif transform_name == "BLUR_BILATERAL": + # Rozmycie bilateralne (zachowuje krawędzie) + self.img_other = cv.bilateralFilter(self.img, 9, 75, 75) + + elif transform_name == "CANNY": + # Detekcja krawędzi Canny + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) if len(self.img.shape) == 3 else self.img + self.img_other = cv.Canny(gray, 100, 200) + + elif transform_name == "THRESHOLD": + # Threshold wymaga obrazu w skali szarości + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) if len(self.img.shape) == 3 else self.img + self.img_other = cv.threshold(gray, 127, 255, cv.THRESH_BINARY)[1] + + elif transform_name == "ADAPTIVE": + # Adaptive threshold wymaga obrazu w skali szarości + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) if len(self.img.shape) == 3 else self.img + self.img_other = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 11, 2) + + elif transform_name == "SOBEL": + # Detekcja krawędzi Sobel + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) if len(self.img.shape) == 3 else self.img + sobelx = cv.Sobel(gray, cv.CV_64F, 1, 0, ksize=5) + sobely = cv.Sobel(gray, cv.CV_64F, 0, 1, ksize=5) + self.img_other = cv.magnitude(sobelx, sobely) + self.img_other = np.uint8(self.img_other) + + elif transform_name == "LAPLACIAN": + # Detekcja krawędzi Laplacian + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) if len(self.img.shape) == 3 else self.img + self.img_other = cv.Laplacian(gray, cv.CV_64F) + self.img_other = np.uint8(np.absolute(self.img_other)) + + elif transform_name == "FACE_DETECTION": + # Detekcja twarzy używając Haar Cascade + self.img_other = self.img.copy() + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) + + # Ścieżka do klasyfikatora Haar Cascade + cascade_path = cv.data.haarcascades + 'haarcascade_frontalface_default.xml' + face_cascade = cv.CascadeClassifier(cascade_path) + + # Wykryj twarze + faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30)) + + # Narysuj prostokąty wokół wykrytych twarzy + for (x, y, w, h) in faces: + cv.rectangle(self.img_other, (x, y), (x+w, y+h), (0, 255, 0), 2) + cv.putText(self.img_other, "Face", (x, y-10), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) + + elif transform_name == "EDGE_DETECTION": + # Zaawansowana detekcja krawędzi + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) + blurred = cv.GaussianBlur(gray, (5, 5), 0) + self.img_other = cv.Canny(blurred, 50, 150) + + elif transform_name == "CONTOURS": + # Detekcja konturów + self.img_other = self.img.copy() + gray = cv.cvtColor(self.img, cv.COLOR_BGR2GRAY) + blurred = cv.GaussianBlur(gray, (5, 5), 0) + edges = cv.Canny(blurred, 50, 150) + contours, _ = cv.findContours(edges, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) + cv.drawContours(self.img_other, contours, -1, (0, 255, 0), 2) + + elif transform_name == "SHARPEN": + # Wyostrzenie obrazu + kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]]) + self.img_other = cv.filter2D(self.img, -1, kernel) + + elif transform_name == "EMBOSS": + # Efekt emboss (wytłoczenie) + kernel = np.array([[-2,-1,0], [-1,1,1], [0,1,2]]) + self.img_other = cv.filter2D(self.img, -1, kernel) + + elif transform_name == "YOLO_DETECT": + # Detekcja obiektów używając YOLO + if not YOLO_AVAILABLE: + raise ValueError("YOLO nie jest dostępne. Zainstaluj: pip install ultralytics") + + self.img_other = self._yolo_detection(model_size='n') + + elif transform_name == "YOLO_DETECT_MEDIUM": + # Detekcja obiektów używając YOLO (model średni - dokładniejszy) + if not YOLO_AVAILABLE: + raise ValueError("YOLO nie jest dostępne. Zainstaluj: pip install ultralytics") + + self.img_other = self._yolo_detection(model_size='s') + + elif transform_name == "YOLO_DETECT_LARGE": + # Detekcja obiektów używając YOLO (model duży - najdokładniejszy) + if not YOLO_AVAILABLE: + raise ValueError("YOLO nie jest dostępne. Zainstaluj: pip install ultralytics") + + self.img_other = self._yolo_detection(model_size='m') + + elif transform_name == "YOLO_SEGMENT": + # Segmentacja obiektów używając YOLO + if not YOLO_AVAILABLE: + raise ValueError("YOLO nie jest dostępne. Zainstaluj: pip install ultralytics") + + self.img_other = self._yolo_segmentation() + + else: + raise ValueError(f"Brak obsługiwanej metody transformacji: {transform_name}") + + # Po wykonaniu transformacji wyświetl obrazy obok siebie, jeśli wymagane + if show_side_by_side and self.img_other is not None: + self.show_side_by_side() + + return self.img_other + + def _yolo_detection(self, model_size='n', conf_threshold=0.25): + """ + Wykonuje detekcję obiektów używając YOLO. + + Args: + model_size (str): Rozmiar modelu ('n', 's', 'm', 'l', 'x') + conf_threshold (float): Próg pewności detekcji (0.0-1.0) + + Returns: + numpy.ndarray: Obraz z naniesionymi detekcjami + """ + print(f"\nŁadowanie modelu YOLO (yolov8{model_size})...") + + # Załaduj model YOLO + model = YOLO(f'yolov8{model_size}.pt') + + print("Wykonywanie detekcji obiektów...") + + # Wykonaj detekcję + results = model(self.img, conf=conf_threshold, verbose=False) + + # Skopiuj obraz + img_result = self.img.copy() + + # Pobierz wyniki + if len(results) > 0: + result = results[0] + boxes = result.boxes + + detected_objects = [] + + # Rysuj prostokąty i etykiety dla każdego wykrytego obiektu + for box in boxes: + # Pobierz współrzędne + x1, y1, x2, y2 = map(int, box.xyxy[0]) + + # Pobierz klasę i pewność + conf = float(box.conf[0]) + cls = int(box.cls[0]) + class_name = model.names[cls] + + detected_objects.append((class_name, conf)) + + # Wybierz kolor dla prostokąta (różne kolory dla różnych klas) + color = self._get_color_for_class(cls) + + # Narysuj prostokąt + cv.rectangle(img_result, (x1, y1), (x2, y2), color, 2) + + # Przygotuj etykietę + label = f"{class_name}: {conf:.2f}" + + # Oblicz rozmiar tekstu + (text_width, text_height), baseline = cv.getTextSize( + label, cv.FONT_HERSHEY_SIMPLEX, 0.6, 2 + ) + + # Narysuj tło dla tekstu + cv.rectangle( + img_result, + (x1, y1 - text_height - baseline - 5), + (x1 + text_width, y1), + color, + -1 + ) + + # Narysuj tekst + cv.putText( + img_result, + label, + (x1, y1 - baseline - 5), + cv.FONT_HERSHEY_SIMPLEX, + 0.6, + (255, 255, 255), + 2 + ) + + # Wyświetl podsumowanie w konsoli + print(f"\n✓ Wykryto {len(detected_objects)} obiektów:") + for obj_name, obj_conf in detected_objects: + print(f" - {obj_name}: {obj_conf:.2%}") + else: + print("\n✗ Nie wykryto żadnych obiektów.") + + return img_result + + def _yolo_segmentation(self, model_size='n', conf_threshold=0.25): + """ + Wykonuje segmentację obiektów używając YOLO. + + Args: + model_size (str): Rozmiar modelu ('n', 's', 'm', 'l', 'x') + conf_threshold (float): Próg pewności detekcji (0.0-1.0) + + Returns: + numpy.ndarray: Obraz z naniesioną segmentacją + """ + print(f"\nŁadowanie modelu YOLO Segmentation (yolov8{model_size}-seg)...") + + # Załaduj model segmentacji + model = YOLO(f'yolov8{model_size}-seg.pt') + + print("Wykonywanie segmentacji obiektów...") + + # Wykonaj segmentację + results = model(self.img, conf=conf_threshold, verbose=False) + + # Skopiuj obraz + img_result = self.img.copy() + + # Pobierz wyniki + if len(results) > 0: + result = results[0] + + if result.masks is not None: + masks = result.masks.data.cpu().numpy() + boxes = result.boxes + + detected_objects = [] + + # Dla każdej maski + for i, (mask, box) in enumerate(zip(masks, boxes)): + # Pobierz klasę i pewność + conf = float(box.conf[0]) + cls = int(box.cls[0]) + class_name = model.names[cls] + + detected_objects.append((class_name, conf)) + + # Wybierz kolor dla maski + color = self._get_color_for_class(cls) + + # Przeskaluj maskę do rozmiaru obrazu + mask_resized = cv.resize(mask, (img_result.shape[1], img_result.shape[0])) + mask_bool = mask_resized > 0.5 + + # Nałóż kolorową maskę na obraz + colored_mask = np.zeros_like(img_result) + colored_mask[mask_bool] = color + + # Zmieszaj z oryginalnym obrazem (przezroczystość 40%) + img_result = cv.addWeighted(img_result, 1.0, colored_mask, 0.4, 0) + + # Narysuj kontur + contours, _ = cv.findContours( + mask_bool.astype(np.uint8), + cv.RETR_EXTERNAL, + cv.CHAIN_APPROX_SIMPLE + ) + cv.drawContours(img_result, contours, -1, color, 2) + + # Dodaj etykietę + x1, y1, x2, y2 = map(int, box.xyxy[0]) + label = f"{class_name}: {conf:.2f}" + cv.putText( + img_result, + label, + (x1, y1 - 10), + cv.FONT_HERSHEY_SIMPLEX, + 0.6, + color, + 2 + ) + + # Wyświetl podsumowanie w konsoli + print(f"\n✓ Zsegmentowano {len(detected_objects)} obiektów:") + for obj_name, obj_conf in detected_objects: + print(f" - {obj_name}: {obj_conf:.2%}") + else: + print("\n✗ Nie wykryto żadnych obiektów do segmentacji.") + else: + print("\n✗ Nie wykryto żadnych obiektów.") + + return img_result + + def _get_color_for_class(self, class_id): + """ + Generuje unikalny kolor dla danej klasy obiektów. + + Args: + class_id (int): ID klasy + + Returns: + tuple: Kolor w formacie BGR + """ + # Predefiniowane kolory dla lepszej wizualizacji + colors = [ + (255, 0, 0), # Niebieski + (0, 255, 0), # Zielony + (0, 0, 255), # Czerwony + (255, 255, 0), # Cyjan + (255, 0, 255), # Magenta + (0, 255, 255), # Żółty + (128, 0, 128), # Fioletowy + (255, 128, 0), # Pomarańczowy + (0, 128, 255), # Jasnoniebieski + (128, 255, 0), # Limonkowy + ] + + return colors[class_id % len(colors)] + diff --git a/dzien_05/przyklady/yolo_test/requirements.txt b/dzien_05/przyklady/yolo_test/requirements.txt new file mode 100644 index 0000000..1f1d039 --- /dev/null +++ b/dzien_05/przyklady/yolo_test/requirements.txt @@ -0,0 +1,5 @@ +opencv-python>=4.8.0 +numpy>=1.24.0 +ultralytics>=8.0.0 +torch>=2.0.0 +torchvision>=0.15.0 diff --git a/dzien_05/przyklady/yolo_test/test_klasy_01.py b/dzien_05/przyklady/yolo_test/test_klasy_01.py new file mode 100644 index 0000000..456921b --- /dev/null +++ b/dzien_05/przyklady/yolo_test/test_klasy_01.py @@ -0,0 +1,7 @@ +from funkcje.obraz import Obraz + +obraz = Obraz("../dzien_01/plane.jpg") +obraz.load_image() +obraz.show_image("Obraz") + + diff --git a/dzien_05/przyklady/yolo_test/test_transform.py b/dzien_05/przyklady/yolo_test/test_transform.py new file mode 100644 index 0000000..1a945e0 --- /dev/null +++ b/dzien_05/przyklady/yolo_test/test_transform.py @@ -0,0 +1,245 @@ +from funkcje.obraz import Obraz +import os +import sys +import cv2 +import numpy as np +from pathlib import Path +from tkinter import Tk, filedialog +import urllib.request +import tempfile + +def test_transform(image_path, transform_name): + """ + Testuje wybraną transformację na podanym obrazie. + + Args: + image_path (str): Ścieżka do obrazu + transform_name (str): Nazwa transformacji do przetestowania + """ + try: + # Wczytanie obrazu + img = Obraz(image_path) + img.load_image() + + print(f"\n--- Testowanie transformacji: {transform_name} ---") + + # Wykonanie transformacji + result = img.transform(transform_name, show_side_by_side=True) + + # Zamknięcie wszystkich okien przed zakończeniem + cv2.destroyAllWindows() + return True + + except Exception as e: + print(f"Błąd podczas wykonywania transformacji {transform_name}: {str(e)}") + import traceback + traceback.print_exc() + cv2.destroyAllWindows() + return False + +def select_image_from_disk(): + """Otwiera okno dialogowe do wyboru pliku obrazu z dysku.""" + print("\nOtwieranie okna dialogowego wyboru pliku...") + + # Ukryj główne okno Tkinter + root = Tk() + root.withdraw() + root.attributes('-topmost', True) + + # Otwórz dialog wyboru pliku + file_path = filedialog.askopenfilename( + title="Wybierz plik obrazu", + filetypes=[ + ("Pliki obrazów", "*.jpg *.jpeg *.png *.bmp *.gif *.tiff"), + ("JPEG", "*.jpg *.jpeg"), + ("PNG", "*.png"), + ("BMP", "*.bmp"), + ("Wszystkie pliki", "*.*") + ] + ) + + root.destroy() + + if file_path: + print(f"✓ Wybrano plik: {file_path}") + return file_path + else: + print("✗ Nie wybrano pliku.") + return None + +def download_image_from_url(url): + """Pobiera obraz z URL i zapisuje go w pliku tymczasowym.""" + try: + print(f"\nPobieranie obrazu z URL: {url}") + + # Pobierz obraz + with urllib.request.urlopen(url, timeout=10) as response: + image_data = response.read() + + # Zapisz do pliku tymczasowego + temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.jpg') + temp_file.write(image_data) + temp_file.close() + + print(f"✓ Obraz pobrany i zapisany jako: {temp_file.name}") + return temp_file.name + + except Exception as e: + print(f"✗ Błąd podczas pobierania obrazu: {str(e)}") + return None + +def select_image_source(): + """Pozwala użytkownikowi wybrać źródło obrazu.""" + print("\n" + "="*60) + print("WYBÓR ŹRÓDŁA OBRAZU") + print("="*60) + print("1. Wybierz plik z dysku (okno dialogowe)") + print("2. Podaj URL do obrazu w internecie") + print("3. Użyj domyślnego obrazu z katalogu dzien_01") + print("0. Anuluj") + print("="*60) + + while True: + choice = input("\nWybierz opcję (0-3): ").strip() + + if choice == '0': + return None + elif choice == '1': + return select_image_from_disk() + elif choice == '2': + url = input("\nPodaj URL obrazu: ").strip() + if url: + return download_image_from_url(url) + else: + print("✗ Nie podano URL.") + return None + elif choice == '3': + # Użyj domyślnego obrazu + base_dir = Path(__file__).parent.parent + images_dir = base_dir / 'dzien_01' + image_extensions = ('.jpg', '.jpeg', '.png', '.bmp') + available_images = [f for f in os.listdir(images_dir) + if f.lower().endswith(image_extensions)] + + if available_images: + default_path = str(images_dir / available_images[0]) + print(f"✓ Używam domyślnego obrazu: {default_path}") + return default_path + else: + print("✗ Nie znaleziono obrazów w katalogu dzien_01") + return None + else: + print("✗ Nieprawidłowy wybór. Wybierz 0-3.") + +def print_menu(transformations): + """Wyświetla menu z dostępnymi transformacjami.""" + print("\n" + "="*60) + print("DOSTĘPNE TRANSFORMACJE OBRAZU") + print("="*60) + for i, transform in enumerate(transformations, 1): + print(f"{i:2d}. {transform}") + print("-"*60) + print(" C. Zmień obraz (wybierz inny plik)") + print(" 0. Wyjście z programu") + print("="*60) + +def main(): + print(f"\n{'='*60}") + print(f"PROGRAM TESTOWANIA TRANSFORMACJI OBRAZÓW") + print(f"{'='*60}") + + # Wybór początkowego obrazu + image_path = select_image_source() + + if not image_path: + print("\n✗ Nie wybrano obrazu. Program zakończony.") + return + + print(f"\nObecnie używany obraz:") + print(f" Nazwa: {os.path.basename(image_path)}") + print(f" Ścieżka: {image_path}") + + # Lista dostępnych transformacji do przetestowania + transformations = [ + "GRAY", # Skala szarości + "BLUR_GAUSSIAN", # Rozmycie Gaussa + "BLUR_MEDIAN", # Rozmycie medianowe + "BLUR_BILATERAL", # Rozmycie bilateralne + "CANNY", # Detekcja krawędzi Canny + "EDGE_DETECTION", # Zaawansowana detekcja krawędzi + "THRESHOLD", # Progowanie binarne + "ADAPTIVE", # Progowanie adaptacyjne + "SOBEL", # Detekcja krawędzi Sobel + "LAPLACIAN", # Detekcja krawędzi Laplacian + "CONTOURS", # Detekcja konturów + "FACE_DETECTION", # Detekcja twarzy + "SHARPEN", # Wyostrzenie + "EMBOSS", # Efekt wytłoczenia + "YOLO_DETECT", # YOLO - Detekcja obiektów (szybki) + "YOLO_DETECT_MEDIUM", # YOLO - Detekcja obiektów (średni) + "YOLO_DETECT_LARGE", # YOLO - Detekcja obiektów (dokładny) + "YOLO_SEGMENT" # YOLO - Segmentacja obiektów + ] + + # Pętla główna programu + while True: + print_menu(transformations) + + try: + choice = input(f"\nWybierz opcję (0-{len(transformations)}, C aby zmienić obraz): ").strip().upper() + + # Sprawdź czy użytkownik chce zakończyć + if choice == '0': + print("\nZakończono program. Do widzenia!") + break + + # Sprawdź czy użytkownik chce zmienić obraz + elif choice == 'C': + new_image_path = select_image_source() + if new_image_path: + image_path = new_image_path + print(f"\n✓ Zmieniono obraz na:") + print(f" Nazwa: {os.path.basename(image_path)}") + print(f" Ścieżka: {image_path}") + else: + print("\n✗ Nie wybrano nowego obrazu. Pozostawiono poprzedni.") + input("\nNaciśnij ENTER, aby kontynuować...") + continue + + # Konwersja na liczbę + try: + choice_idx = int(choice) - 1 + except ValueError: + print("\n✗ Proszę wprowadzić poprawną liczbę lub 'C'.") + continue + + # Sprawdź poprawność wyboru + if 0 <= choice_idx < len(transformations): + transform_name = transformations[choice_idx] + print(f"\n{'='*60}") + print(f"Wybrano transformację: {transform_name}") + print(f"{'='*60}") + + # Wykonaj transformację + success = test_transform(image_path, transform_name) + + if success: + print(f"\n✓ Transformacja '{transform_name}' zakończona pomyślnie.") + else: + print(f"\n✗ Transformacja '{transform_name}' zakończona z błędem.") + + # Poczekaj na potwierdzenie przed powrotem do menu + input("\nNaciśnij ENTER, aby wrócić do menu...") + else: + print(f"\n✗ Nieprawidłowy wybór. Wybierz numer od 0 do {len(transformations)}.") + + except KeyboardInterrupt: + print("\n\nPrzerwano przez użytkownika. Do widzenia!") + break + except Exception as e: + print(f"\n✗ Wystąpił nieoczekiwany błąd: {str(e)}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + main()