diff --git a/Marcin.md b/Marcin.md new file mode 100644 index 0000000..d52546b --- /dev/null +++ b/Marcin.md @@ -0,0 +1,93 @@ +# Podprojekt - sieć neuronowa" +**Twórca: Marcin Kwapisz** + +**Klawisz F7 uruchamia program** + +Program otrzymuje zdjęcie aktualnego pola i za +pomocą sieci neuronowej określa jakie to jest pole +i wybiera tryb w jakim ma pracować traktor + +Sieć neuronowa została nauczona przy użyciu modułu darknet. Sieć została użyta po +20000 iteracjach treningowych + +**Main** +``` + def main(self): + self.pole = self.ui.field_images[self.field.get_value(self.traktor.get_poz())] + self.img = pygame.surfarray.array3d(self.pole) + self.img = self.img.transpose([1,0,2]) + self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2BGR) + self.reco = self.mode(self.recognition(self.img)) + if self.reco == 10: + print("Nic nie trzeba robić") + else: + self.traktor.set_mode(self.reco) +``` +Wywołuje wszystkie pozostałe funkcje programu + +**Get_output_layers** +``` + def get_output_layers(self,net): + layer_names = net.getLayerNames() + output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()] + return output_layers +``` +Zwraca nazwy kolejnych warstw, warstwa wyjściowa nie jest połączona z żadną następną warstwą + +**Recognition** +``` + def recognition(self,photo): + image = photo + + Width = image.shape[1] + Height = image.shape[0] + scale = 0.00392 + + with open("si.names", 'r') as f: + classes = [line.strip() for line in f.readlines()] + + COLORS = np.random.uniform(0, 255, size=(len(classes), 3)) + + net = cv2.dnn.readNet("si_20000.weights", "si.cfg") + + blob = cv2.dnn.blobFromImage(image, scale, (416, 416), (0, 0, 0), True, crop=False) + + net.setInput(blob) + + outs = net.forward(self.get_output_layers(net)) + + class_ids = [] + confidences = [] + boxes = [] + conf_threshold = 0.5 + nms_threshold = 0.4 + + for out in outs: + for detection in out: + scores = detection[5:] + class_id = np.argmax(scores) + confidence = scores[class_id] + if confidence > 0.5: + class_ids.append(class_id) + return class_ids[0] +``` +Odpowiada za odebranie zdjęcia od funkcji głównej i +używa sieci neuronowej do rozpoznania zdjęcia + +**Mode** +``` + def mode(self,mode): + self.mode_value = mode + if self.mode_value in [0, 1, 2, 3]: + return 0 + elif self.mode_value in [1, 3, 5, 7]: + return 1 + elif self.mode_value in [0, 1, 4, 5]: + return 2 + elif self.mode_value in [8]: + return 3 + elif self.mode_value in [6]: + return 10 +``` +Na podstawie klasy otrzymanej przez funkcję **recognition** wybiera tryb +w jakim ma pracować traktor \ No newline at end of file diff --git a/Marcin.py b/Marcin.py index db3fb80..eac09c7 100644 --- a/Marcin.py +++ b/Marcin.py @@ -9,6 +9,7 @@ class main(): self.field = field self.ui = ui self.path = path + self.mode_value = 0 def get_output_layers(self,net): layer_names = net.getLayerNames() @@ -27,7 +28,7 @@ class main(): COLORS = np.random.uniform(0, 255, size=(len(classes), 3)) - net = cv2.dnn.readNet("si_final.weights", "si.cfg") + net = cv2.dnn.readNet("si_20000.weights", "si.cfg") blob = cv2.dnn.blobFromImage(image, scale, (416, 416), (0, 0, 0), True, crop=False) @@ -48,16 +49,18 @@ class main(): confidence = scores[class_id] if confidence > 0.5: class_ids.append(class_id) - print(class_id) - print(scores) - return class_id + return class_ids[0] def main(self): self.pole = self.ui.field_images[self.field.get_value(self.traktor.get_poz())] self.img = pygame.surfarray.array3d(self.pole) self.img = self.img.transpose([1,0,2]) self.img = cv2.cvtColor(self.img, cv2.COLOR_RGB2BGR) - self.traktor.set_mode(self.mode(self.recognition(self.img))) + self.reco = self.mode(self.recognition(self.img)) + if self.reco == 10: + print("Nic nie trzeba robić") + else: + self.traktor.set_mode(self.reco) def mode(self,mode): self.mode_value = mode @@ -69,3 +72,5 @@ class main(): return 2 elif self.mode_value in [8]: return 3 + elif self.mode_value in [6]: + return 10 diff --git a/decisiontree.md b/decisiontree.md index 1835440..8a86b3a 100644 --- a/decisiontree.md +++ b/decisiontree.md @@ -2,10 +2,125 @@ **Członkowie zespołu:** Marcin Kwapisz, Kamila Matysiak, Piotr Rychlicki, Justyna Zarzycka -**Temat podprojektu:** Wybór trybu pracy traktora za pomocą drzewa decyzyjnego - **Autor podprojektu:** Kamila Matysiak ### Drzewo Decyzyjne +Projekt wykorzystuje drzewo decyzyjne do wybrania czynności dla każdego pola, a następnie wysłania traktora do pól zgodnych z obecnie wybranym trybem. + +Projekt używa metody CART (Classification and Regression Tree). Tworzy on drzewo binarne, w którym rozpatruje wszystkie możliwe podziały zbioru wartości cech na dwa rozłączne i uzupełniające się podzbiory dla cech dyskretnych. + +Uruchamia się go za pomocą klawisza **F6**. + +#### Zbiór uczący: + +Zbiorem uczącym jest zestaw danych informujących drzewo jak postępować z polem o danych parametrach. +Kolejne cyfry odpowiadają za: nawodnienie pola, obecność chwastów, czy pole jest puste, czy jest do zbioru. + +``` +training_data = [[0, 0, 1, 0, "Zasadzic"], + [0, 1, 1, 0, "Odchwascic"], + [0, 0, 0, 0, "Podlac"], + [0, 1, 0, 0, "Odchwascic"], + [1, 0, 1, 0, "Zasadzic"], + [1, 1, 1, 0, "Odchwascic"], + [1, 0, 0, 0, "Czekac"], + [1, 1, 0, 0, "Odchwascic"], + [0, 0, 0, 1, "Zebrac"]] + self.tree = build_tree(training_data) + print_tree(self.tree) +``` + +#### Algotytm tworzenia drzewa: + +Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie zapytania dzieli nam dane na spełnione i niespełnione wiersze: + +``` +# podział danych na spełnione i niespełnione wiersze +def partition(rows, question): + true_rows, false_rows = [], [] + for row in rows: + if question.match(row): + true_rows.append(row) + else: + false_rows.append(row) + return true_rows, false_rows +``` + +Następnie wyokrzystujemy **Index Gini**, który mierzy jak często losowo wybrany element będzie źle zindentyfikowany. Gdy jest równy 0, oznacza to, że element zostanie właściwie oznaczony. + + + +``` +# funkcja implementująca indeks gini +def gini(rows): + counts = class_counts(rows) + impurity = 1 + for lbl in counts: + prob_of_lbl = counts[lbl] / float(len(rows)) + impurity -= prob_of_lbl ** 2 + return impurity + +def info_gain(left, right, current_uncertainty): + p = float(len(left)) / (len(left) + len(right)) + return current_uncertainty - p * gini(left) - (1 - p) * gini(right) + +``` + +Następnie na podstawie uzykanych informacji, znajdujemy najlepsze miejsce na podział danych: + +``` +# znalezienie najlepszego "miejsca" na podział danych +def find_best_split(rows): + best_gain = 0 + best_question = None + current_uncertainty = gini(rows) + n_features = len(rows[0]) - 1 + for col in range(n_features): + values = set([row[col] for row in rows]) + for val in values: + question = Question(col, val) + true_rows, false_rows = partition(rows, question) + if len(true_rows) == 0 or len(false_rows) == 0: + continue + gain = info_gain(true_rows, false_rows, current_uncertainty) + if gain >= best_gain: + best_gain, best_question = gain, question + return best_gain, best_question +``` + +Po stworzeniu klas definiujących liść i węzęł deycyzyjny przechodzimy do właściwej funkcji **build_tree*: +``` +# funkcja budująca drzewo +def build_tree(rows): + gain, question = find_best_split(rows) # znalezienie najlepszego podziału + if gain == 0: + return Leaf(rows) + true_rows, false_rows = partition(rows, question) # podział danych + + true_branch = build_tree(true_rows) + false_branch = build_tree(false_rows) #stworzenie gałęzi prawdy i fałszu + + return DecisionNode(question, true_branch, false_branch) +``` + +#### Integracja: + +Program sczytuje dane z głównego projektu, następnie interpretuje je za pomocą prostej funkcji **translate**, która zwraca informacje o stanie pola. Następnie za pomocą drzewa określamy czynność, jaka powinna zostać wykonana na tym polu. Wykonanie pracy zlecamy klasie **pathfinding**, która za pomocą algorytmu A* wysyła traktor na pola odpowiadające wybranemu trybowi. + +``` + def search_field(self): + matrix = self.field.get_matrix() + for i in range(len(matrix)): + for j in range(len(matrix[i])): + print("Pole (%d,%d) Przewidziania czynnosc: %s" + % (i, j, print_leaf(classify(translate(matrix[i][j]), self.tree)))) + if work[self.traktor.get_mode()] in self.work_field(classify(translate(matrix[i][j]), self.tree)): + print("Zgodna z aktualnym trybem, czynnosc wykonywana") + self.path.find_path(self.traktor, self.field, self.ui, [j, i]) + self.ui.update() + time.sleep(0.5) +``` + + diff --git a/ui.py b/ui.py index 6fa34e9..29daa46 100644 --- a/ui.py +++ b/ui.py @@ -1,5 +1,5 @@ import pygame - +import random class game_ui(): def __init__(self,traktor,field): @@ -34,8 +34,11 @@ class game_ui(): self.pole1_surf_rect.y = self.POLE_POZ[1] - 75 self.traktor_img = ["traktor_d.png", "traktor_l.png", "traktor_u.png", "traktor_r.png"] self.field_images = [] - for i in ['gleba_pix.png','gleba_chwasty_pix.png','sadzonka_suchi_pix.png','sadzonka_chwasty_pix.png','gleba_mokra_pix.png','gleba_mokra_chwasty.png','sadzonka_mokra_pix.png','sadzonka_mokra_chwasty_pix.png','gotowy_burak_pix.png']: - self.field_images.append(pygame.image.load('images/'+i)) + # self.field_images_path = [] + # self.random = random.randint(0,99) + for i in ['gleba_pix','gleba_chwasty_pix','sadzonka_suchi_pix','sadzonka_chwasty_pix','gleba_mokra_pix','gleba_mokra_chwasty','sadzonka_mokra_pix','sadzonka_mokra_chwasty_pix','gotowy_burak_pix']: + # self.field_images_path.append("images/"+i+"/"+i+str(self.random)+".png") + self.field_images.append(pygame.image.load("images/"+i+".png")) # Zezwalamy na przechwytywanie klawiszy pygame.event.pump()