final
1
.gitignore
vendored
@ -4,4 +4,3 @@ venv/
|
||||
.idea
|
||||
__pycache__/
|
||||
/resources/smieci w kontenerach
|
||||
|
118
adamORaport.md
Normal file
@ -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)
|
BIN
etykiety.h5
Normal file
1
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)
|
||||
|
||||
|
54
kacperRaport.md
Normal file
@ -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
|
4
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__':
|
||||
|
BIN
parametry_zdjec.h5
Normal file
@ -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`)
|
||||
|
@ -1,2 +1,4 @@
|
||||
pygame==1.9.6
|
||||
numpy==1.18
|
||||
Keras==2.3.1
|
||||
tensorflow==2.2.0
|
||||
|
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 8.5 KiB |
BIN
resources/screenShots/adamo1.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
resources/screenShots/adamo10.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/screenShots/adamo11.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
resources/screenShots/adamo12.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
resources/screenShots/adamo13.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
resources/screenShots/adamo2.png
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
resources/screenShots/adamo3.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
resources/screenShots/adamo4.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
resources/screenShots/adamo5.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
resources/screenShots/adamo6.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
resources/screenShots/adamo7.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
resources/screenShots/adamo8.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/screenShots/adamo9.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
resources/smieci w kontenerach/glass/google-image(0113).jpeg
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
resources/smieci/plastic/google-image(0645).jpeg
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
resources/zbior_uczacy/plastic/бутылка.jpg
Normal file
After Width: | Height: | Size: 90 KiB |
@ -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()
|
||||
|