diff --git a/.gitignore b/.gitignore index 963681f..a8a89eb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ venv/ .idea __pycache__/ /resources/smieci w kontenerach - \ No newline at end of file diff --git a/adamORaport.md b/adamORaport.md new file mode 100644 index 0000000..58fd0d7 --- /dev/null +++ b/adamORaport.md @@ -0,0 +1,118 @@ +# Sztuczna Inteligencja + +**Temat projektu:** Inteligenta Śmieciarka + +**Zespół:** Kacper Borkowski, Adam Borowski, Adam Osiowy + +**Podprojekt:** Adam Osiowy - *segregator śmieci* + +--- + +## Opis podprojektu: + +- w projekcie wykorzystane zostały drzewa decyzyjne jako metoda uczenia +- projekt podzielony jest na 4 pliki +- plik tworzenie_danych_AO.py jest odpowiedzialny za wydobycie z każdego zdjęcia własności i zapis ich do pliku +![4](resources/screenShots/adamo4.png) +- w pliku uczenie_adamO.py znajdują się funkcje odpowiedzialne za uczenie i testowanie modelu +![5](resources/screenShots/adamo5.png) +- plik parametry_zdjec.h5 zawiera własności wszystkich zdjęć wykorzystanych w projekcie +- plik etykiety.h5 zawiera odpowiedni typ każdego ze zdjęć (glass,paper,plastic,metal) + +--- + +## Ogólne działanie: + +- na początku zbierane są informacje o każdym zdjęciu +``` +momenty = wyznaczHuMomenty(zdj) +haralick = wyznaczHaralick(zdj) +histogram = wyznaczHistogram(zdj) +``` +- wybrane własności to: + 1. Histogram kolorów okreslający rozkład jasności pixeli w każdej komórce na zdjęciu w skali szarości + ![6](resources/screenShots/adamo6.png) + zdjęcie jest przekształcane do przestrzeni barw hsv + po czym wyliczany jest histogram podając do funkcji zdjęcie, kanały (hsv), maskę, podział zdjęcia na 512 przedziałów (8x8x8), zakres każdego kanału + 2. Momenty obrazu (Hu Moments) określające kształt obiektu na zdjęciu + ![8](resources/screenShots/adamo8.png) + są średnią ważoną intensywności pikseli obrazu. + Są liczone ze wzoru: + ![10](resources/screenShots/adamo10.png) + gdzie I(x,y) to intensywność pixela w danym punkcie + *Momenty surowe* - informują o intensywności pikseli i ich położeniu na obrazie + *Momenty centralne* - otrzymujemy po odjęciu od momentów surowych środka ciężkości danego kształtu + ![11](resources/screenShots/adamo11.png) + momenty te są niezmienne w wyliczaniu to znaczy że jeśli kształt jest ten sam to nie ważne jest jego położenie na zdjęciu + *Momenty Hu* - to zbiór 7 liczb obliczonych na podstawie momentów centralnych. + Pierwsze 6 momentów są niezmienne dla translacji, skali i rotacji. + Podczas gdy znak siódmej liczby zmienia się wraz z odbiciem kształu (względem osi). + ![12](resources/screenShots/adamo12.png) + + 3. Tekstura Haralicka określająca nasycenie ilości pixeli w skali szarości + ![7](resources/screenShots/adamo7.png) + "Haralick zasugerował zastosowanie macierzy współwystępowania poziomu szarości (GLCM). + Ta metoda opiera się na połączonych rozkładach prawdopodobieństwa par pikseli. + GLCM pokazuje, jak często każdy poziom szarości występuje w pikselach umieszczonych w ustalonym położeniu + geometrycznym względem siebie, w zależności od poziomu szarości." + ![13](resources/screenShots/adamo13.png) + +- własności sa zapisywane jako macierze, ustawiane w szereg jako wiersz i zapisywane do pliku z danymi .h5 +``` +wiersz = np.hstack([momenty, histogram, haralick]) +``` +- dane dzielone są losowo na 2 pary, jedna testowa druga treningowa +``` +(uczenieDane, testowanieDane, uczenieEtykiety, testowanieEtykiety) = +train_test_split(np.array(dane), np.array(etykiety), test_size=rozmiar_zbioru_testowego) +``` +gdzie rozmiar zbioru testowego określony wcześniej na 20% +- tworzony jest estymator +``` +rfc = RandomForestClassifier(max_depth=15, n_jobs=4, random_state=1) +``` +gdzie n_jobs to ilość wątków, random_state pilnuje aby zbiór był zawsze dzielony tak samo, +a max_depth to maksymalna głebokość każdego drzewa +estymator domyślnie korzysta ze strategii opierającej się o indeks Giniego +``` +'indeks Giniego jest to miara która określa jak często losowo wybrany element zostanie błędnie zidentyfikowany' +``` +indeks jest obliczany ze wzoru: +![9](resources/screenShots/adamo9.png) +[przykład](https://www.geeksforgeeks.org/decision-tree-introduction-example/) +- estymator rozpoczyna uczenie korzystając ze zbiorów treningowych +``` +rfc.fit(uczenieDane, uczenieEtykiety) +``` +- następnie wyliczana jest skuteczność na zbiorach testowych +``` +rfc.score(testowanieDane, testowanieEtykiety) +``` + +--- + +## Integracja z projektem zespołowym: + +- Przy starcie programu estymator rozpoczyna nauke +``` +rfc = adamO.rozpocznijUczenie() +``` +- Śmieciarka porusza się po domach zbierając z nich śmieci +- Po zebraniu wszystkich śmieci kieruje się na wysypisko +- Każde zdjęcie śmieci jest segregowane z wykorzystaniem funkcji przewidującej typ +``` +rodzaj = adamO.przewidz(smiec, rfc) +``` +![3](resources/screenShots/adamo3.png) +- Zdjęcia posegregowanych śmieci umieszczane są w odpowiednich folderach: +![1](resources/screenShots/adamo1.png) +- Na koniec wyświetlane są losowo wybrane zdjęcia śmieci z kontenerów wraz z informacją o typie ustalonym przez estymator +![2](resources/screenShots/adamo2.png) + 1. górny napis to typ zwrócony przez estymator + 2. drugi napis to wartości prawpopodobieństwa z jakim estymator ocenił typ + 3. trzeci napis to nazwa zdjęcia + +--- + +## Efekt działania programu w postaci drzewa decyzyjnego: +![10](graph.png) diff --git a/etykiety.h5 b/etykiety.h5 new file mode 100644 index 0000000..aa05199 Binary files /dev/null and b/etykiety.h5 differ diff --git a/game.py b/game.py index d4f241e..de99803 100644 --- a/game.py +++ b/game.py @@ -109,7 +109,6 @@ def game(): rodzaj = kacper.przewidz(smiec) elif osoba == 'adamB': rodzaj = adamB.predict(smiec) - # rodzaj = kacper.przewidz(smiec) else: rodzaj = adamO.przewidz(smiec, rfc) diff --git a/graph.png b/graph.png new file mode 100644 index 0000000..422517b Binary files /dev/null and b/graph.png differ diff --git a/kacperRaport.md b/kacperRaport.md new file mode 100644 index 0000000..5a085e7 --- /dev/null +++ b/kacperRaport.md @@ -0,0 +1,54 @@ +# Sztuczna Inteligencja + +**Temat projektu:** Inteligenta Śmieciarka + +**Zespół:** Kacper Borkowski, Adam Borowski, Adam Osiowy + +**Podprojekt:** Kacper Borkowski + +--- + +## 1. Model: + +![model](resources/screenShots/kacper1.png) + +- Powyższa funkcja tworzy sekwencyjny model sieci neuronowej +- Składa się on z warstw +- Warstwa Conv2D jest to warstwa splotu, stosuje ona filtr na obrazku +- Warstwa Activation jest to warstwa aktywacji wykorzystująca funkcję aktywacji, relu jest to funkcja zwracająca 0 dla x < 0 oraz x dla pozostałych argumentów; softmax to funkcja pozwalająca na poznanie rozkładu prawdopodobieństwa na kategorie +- Warstwa MaxPooling wyciąga największą wartość z wycinka obrazka, w tym przypadku z kawałka 2x2 piksele +- Warstwa Flatten spłaszcza macierz do wektorów +- Warstwa Dense to połączone ze sobą neurony +- Warstwa Dropout przepuszcza część danych, w tym przypadku 50% w celu uniknięcia przeuczenia sieci + +--- + +## 2. Uczenie modelu: + +![uczenie](resources/screenShots/kacper2.png) + +- Model uczy się na 1599 zdjęciach śmieci podzielonych na 4 kategorie +- Wszystkie zdjęcia mają rozmiar 299x299 pikseli +- Podczas uczenia zbiór dzielony jest na paczki po 16 elementów +- Zastosowana funkcja straty to categorical_crossentropy ponieważ mamy więcej niż dwie klasy śmieci + +--- + +## 2. Przewidywanie: + +![przewidywanie](resources/screenShots/kacper3.png) + +- Obrazki są zamieniane na macierze +- Prediction zawiera rozkład prawdopodobieństwa obrazka na kategorie +- Funkcja zwraca konkretny typ śmiecia w zależności od przewidzianego prawdopodobieństwa + +--- + +## 2. Integracja w projekcie: + +![integracja](resources/screenShots/kacper4.png) + +- Podczas wizyty śmieciarki w domu wykonywana jest funkcja przewidzenia kategorii na każdym ze śmieci w danym domu +- Zależnie od wyniku przewidywania śmieć jest umieszczany na odpowiedniej liście śmieci w śmieciarce +- Śmieci z wszystkich list są wyładowywane na wysypisku do kontenerów odpowiadających listom +- Zdjęcia śmieci znajdują się finalnie w posortowanych folderach \ No newline at end of file diff --git a/main.py b/main.py index 1078433..a83c86e 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,10 @@ import game import uczenie_adamO -import uczenie_adamB def main(): - game.game() + rfc = game.game() + uczenie_adamO.wyswietlZdjecia(rfc) if __name__ == '__main__': diff --git a/parametry_zdjec.h5 b/parametry_zdjec.h5 new file mode 100644 index 0000000..732a82d Binary files /dev/null and b/parametry_zdjec.h5 differ diff --git a/raport_adamB.md b/raport_adamB.md index cd5dbc5..aabcf08 100644 --- a/raport_adamB.md +++ b/raport_adamB.md @@ -99,3 +99,31 @@ def predict(img_path): - zainicjowano sieć, wczytano ścieżke, przetransformowano argument funkcji(zdjecie) do porządanego formatu - następnie przekazano tensor jako argument do instancji klasy sieci - w ostatnim kroku za pomocą funkcji `max` wyciągnięto największą wagę i na jej podstawie rozpoznano klasę + +## 4. Integracja w projekcie: + +``` +for dom in obiekty["domy"]: + if dom.x == pozX and dom.y == pozY: + while dom.smieci: + smiec = dom.smieci.pop(0) + rodzaj = "" + if osoba == 'kacper': + rodzaj = kacper.przewidz(smiec) + elif osoba == 'adamB': + rodzaj = adamB.predict(smiec) + else: + rodzaj = adamO.przewidz(smiec, rfc) + + if rodzaj == "paper": + obiekty["smieciarka"].dodajPapier(smiec) + elif rodzaj == "glass": + obiekty["smieciarka"].dodajSzklo(smiec) + elif rodzaj == "metal": + obiekty["smieciarka"].dodajMetal(smiec) + elif rodzaj == "plastic": + obiekty["smieciarka"].dodajPlastik(smiec) +``` + +- zgodnie z wybraną osobą na starcie wykonywana jest odpowiednia funkcja przewidywania na śmieciach w poszczególnych domach +- finalnie zdjęcia posortowanych śmieci znajdują się w kontenerach(folder `smieci w kontenerach`) diff --git a/requirements.txt b/requirements.txt index f443816..2ce5dd2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ pygame==1.9.6 -numpy==1.18 \ No newline at end of file +numpy==1.18 +Keras==2.3.1 +tensorflow==2.2.0 diff --git a/resources/asmieci/0M1VQgmsbWc.jpg b/resources/asmieci/0M1VQgmsbWc.jpg deleted file mode 100644 index 5a2276c..0000000 Binary files a/resources/asmieci/0M1VQgmsbWc.jpg and /dev/null differ diff --git a/resources/asmieci/google-image(0002).jpeg b/resources/asmieci/google-image(0002).jpeg deleted file mode 100644 index b72d2d9..0000000 Binary files a/resources/asmieci/google-image(0002).jpeg and /dev/null differ diff --git a/resources/asmieci/google-image(0003).jpeg b/resources/asmieci/google-image(0003).jpeg deleted file mode 100644 index 0eac3a7..0000000 Binary files a/resources/asmieci/google-image(0003).jpeg and /dev/null differ diff --git a/resources/asmieci/google-image(0021).jpeg b/resources/asmieci/google-image(0021).jpeg deleted file mode 100644 index d26e612..0000000 Binary files a/resources/asmieci/google-image(0021).jpeg and /dev/null differ diff --git a/resources/screenShots/adamo1.png b/resources/screenShots/adamo1.png new file mode 100644 index 0000000..1823e9f Binary files /dev/null and b/resources/screenShots/adamo1.png differ diff --git a/resources/screenShots/adamo10.png b/resources/screenShots/adamo10.png new file mode 100644 index 0000000..297a2a7 Binary files /dev/null and b/resources/screenShots/adamo10.png differ diff --git a/resources/screenShots/adamo11.png b/resources/screenShots/adamo11.png new file mode 100644 index 0000000..9819070 Binary files /dev/null and b/resources/screenShots/adamo11.png differ diff --git a/resources/screenShots/adamo12.png b/resources/screenShots/adamo12.png new file mode 100644 index 0000000..eb63ce9 Binary files /dev/null and b/resources/screenShots/adamo12.png differ diff --git a/resources/screenShots/adamo13.png b/resources/screenShots/adamo13.png new file mode 100644 index 0000000..2bb9ca1 Binary files /dev/null and b/resources/screenShots/adamo13.png differ diff --git a/resources/screenShots/adamo2.png b/resources/screenShots/adamo2.png new file mode 100644 index 0000000..2834623 Binary files /dev/null and b/resources/screenShots/adamo2.png differ diff --git a/resources/screenShots/adamo3.png b/resources/screenShots/adamo3.png new file mode 100644 index 0000000..563c1d0 Binary files /dev/null and b/resources/screenShots/adamo3.png differ diff --git a/resources/screenShots/adamo4.png b/resources/screenShots/adamo4.png new file mode 100644 index 0000000..4323087 Binary files /dev/null and b/resources/screenShots/adamo4.png differ diff --git a/resources/screenShots/adamo5.png b/resources/screenShots/adamo5.png new file mode 100644 index 0000000..b657194 Binary files /dev/null and b/resources/screenShots/adamo5.png differ diff --git a/resources/screenShots/adamo6.png b/resources/screenShots/adamo6.png new file mode 100644 index 0000000..d129b0d Binary files /dev/null and b/resources/screenShots/adamo6.png differ diff --git a/resources/screenShots/adamo7.png b/resources/screenShots/adamo7.png new file mode 100644 index 0000000..551fb6a Binary files /dev/null and b/resources/screenShots/adamo7.png differ diff --git a/resources/screenShots/adamo8.png b/resources/screenShots/adamo8.png new file mode 100644 index 0000000..1130842 Binary files /dev/null and b/resources/screenShots/adamo8.png differ diff --git a/resources/screenShots/adamo9.png b/resources/screenShots/adamo9.png new file mode 100644 index 0000000..7dca6c3 Binary files /dev/null and b/resources/screenShots/adamo9.png differ diff --git a/resources/smieci w kontenerach/glass/google-image(0113).jpeg b/resources/smieci w kontenerach/glass/google-image(0113).jpeg new file mode 100644 index 0000000..4e7ffc9 Binary files /dev/null and b/resources/smieci w kontenerach/glass/google-image(0113).jpeg differ diff --git a/resources/smieci/plastic/google-image(0645).jpeg b/resources/smieci/plastic/google-image(0645).jpeg new file mode 100644 index 0000000..5895def Binary files /dev/null and b/resources/smieci/plastic/google-image(0645).jpeg differ diff --git a/resources/zbior_uczacy/plastic/бутылка.jpg b/resources/zbior_uczacy/plastic/бутылка.jpg new file mode 100644 index 0000000..fe0b0d3 Binary files /dev/null and b/resources/zbior_uczacy/plastic/бутылка.jpg differ diff --git a/uczenie_adamO.py b/uczenie_adamO.py index 40f7126..b20c690 100644 --- a/uczenie_adamO.py +++ b/uczenie_adamO.py @@ -10,6 +10,9 @@ import matplotlib.pyplot as plt import mahotas import random from math import ceil +from io import StringIO +from sklearn.tree import export_graphviz +import pydotplus warnings.filterwarnings('ignore') @@ -29,7 +32,8 @@ def wyznaczHuMomenty(zdj): def wyznaczHistogram(zdj, mask=None): zdj = cv2.cvtColor(zdj, cv2.COLOR_BGR2HSV) - hist = cv2.calcHist([zdj], [0, 1, 2], mask, [8, 8, 8], [0, 256, 0, 256, 0, 256]) + hist = cv2.calcHist([zdj], [0, 1, 2], mask, [8, 8, 8], + [0, 256, 0, 256, 0, 256]) cv2.normalize(hist, hist) return hist.flatten() @@ -57,12 +61,25 @@ def rozpocznijUczenie(): h5f_etykiety.close() (uczenieDane, testowanieDane, uczenieEtykiety, testowanieEtykiety) = train_test_split(np.array(dane), - np.array(etykiety), + np.array( + etykiety), test_size=rozmiar_zbioru_testowego) rfc = RandomForestClassifier(max_depth=15, n_jobs=4, random_state=1) rfc.fit(uczenieDane, uczenieEtykiety) - print("uzyskana skutecznosc: ", rfc.score(testowanieDane, testowanieEtykiety)) + print("uzyskana skutecznosc: ", rfc.score( + testowanieDane, testowanieEtykiety)) + # tworzenie grafu + # dot_data = StringIO() + # print(rfc.estimators_) + # estimator = rfc.estimators_[5] + # export_graphviz(estimator, out_file=dot_data, + # feature_names=dane[1], + # rounded=True, proportion=False, + # precision=2, filled=True, + # special_characters=True, class_names=['glass', 'metal', 'paper', 'plastic']) + # graph = pydotplus.graph_from_dot_data(dot_data.getvalue()) + # graph.write_png('graph.png') return rfc @@ -77,7 +94,8 @@ def przewidz(zdjecie, rfc): haralick = wyznaczHaralick(zdj) histogram = wyznaczHistogram(zdj) - wiersz = np.hstack([momenty, histogram, haralick]) # ustaw poziomo, jeden za drugim + # ustaw poziomo, jeden za drugim + wiersz = np.hstack([momenty, histogram, haralick]) wiersz = wiersz.reshape(1, -1) # zmniejsz wymiar z 2 do 1 przewidywany_typ = rfc.predict(wiersz)[0] # zwraca wartosc 0,1,2,3 return klasy[przewidywany_typ] # zwraca glass,metal,paper,plastic @@ -104,7 +122,7 @@ def wyswietlZdjecia(rfc): wszystkie_pliki = sum(wszystkie_pliki, []) rozmiar = ceil(0.25 * len(wszystkie_pliki)) wybrane_zdjecia = random.sample(wszystkie_pliki, k=rozmiar) - print("ilosc wybranych zdjec: ",len(wybrane_zdjecia)) + print("ilosc wybranych zdjec: ", len(wybrane_zdjecia)) for i in wybrane_zdjecia: zdjecie = cv2.imread(path + "\\" + katalog_testujacy + "\\" + i) @@ -115,15 +133,19 @@ def wyswietlZdjecia(rfc): haralick = wyznaczHaralick(zdjecie) histogram = wyznaczHistogram(zdjecie) - wiersz = np.hstack([momenty, histogram, haralick]) # ustaw poziomo, jeden za drugim + # ustaw poziomo, jeden za drugim + wiersz = np.hstack([momenty, histogram, haralick]) wiersz = wiersz.reshape(1, -1) # zmniejsz wymiar z 2 do 1 przewidywany = rfc.predict(wiersz)[0] prawdopodobienstwo = rfc.predict_proba(wiersz) - cv2.putText(zdjecie, klasy[przewidywany], (3, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), thickness=3) - cv2.putText(zdjecie, str(prawdopodobienstwo), (3, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), thickness=1) - cv2.putText(zdjecie, i, (3, 460), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), thickness=2) + cv2.putText(zdjecie, klasy[przewidywany], (3, 30), + cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), thickness=3) + cv2.putText(zdjecie, str(prawdopodobienstwo), (3, 60), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), thickness=1) + cv2.putText(zdjecie, i, (3, 460), cv2.FONT_HERSHEY_SIMPLEX, + 1, (255, 0, 0), thickness=2) plt.imshow(cv2.cvtColor(zdjecie, cv2.COLOR_BGR2RGB)) plt.show()