Compare commits

..

3 Commits

Author SHA1 Message Date
Mariia Kuzmenko
a1c9425a65 Merge remote-tracking branch 'origin/master' 2020-06-11 00:03:41 +03:00
Mariia Kuzmenko
a4cf816bf2 Food clasification network 2020-06-11 00:03:16 +03:00
Mariia Kuzmenko
a6d3bd8640 Food clasification network 2020-06-10 17:14:40 +03:00
27 changed files with 162 additions and 840 deletions

View File

@ -4,4 +4,7 @@
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (ProjektAI)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>
</project>

View File

@ -1,26 +0,0 @@
## Table of contents
* [General info](#general-info)
* [Technologies](#technologies)
* [Setup](#setup)
## General info
This is AI project of autonomic waiter that recognizes images of placed ordes with CNN algorithm. Orders are generated using the decision tree algoritm while tables by generic algorithm.
Table of contents
* [General info](#general-info)
* [Technologies](#technologies)
* [Setup](#setup)
## Technologies
Project is created with:
* Python 64-bit: 3.6
* Tensorflow: 2.0.0
## Setup
The `requirements.txt` file should list all Python libraries that your notebooks
depend on, and they will be installed using:
```
pip install -r requirements.txt
```

View File

@ -1,104 +0,0 @@
class CrossingOverMethod:
FixedQuadrant = 0
SingleHorizontalDiv = 1
SingleVerticalDiv = 2
DoubleHorizontalDiv = 3
DoubleVerticalDiv = 4
RandomChoice = 5
class SelectionMethod:
Roulette = 0
Tournament = 1
class MutationMethod:
Flip = 0
Swap = 1
class GADefaults:
def __init__(self):
self.defSelectionMethods = [("ruletka", SelectionMethod.Roulette),
("turniej", SelectionMethod.Tournament)]
self.defCrossingOverMethods = [("pojedynczy poziomy", CrossingOverMethod.SingleHorizontalDiv),
("pojedynczy pionowy", CrossingOverMethod.SingleVerticalDiv),
("podwójny poziomy", CrossingOverMethod.DoubleHorizontalDiv),
("podwójny pionowy", CrossingOverMethod.DoubleVerticalDiv),
("ćwiartki", CrossingOverMethod.FixedQuadrant),
("losowe", CrossingOverMethod.RandomChoice)]
self.defMutationMethods = [("inwersja", MutationMethod.Flip),
("wymiana", MutationMethod.Swap)]
self.windowName = "Algorytm genetyczny - parametry"
self.windowGeometry = "400x400"
self.minTablesCount = 1
self.maxTablesCount = 100
self.defTablesCount = 20
self.runTablesCount = self.defTablesCount
self.sliderNameTablesCount = "stoliki"
self.minPopulationSize = 4
self.maxPopulationSize = 30
self.defPopulationSize = 5
self.runPopulationSize = self.defPopulationSize
self.sliderNamePopulationSize = "populacja"
self.minMutation = 0
self.maxMutation = 10
self.defMutation = 1
self.runMutation = self.defMutation
self.sliderNameMutation = "mutacje"
self.minGenerationsNumber = 1
self.maxGenerationsNumber = 1000
self.defGenerationsNumber = 20
self.runGenerationsNumber = self.defGenerationsNumber
self.sliderNameGenerationsNumber = "pokolenia"
self.defInfoFold = 5
self.runInfoFold = self.defInfoFold
self.sliderInfoFold = "co ile"
self.defSelectionMethod = SelectionMethod.Tournament
self.runSelectionMethod = self.defSelectionMethod
self.radioSelectionMethodName = "metoda selekcji"
self.defCrossingOverMethod = CrossingOverMethod.SingleHorizontalDiv
self.runCrossingOverMethod = self.defCrossingOverMethod
self.radioCrossingOverMethodName = "metoda krzyżowania"
self.defMutationMethod = MutationMethod.Swap
self.runMutationMethod = self.defMutationMethod
self.radioMutationMethodName = "metoda mutacji"
self.minElitism = 0
self.maxElitism = 50
self.defElitism = 0
self.runElitism = self.defElitism
self.sliderElitismName = "elitarność [%]"
self.buttonStartName = "generuj"
self.buttonDefaultsName = "przywróć"
self.__forbiddenPlaces = None
self.waiterPosition = None
self.kitchenPosition = None
def getForbiddenPlaces(self):
if self.__forbiddenPlaces is None:
self.__forbiddenPlaces = [self.waiterPosition, self.kitchenPosition]
return self.__forbiddenPlaces
def getInfo(self):
return "populacja: " + str(self.runPopulationSize) \
+ ", pokolenia: " + str(self.runGenerationsNumber) \
+ ", stoliki: " + str(self.runTablesCount) \
+ ", mutacje: " + str(self.runMutation)

View File

@ -1,82 +0,0 @@
import tkinter
from tkinter import *
from kelner.gui.GAdialog.GADefaults import CrossingOverMethod
class GADialog:
def __init__(self, defaults):
self.__defaults = defaults
self.window = tkinter.Tk()
self.window.attributes('-topmost', 'true')
self.window.title(defaults.windowName)
self.__sliderTablesCount = self.__getSlider(0, defaults.minTablesCount, defaults.maxTablesCount, defaults.runTablesCount, defaults.sliderNameTablesCount)
self.__sliderPopulationSize = self.__getSlider(1, defaults.minPopulationSize, defaults.maxPopulationSize, defaults.runPopulationSize, defaults.sliderNamePopulationSize)
self.__sliderMutation = self.__getSlider(2, defaults.minMutation, defaults.maxMutation, defaults.runMutation, defaults.sliderNameMutation)
self.__sliderGenerationsNumber = self.__getSlider(3, defaults.minGenerationsNumber, defaults.maxGenerationsNumber, defaults.runGenerationsNumber, defaults.sliderNameGenerationsNumber)
self.__sliderInfoFold = self.__getSlider(4, defaults.minGenerationsNumber, defaults.maxGenerationsNumber, defaults.runInfoFold, defaults.sliderInfoFold)
self.__sliderElitism = self.__getSlider(5, defaults.minElitism, defaults.maxElitism, defaults.runElitism, defaults.sliderElitismName)
self.__radioSelectionMethodValue = IntVar()
self.__radioSelectionMethodValue.set(self.__defaults.runSelectionMethod)
self.__getRadioButton(6, defaults.defSelectionMethods, self.__radioSelectionMethodValue, defaults.radioSelectionMethodName)
self.__radioCrossingOverMethodValue = IntVar()
self.__radioCrossingOverMethodValue.set(self.__defaults.runCrossingOverMethod)
self.__getRadioButton(8, defaults.defCrossingOverMethods, self.__radioCrossingOverMethodValue, defaults.radioCrossingOverMethodName)
self.__radioMutationMethodValue = IntVar()
self.__radioMutationMethodValue.set(self.__defaults.runMutationMethod)
self.__getRadioButton(12, defaults.defMutationMethods, self.__radioMutationMethodValue, defaults.radioMutationMethodName)
self.__buttonDefaults = self.__getButton(15, 0, W, defaults.buttonDefaultsName, self.__setDefaults)
self.__buttonStart = self.__getButton(15, 1, E, defaults.buttonStartName, self.__getAllValues)
self.window.mainloop()
def __getSlider(self, rowNum, minVal, maxVal, runVal, labText):
label = Label(self.window, text = labText)
label.grid(row = rowNum, column = 0, sticky = S + W, padx = 5, pady = 5)
slider = Scale(self.window, variable = IntVar(), from_ = minVal, to = maxVal, orient=HORIZONTAL, length = 200)
slider.grid(row = rowNum, column = 1, sticky = E, padx = 5, pady = 3)
slider.set(runVal)
return slider
def __getButton(self, rowNum, colNum, stickPos, btnText, action):
button = Button(self.window, text = btnText, command = action)
button.grid(row = rowNum, column = colNum, stick = stickPos, columnspan = 2, padx=60, pady=5)
return button
def __getRadioButton(self, rowNum, methods, variable, labText):
label = LabelFrame(self.window, text = labText)
label.grid(row=rowNum, column=0, columnspan=2, padx=5, pady=5, sticky=W)
rowNum += 1
iteration = 0
for text, mode in methods:
radio = Radiobutton(label, text = text, variable = variable, value = mode)
radio.grid(row = rowNum, column = iteration % 2, sticky = W, padx = 5, pady = 3)
rowNum += iteration % 2
iteration += 1
def __setDefaults(self):
self.__sliderTablesCount.set(self.__defaults.defTablesCount)
self.__sliderPopulationSize.set(self.__defaults.defPopulationSize)
self.__sliderMutation.set(self.__defaults.defMutation)
self.__sliderGenerationsNumber.set(self.__defaults.defGenerationsNumber)
self.__sliderInfoFold.set(self.__defaults.defInfoFold)
self.__sliderElitism.set(self.__defaults.defElitism)
self.__radioSelectionMethodValue.set(self.__defaults.defSelectionMethod)
self.__radioCrossingOverMethodValue.set(self.__defaults.defCrossingOverMethod)
self.__radioMutationMethodValue.set(self.__defaults.defMutationMethod)
def __getAllValues(self):
self.__defaults.runTablesCount = self.__sliderTablesCount.get()
self.__defaults.runPopulationSize = self.__sliderPopulationSize.get()
self.__defaults.runMutation = self.__sliderMutation.get()
self.__defaults.runGenerationsNumber = self.__sliderGenerationsNumber.get()
self.__defaults.runInfoFold = self.__sliderInfoFold.get()
self.__defaults.runElitism = self.__sliderElitism.get()
self.__defaults.runSelectionMethod = self.__radioSelectionMethodValue.get()
self.__defaults.runCrossingOverMethod = self.__radioCrossingOverMethodValue.get()
self.__defaults.runMutationMethod = self.__radioMutationMethodValue.get()
self.window.destroy()

View File

@ -1,22 +0,0 @@
import matplotlib.pyplot as plt
class Plots:
def __init__(self, generationNumber, bestFitnesses, bestTabless, worstFitnesses, worstTables, title):
self.__generationsNumber = generationNumber
self.__bestFitnesses = bestFitnesses
self.__bestTables = bestTabless
self.__worstTables = worstTables
self.__worstFitnesses = worstFitnesses
self.__title = title
def draw(self):
generations = [i for i in range(self.__generationsNumber + 1)]
plt.figure(num = self.__title)
plt.plot(generations, self.__bestTables, label = "stoliki najlepszego")
plt.plot(generations, self.__bestFitnesses, label="fitness najlepszego")
plt.plot(generations, self.__worstTables, label = "stoliki najgorszego")
plt.plot(generations, self.__worstFitnesses, label = "fitness najgorszego")
plt.legend()
plt.show()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 B

After

Width:  |  Height:  |  Size: 850 B

View File

@ -1,32 +1,36 @@
import pygame
from kelner.src.components.GridBoard import GridBoard
from kelner.src.components.Waiter import Waiter
from kelner.src.components.Table import Table
from kelner.src.components.Kitchen import Kitchen
from kelner.src.managers.DrawableCollection import DrawableCollection
# create screen consts
from kelner.src.managers.MenuManager import MenuManager
from kelner.src.managers.TableGenerator import TableGenerator
from kelner.src.managers.TableManager import TableManager
from kelner.src.managers.WaiterManager import WaiterManager
from kelner.src.algorithms.DecisionTree import Tree_Builder
from kelner.src.managers.KitchenManager import KitchenManager
from kelner.src.algorithms.CNN.PrepareData import LoadModelThread
from kelner.src.algorithms.FoodNet import classify
import kelner.src.settings as settings
# import time
Scale = 1.5 # scale for all images used within project
CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid
PaintOffset = CellSize # pixel size of paint offset for all drawables
GridCountX = 15 # number of columns in grid
GridCountY = 9 # number of rows in grid
ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
# create screen consts
Scale = 1 # scale for all images used within project
CellSize = round(50 * Scale) # pixel size of 1 square cell in the grid
PaintOffset = CellSize # pixel size of paint offset for all drawables
GridCountX = 15 # number of columns in grid
GridCountY = 9 # number of rows in grid
ScreenWidth = CellSize * GridCountX + 2 * PaintOffset # screen width in pixels
ScreenHeight = CellSize * GridCountY + 2 * PaintOffset # screen height in pixels
running_tasks = {'table': [], 'waiter': []}
# initialize background
gridBoard = GridBoard(ScreenWidth, ScreenHeight)
classify.join('/src/algorithms/FoodNet/classify.py')
classify.join('C:/Users/Maria/Desktop/ProjektAI/kelner/src/algorithms/FoodNet/classify.py')
# start loading prediction model
settings.init()
@ -36,15 +40,13 @@ load_model_thread.start()
# joining this thread to main thread. Man thread will be started after this finish
load_model_thread.join()
kitchenManager = KitchenManager(gridBoard)
# initialize drawable objects manager
drawableManager = DrawableCollection(kitchenManager)
drawableManager = DrawableCollection()
# initialize menu manager
menuManager = MenuManager()
##TESTING THE DECISION TREE
# TESTING THE DECISION TREE
# Testing Data
testing_db = [
[1, 0, 0, 0, "Kurczak"],
@ -79,16 +81,48 @@ else:
print("test4: fail")
# initialize waiter component
waiter1 = Waiter(7, 4, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
waiter1 = Waiter(0, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter2 = Waiter(0, GridCountY - 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter3 = Waiter(GridCountX - 1, 0, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# waiter4 = Waiter(GridCountX - 1, GridCountY - 1, 0, GridCountX - 1, 0, GridCountY - 1, CellSize, PaintOffset)
# adds waiter to drawable collection
drawableManager.add(waiter1)
# drawableManager.add(waiter2)
# drawableManager.add(waiter3)
# drawableManager.add(waiter4)
kitchen = Kitchen(14, 0, 5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
kitchen = Kitchen(5, GridCountX - 5, 5, GridCountY - 5, CellSize, PaintOffset)
drawableManager.add(kitchen)
kitchenManager = KitchenManager(drawableManager, gridBoard)
tableGenerator = TableGenerator(GridCountX, GridCountY, 1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset, drawableManager)
tableGenerator.start()
# My comment
# initialize a number of tables given in range
for i in range(0, 40):
table = Table(1, GridCountX - 2, 1, GridCountY - 2, CellSize, PaintOffset)
if drawableManager.generatePosition(table):
drawableManager.add(table)
# new thread controlling tables
tableTask = TableManager(drawableManager, menuManager)
tableTask.start()
running_tasks['table'].append(tableTask)
# new thread controlling waiter
waiter1Task = WaiterManager(drawableManager, [waiter1], kitchenManager, menuManager, tableTask)
waiter1Task.start()
running_tasks['waiter'].append(tableTask)
# waiter2Task = WaiterManager(drawableManager, [waiter2])
# waiter2Task.start()
#
# waiter3Task = WaiterManager(drawableManager, [waiter3])
# waiter3Task.start()
#
# waiter4Task = WaiterManager(drawableManager, [waiter4])
# waiter4Task.start()
# main loop
running = True
@ -96,14 +130,58 @@ while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
tableGenerator.stop()
drawableManager.stop()
tableTask.stop()
waiter1Task.stop()
# waiter2Task.stop()
# waiter3Task.stop()
# waiter4Task.stop()
running = False
# handles keyboard events
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
# checks if new waiter's position to the left is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY()):
waiter1.moveLeft()
if event.key == pygame.K_RIGHT:
# checks if new waiter's position to the right is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY()):
waiter1.moveRight()
if event.key == pygame.K_UP:
# checks if new waiter's position up is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX(), waiter1.getY() - 1):
waiter1.moveUp()
if event.key == pygame.K_DOWN:
# checks if new waiter's position down is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX(), waiter1.getY() + 1):
waiter1.moveDown()
if event.key == pygame.K_w:
# checks if new waiter's position to the left is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() - 1):
waiter1.moveLeft()
waiter1.moveUp()
if event.key == pygame.K_d:
# checks if new waiter's position to the right is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() - 1):
waiter1.moveRight()
waiter1.moveUp()
if event.key == pygame.K_s:
# checks if new waiter's position up is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() + 1, waiter1.getY() + 1):
waiter1.moveDown()
waiter1.moveRight()
if event.key == pygame.K_a:
# checks if new waiter's position down is not occupied by other object
if drawableManager.isPositionAvailable(waiter1.getX() - 1, waiter1.getY() + 1):
waiter1.moveDown()
waiter1.moveLeft()
drawableManager.forceRepaint()
# repaints all objects to the screen
# is set only on initial paint or call to forceRepaint()
# is set only on initial paint or after keyboard event or call to forceRepaint()
if drawableManager.mustRepaint():
if not kitchenManager.is_running():
gridBoard.reinitialize()
gridBoard.draw(drawableManager)
gridBoard.udpdate()
gridBoard.udpdate()

View File

@ -2,7 +2,6 @@ from collections import defaultdict
from shutil import copytree, rmtree, copy
import matplotlib.pyplot as plt
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
import threading
from tensorflow.keras.models import load_model
import kelner.src.settings as settings
@ -11,7 +10,7 @@ import kelner.src.settings as settings
#data_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101\\images'
#folder_dir = 'D:\\Nauka\\Studia\\4_sem\\SztucznaInteligencja\\A_star\\CNN\\foodRecognitionCNN\\food-101'
#foods_sorted = sorted(os.listdir(data_dir))
food_id = 0
#food_id = 0
# VISUALIZE DATA #

View File

@ -6,10 +6,10 @@ from os.path import isfile, join
from tensorflow import keras
import matplotlib.pyplot as plt
MACARONS_DIR = './././images/dataset/macarons'
PIZZA_DIR = './././images/dataset/pizza'
FFRIES_DIR = './././images/dataset/ffries'
PEAS_DIR = './././images/dataset/peas'
MACARONS_DIR = '/kelner/images/dataset/macarons'
PIZZA_DIR = '/kelner/images/dataset/pizza'
FFRIES_DIR = '/kelner/images/dataset/ffries'
PEAS_DIR = '/kelner/src/images/dataset/peas'
COUNT = 10
SIZE = 128, 128

View File

@ -1,304 +0,0 @@
import random
import math
from queue import PriorityQueue
from kelner.src.algorithms.GATableGenerator.Individual import Individual
from kelner.src.algorithms.AStar.Finder import Finder
from kelner.gui.GAdialog.GADefaults import GADefaults, CrossingOverMethod, MutationMethod, SelectionMethod
class GATableGenerator:
def __init__(self, gridCols, gridRows, params):
self.gridCols = gridCols
self.gridRows = gridRows
self.params = params
self.currentGenerationNumber = 0
self.population = None
self.bestFitnessScores = []
self.worstFitnessScores = []
self.bestTables = []
self.worstTables = []
def generateTables(self):
table = [[0] * self.gridCols for i in range(self.gridRows)]
for _ in range(self.params.runTablesCount):
isPositionUnique = False
while not isPositionUnique:
x = random.randint(0, self.gridCols - 1)
y = random.randint(0, self.gridRows - 1)
if (x, y) not in self.params.getForbiddenPlaces() and table[y][x] == 0:
isPositionUnique = True
table[y][x] = 1
table[self.params.kitchenPosition[1]][self.params.kitchenPosition[0]] = 1
return table
def getIndividual(self, table):
origin = self.params.waiterPosition
finder = Finder(table)
fitnessScore = 0
tablesCount = 0
for y in range(self.gridRows):
for x in range(self.gridCols):
if table[y][x] == 1:
tablesCount += 1
targets = finder.getNeighbours((x, y), False)
for target in targets:
if origin == target:
fitnessScore += 1
break
else:
path = finder.getPath(origin, target, True)
if path:
fitnessScore += 1
break
individual = Individual(table, fitnessScore - (tablesCount - fitnessScore), tablesCount)
return individual
def updateStats(self):
bestIndividual = self.getBestIndividual()
worstIndividual = self.getWorstIndividual()
self.bestFitnessScores.append(bestIndividual.getFitness())
self.bestTables.append(bestIndividual.getTablesCount())
self.worstFitnessScores.append(worstIndividual.getFitness())
self.worstTables.append(worstIndividual.getTablesCount())
def firstPopulation(self):
self.population = PriorityQueue()
for _ in range(self.params.runPopulationSize):
self.population.put(self.getIndividual(self.generateTables()))
self.currentGenerationNumber = 0
self.bestFitnessScores = []
self.worstFitnessScores = []
self.bestTables = []
self.worstTables = []
self.updateStats()
def getPopulationQueue(self):
queue = PriorityQueue()
for item in self.population.queue:
queue.put(item)
return queue
def getPopulationSortedArray(self):
queue = self.getPopulationQueue()
array = []
while not queue.empty():
array.append(queue.get())
return array
def arrayToQueue(self, array):
queue = PriorityQueue()
for item in array:
queue.put(item)
return queue
def selectParentsByRoulette(self):
populationArray = self.getPopulationSortedArray()
parents = []
delta = populationArray[len(populationArray) - 1].getFitness()
if delta > 0:
delta = 0
else:
delta = abs(delta) + 1
fitnessSum = 0
for individual in populationArray:
fitnessSum += individual.getFitness() + delta
for _ in range(2):
draw = random.uniform(0, 1)
accumulated = 0
for individual in populationArray:
probability = float(individual.getFitness() + delta) / fitnessSum
accumulated += probability
if draw <= accumulated:
parents.append(individual)
fitnessSum -= (individual.getFitness() + delta)
populationArray.remove(individual)
break
return parents
def selectParentsByTournament(self):
parents = []
competitorsNum = math.ceil(0.25 * self.params.runPopulationSize)
if competitorsNum < self.params.minPopulationSize:
competitorsNum = self.params.minPopulationSize - 1
population = self.getPopulationSortedArray()
parent = self.arrayToQueue(random.sample(population, competitorsNum)).get()
population.remove(parent)
parents.append(parent)
parents.append(self.arrayToQueue(random.sample(population, competitorsNum)).get())
return parents
def quadrant(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
for row in range(self.gridRows):
for col in range(self.gridCols):
if (row <= math.floor((self.gridRows - 1) / 2.0)) and (col <= math.ceil((self.gridCols - 1) / 2.0)) or \
(row > math.floor((self.gridRows - 1) / 2.0)) and (col > math.ceil((self.gridCols - 1) / 2.0)):
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def singleVerticalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divX = random.randint(1, self.gridCols - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if col <= divX:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def singleHorizontalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divY = random.randint(1, self.gridRows - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if row <= divY:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def doubleVerticalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divC = math.ceil((self.gridCols - 1) / 2)
divX1 = random.randint(1, divC - 1)
divX2 = random.randint(divC + 1, self.gridCols - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if divX1 <= col < divX2:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def doubleHorizontalDiv(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
divC = math.ceil((self.gridRows - 1) / 2)
divY1 = random.randint(1, divC - 1)
divY2 = random.randint(divC + 1, self.gridRows - 2)
for row in range(self.gridRows):
for col in range(self.gridCols):
if divY1 <= row < divY2:
childTables[row][col] = parentL.getTables()[row][col]
else:
childTables[row][col] = parentR.getTables()[row][col]
return childTables
def randomChoice(self, parentL, parentR):
childTables = [[0] * self.gridCols for i in range(self.gridRows)]
parents = [parentL.getTables(), parentR.getTables()]
for row in range(self.gridRows):
for col in range(self.gridCols):
childTables[row][col] = random.choice(parents)[row][col]
return childTables
def procreate(self):
if self.params.runSelectionMethod == SelectionMethod.Roulette:
parentLeft, parentRight = self.selectParentsByRoulette()
elif self.params.runSelectionMethod == SelectionMethod.Tournament:
parentLeft, parentRight = self.selectParentsByTournament()
child = None
if self.params.runCrossingOverMethod == CrossingOverMethod.FixedQuadrant:
child = self.quadrant(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.SingleVerticalDiv:
child = self.singleVerticalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.SingleHorizontalDiv:
child = self.singleHorizontalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.DoubleVerticalDiv:
child = self.doubleVerticalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.DoubleHorizontalDiv:
child = self.doubleHorizontalDiv(parentLeft, parentRight)
elif self.params.runCrossingOverMethod == CrossingOverMethod.RandomChoice:
child = self.randomChoice(parentLeft, parentRight)
return child
def getRandTuple(self):
isPlaceAvailable = False
while not isPlaceAvailable:
randX = random.randint(0, self.gridCols - 1)
randY = random.randint(0, self.gridRows - 1)
isPlaceAvailable = (randX, randY) not in self.params.getForbiddenPlaces()
return randX, randY
def mutateFlip(self, tables):
mutatedTables = tables
numberOfMutation = random.randint(0, self.params.runMutation)
for _ in range(numberOfMutation):
randX, randY = self.getRandTuple()
if mutatedTables[randY][randX] == 1:
mutatedTables[randY][randX] = 0
else:
mutatedTables[randY][randX] = 1
return mutatedTables
def mutateSwap(self, tables):
mutatedTables = tables
numberOfMutation = random.randint(0, self.params.runMutation)
for _ in range(numberOfMutation):
randX1, randY1 = self.getRandTuple()
randX2, randY2 = self.getRandTuple()
value = mutatedTables[randY1][randX1]
mutatedTables[randY1][randX1] = mutatedTables[randY2][randX2]
mutatedTables[randY2][randX2] = value
return mutatedTables
def makeNextGeneration(self):
tablesArray = []
eliteSize = math.ceil((self.params.runPopulationSize * self.params.runElitism) / 100.0)
for _ in range(self.params.runPopulationSize - eliteSize):
if self.params.runMutationMethod == MutationMethod.Flip:
mutated = self.mutateFlip(self.procreate())
elif self.params.runMutationMethod == MutationMethod.Swap:
mutated = self.mutateSwap(self.procreate())
tablesArray.append(mutated)
eliteArray = []
for _ in range(eliteSize):
eliteArray.append(self.population.get())
self.population = PriorityQueue()
for individual in eliteArray:
self.population.put(individual)
for table in tablesArray:
self.population.put(self.getIndividual(table))
self.currentGenerationNumber += 1
self.updateStats()
def canGenerate(self):
return self.currentGenerationNumber < self.params.runGenerationsNumber
def getBestIndividual(self):
population = self.getPopulationQueue()
return population.get()
def getWorstIndividual(self):
population = self.getPopulationSortedArray()
return population[len(population) - 1]
def printBest(self):
populationBest = self.getBestIndividual()
populationBest.print(self.currentGenerationNumber)
def printPopulation(self):
queue = self.getPopulationQueue()
while not queue.empty():
individual = queue.get()
individual.print(self.currentGenerationNumber)
print('---------------------------------------')
def makeAllGenerations(self):
self.printBest()
while self.canGenerate():
self.makeNextGeneration()
self.printBest()
"""
params = GADefaults()
generator = GATableGenerator(15, 9, params)
generator.firstPopulation()
generator.printPopulation()
while generator.canGenerate():
generator.makeNextGeneration()
generator.printPopulation()
"""

View File

@ -1,33 +0,0 @@
class Individual:
def __init__(self, table, fitnessScore, tablesCount):
self.__table = table
self.__fitnessScore = fitnessScore
self.__tablesCount = tablesCount
# operator (>) for PriorityQueue comparison (determines the objects order)
def __gt__(self, other):
return self.__fitnessScore < other.__fitnessScore
def getTables(self):
return self.__table
def getTablesCount(self):
return self.__tablesCount
def getFitness(self):
return self.__fitnessScore
def getInfo(self, generation):
return f"GENERATION: {generation}, FITNESS: {self.__fitnessScore}, TABLES: {self.__tablesCount}"
def print(self, generation):
print(self.getInfo(generation))
cols = len(self.__table[0])
rows = len(self.__table)
for row in range(rows):
for col in range(cols):
v = self.__table[row][col]
v = ' ' if v == 0 else '#' if v == 1 else 'O'
print('|', v, sep='', end='')
print('|')

View File

@ -1,3 +1,5 @@
from kelner.src.managers.ImageCache import ImageCache, Images
class Drawable:
@ -60,3 +62,15 @@ class Drawable:
def drawAux(self, screen):
pass
def getImage(self, imageKind, img_path=None):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
size = int(self.getCellSize() / 3)
elif imageKind in [Images.Kitchen, Images.Dishes]:
size = int(self.getCellSize())
else:
size = int(1.4 * self.getCellSize())
if img_path:
return ImageCache.getInstance().getImage(imageKind, size, size, img_path)
else:
return ImageCache.getInstance().getImage(imageKind, size, size)

View File

@ -1,15 +1,18 @@
import random
from enum import Enum
from threading import Lock
from kelner.src.components.Drawable import Drawable
from kelner.src.managers.ImageCache import ImageCache, Images
from kelner.src.algorithms.DecisionTree import Tree_Builder
import os
import copy
import time
import pygame
class Kitchen(Drawable):
def __init__(self, x, y, minX, maxX, minY, maxY, cellSize, offset):
def __init__(self, minX, maxX, minY, maxY, cellSize, offset):
# call base class constructor
super().__init__(x, y, minX, maxX, minY, maxY, cellSize, offset)
super().__init__(14, 0, minX, maxX, minY, maxY, cellSize, offset)
self._preparing_orders = None
self._ready_orders = None
self._photos_path = os.path.join(os.getcwd(), 'foodImages')
@ -89,17 +92,7 @@ class Kitchen(Drawable):
# print("Image drawing: {}".format(img_path))
return img_paths
def getImage(self, imageKind, img_path=None):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
size = int(self.getCellSize() / 3)
elif imageKind in [Images.Kitchen, Images.Dishes]:
size = int(self.getCellSize())
else:
size = int(1.4 * self.getCellSize())
if img_path:
return ImageCache.getInstance().getImage(imageKind, size, size, img_path)
else:
return ImageCache.getInstance().getImage(imageKind, size, size)
def draw(self, screen):
xBase = self.getX() * self.getCellSize() + self.getOffset()

View File

@ -111,7 +111,7 @@ class Table(Drawable):
self.__status = status
def __getImage(self, imageKind):
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate, Images.Chicken]:
if imageKind in [Images.Guest1, Images.Guest2, Images.Guest3, Images.Plate]:
size = int(self.getCellSize() / 3)
else:
size = int(1.4 * self.getCellSize())
@ -164,15 +164,3 @@ class Table(Drawable):
screen.blit(imagePlate, (xBase + guest1XOffset, yBase + platesYOffset))
screen.blit(imagePlate, (xBase + guest2XOffset, yBase + platesYOffset))
screen.blit(imagePlate, (xBase + guest3XOffset, yBase + platesYOffset))
elif self.isStatus(Status.Served):
platesYOffset = int(0.3 * self.getCellSize())
imageChicken = self.__getImage(Images.Chicken)
if len(self.__guests) == 1:
screen.blit(imageChicken, (xBase + guest2XOffset, yBase + platesYOffset))
elif len(self.__guests) == 2:
screen.blit(imageChicken, (xBase + guest4XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest5XOffset, yBase + platesYOffset))
elif len(self.__guests) == 3:
screen.blit(imageChicken, (xBase + guest1XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest2XOffset, yBase + platesYOffset))
screen.blit(imageChicken, (xBase + guest3XOffset, yBase + platesYOffset))

View File

@ -7,43 +7,16 @@ from kelner.src.components.Kitchen import Kitchen
# drawable objects manager
from kelner.src.managers.MenuManager import MenuManager
from kelner.src.managers.TableManager import TableManager
from kelner.src.managers.WaiterManager import WaiterManager
class DrawableCollection:
# const, minimal distance between objects
__MinDistanceX = 1
__MinDistanceY = 0
def __init__(self, kitchenManager):
def __init__(self):
# collection that holds all drawable objects
self.__mustRepaint = True
self.__drawables = []
self.__waiterLock = Lock()
self.__tasks = []
self.__kitchenManager = kitchenManager
def start(self):
# initialize menu manager
menuManager = MenuManager()
# new thread controlling tables
tableTask = TableManager(self, menuManager)
self.__tasks.append(tableTask)
waiters = self.getWaiters()
for waiter in waiters:
# new thread controlling waiter
waiterTask = WaiterManager(self, [waiter], self.__kitchenManager, menuManager, tableTask)
self.__tasks.append(waiterTask)
for task in self.__tasks:
task.start()
def stop(self):
for task in self.__tasks:
task.stop()
# adds drawable objects to the collection
def add(self, drawable):
@ -79,10 +52,6 @@ class DrawableCollection:
break
return isPositionAvailable
# deletes all tables
def delTables(self):
self.__drawables = [drawable for drawable in self.__drawables if not isinstance(drawable, Table)]
# gets all tables by status from collection
def getTables(self, status):
result = []
@ -92,10 +61,11 @@ class DrawableCollection:
return result
def get_kitchen(self):
kitchen = None
for item in self.__drawables:
if isinstance(item, Kitchen):
return item
return None
kitchen = item
return kitchen
def lock(self):
self.__waiterLock.acquire()
@ -131,8 +101,8 @@ class DrawableCollection:
nearestTables = []
tables = self.getTables(tableStatus)
for table in tables:
if (table.getX() == waiter.getX() and abs(table.getY() - waiter.getY()) == 1) or\
(table.getY() == waiter.getY() and abs(table.getX() - waiter.getX()) == 1):
if (table.getX() == waiter.getX() and abs(table.getY() - waiter.getY()) == 1) or \
(table.getY() == waiter.getY() and abs(table.getX() - waiter.getX()) == 1):
nearestTables.append(table)
return nearestTables

View File

@ -23,7 +23,6 @@ class Images(Enum):
ToolTip = 16
Kitchen = 17
Dishes = 18
Chicken = 19
class ImageCache:
@ -61,8 +60,7 @@ class ImageCache:
Images.Guest3: './images/wiking_rudy2.png',
Images.ToolTip: './images/tooltip.png',
Images.Kitchen: './images/kitchen.png',
Images.Dishes: './images/testDishes/',
Images.Chicken: './images/kurczak.png'
Images.Dishes: './images/testDishes/'
}
def __getFont(self):

View File

@ -6,8 +6,9 @@ import sys
# creates new thread
class KitchenManager(threading.Thread):
def __init__(self, gridboard):
def __init__(self, drawable_manager, gridboard):
super().__init__()
self._drawable_manager = drawable_manager
self._gridboard = gridboard
self.__runThread = False

View File

@ -1,120 +0,0 @@
import threading
from tkinter import messagebox, Tk
from kelner.src.components.Table import Table
from kelner.src.algorithms.GATableGenerator.GATableGenerator import GATableGenerator
from kelner.gui.GAdialog.GADialog import GADialog
from kelner.gui.GAdialog.GADefaults import GADefaults
from kelner.gui.chart.Plots import Plots
# creates new thread
class TableGenerator (threading.Thread):
def __init__(self, gridCols, gridRows, minX, maxX, minY, maxY, cellSize, paintOffset, drawableManager):
super().__init__()
self.__minX = minX
self.__maxX = maxX
self.__minY = minY
self.__maxY = maxY
self.__cellSize = cellSize
self.__paintOffset = paintOffset
self.__drawableManager = drawableManager
self.__runThread = True
self.__defaults = GADefaults()
self.__defaults.waiterPosition = self.__getDefaultWaiterPosition()
self.__defaults.kitchenPosition = self.__getDefaultKitchenPosition()
self.__gaTableGenerator = GATableGenerator(gridCols, gridRows, self.__defaults)
def __getDefaultWaiterPosition(self):
waiters = self.__drawableManager.getWaiters()
if waiters:
return waiters[0].getX(), waiters[0].getY()
return None
def __getDefaultKitchenPosition(self):
kitchen = self.__drawableManager.get_kitchen()
if kitchen is not None:
return kitchen.getX(), kitchen.getY()
return None
def __randomTables(self):
# initialize a number of tables given in range
for i in range(0, 40):
table = Table(self.__minX, self.__maxX, self.__minY, self.__maxY, self.__cellSize, self.__paintOffset)
if self.__drawableManager.generatePosition(table):
self.__drawableManager.add(table)
def __geneticTables(self):
bestIndividual = self.__gaTableGenerator.getBestIndividual()
for row in range(self.__gaTableGenerator.gridRows):
for col in range(self.__gaTableGenerator.gridCols):
if bestIndividual.getTables()[row][col] == 1 and \
(row != self.__defaults.kitchenPosition[1] or col != self.__defaults.kitchenPosition[0]):
table = Table(0, self.__gaTableGenerator.gridCols - 1, 0, self.__gaTableGenerator.gridRows - 1, self.__cellSize, self.__paintOffset)
table.setX(col)
table.setY(row)
self.__drawableManager.add(table)
def __askIfGA(self):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion("Rodzaj algorytmu", "Czy uruchomić algorytm genetyczny?", parent=window)
window.destroy()
return result == 'yes'
def __ask(self, info):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion(info + '\n', "Czy nowa generacja?", parent=window)
window.destroy()
return result == 'yes'
def __askIfAgain(self):
window = Tk()
window.attributes('-topmost', 'true')
window.wm_withdraw()
result = messagebox.askquestion("Potwierdź", "Czy powtórzyć proces?", parent=window)
window.destroy()
return result == 'yes'
def __plot(self):
plot = Plots(self.__gaTableGenerator.currentGenerationNumber,
self.__gaTableGenerator.bestFitnessScores, self.__gaTableGenerator.bestTables,
self.__gaTableGenerator.worstFitnessScores, self.__gaTableGenerator.worstTables,
self.__defaults.getInfo())
plot.draw()
def run(self):
if self.__askIfGA():
while self.__runThread:
again = True
GADialog(self.__defaults)
self.__gaTableGenerator.firstPopulation()
while again:
self.__drawableManager.delTables()
self.__geneticTables()
self.__drawableManager.forceRepaint()
if self.__gaTableGenerator.canGenerate():
if self.__gaTableGenerator.currentGenerationNumber % self.__defaults.runInfoFold != 0 or\
self.__ask(self.__gaTableGenerator.getBestIndividual().getInfo(self.__gaTableGenerator.currentGenerationNumber)):
self.__gaTableGenerator.makeNextGeneration()
else:
self.__drawableManager.start()
self.stop()
again = False
self.__plot()
else:
self.__plot()
if not self.__askIfAgain():
self.__drawableManager.start()
self.stop()
again = False
else:
self.__randomTables()
self.__drawableManager.forceRepaint()
self.__drawableManager.start()
def stop(self):
self.__runThread = False

View File

@ -1,7 +1,6 @@
import threading
import time
import sys
from math import sqrt
from kelner.src.components.Table import Status
from kelner.src.algorithms.AStar.Finder import Finder
from kelner.src.algorithms.BFS.BFS import BFS
@ -21,65 +20,43 @@ class WaiterManager(threading.Thread):
self._menu_manager = menu_manager
self._table_manager = table_manager
def __getDistance(self, waiter, tupleXY):
dx = waiter.getX() - tupleXY[0]
dy = waiter.getY() - tupleXY[1]
return sqrt(dx * dx + dy * dy)
def __sortTargets(self, waiter, targets):
return sorted(targets, key=lambda target: self.__getDistance(waiter, (target[0], target[1])))
def __getTargets(self, waiter, finder):
found = []
def __getNearestTargetPath(self, waiter, target):
distance = sys.maxsize
nearestTargetPath = None
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
tables = self.__drawableManager.getTables(Status.Ready)
finder = Finder(reservedPlaces)
origin = (waiter.getX(), waiter.getY())
if target == 'kitchen':
path = finder.getPath(origin, (14, 1), True)
path2 = finder.getPath(origin, (13, 0), True)
path = path2 if len(path) > len(path2) else path
return path
if tables:
origin = (waiter.getX(), waiter.getY())
for table in tables:
if table.hasOrder():
targets = finder.getNeighbours((table.getX(), table.getY()), False)
for target in targets:
if target == origin:
return []
else:
found.append(target)
return self.__sortTargets(waiter, found)
def __getNearestTargetPath(self, waiter, targets=None):
distance = sys.maxsize
nearestTargetPath = None
reservedPlaces = self.__drawableManager.getReservedPlaces(waiter)
finder = Finder(reservedPlaces)
origin = (waiter.getX(), waiter.getY())
if targets is None:
targets = self.__getTargets(waiter, finder)
for target in targets:
if distance > self.__getDistance(waiter, target):
path = finder.getPath(origin, target, True)
if path:
result = len(path)
if result < distance:
distance = result
nearestTargetPath = path
if target is not None:
path = finder.getPath(origin, target, True)
if path:
result = len(path)
if result < distance:
distance = result
nearestTargetPath = path
return nearestTargetPath
def get_specified_path(self, waiter, table):
distance = sys.maxsize
nearestTargetPath = None
reserved_places = self.__drawableManager.getReservedPlaces(waiter)
finder = Finder(reserved_places)
origin = (waiter.getX(), waiter.getY())
targets = finder.getNeighbours((table[0], table[1]), False)
for target in targets:
if distance > self.__getDistance(waiter, target):
if target is not None:
path = finder.getPath(origin, target, True)
if path:
result = len(path)
if result < distance:
distance = result
nearestTargetPath = path
return nearestTargetPath
return path
def __changeWaiterDirection(self, waiter, x, y):
targetDirection = x - waiter.getX(), y - waiter.getY()
@ -195,14 +172,13 @@ class WaiterManager(threading.Thread):
if len(waiter.getAcceptedOrders()) > 1:
waiter.set_target('kitchen')
path = self.__getNearestTargetPath(waiter, [(14, 1), (13, 0)])
path = self.__getNearestTargetPath(waiter, target=waiter.get_target())
waiter.make_busy()
else:
if waiter.get_target() == 'return_order' and waiter.isPathEmpty():
print("Order returned")
table = self._table_manager.get_table(waiter.get_remaining_positions()[0])
table.setStatus(Status.Served)
self.__changeWaiterDirection(waiter, table.getX(), table.getY())
waiter.get_remaining_positions().pop(0)
time.sleep(2)
@ -211,7 +187,7 @@ class WaiterManager(threading.Thread):
path = self.get_specified_path(waiter, waiter.get_remaining_positions()[0])
else:
waiter.set_target('table')
path = self.__getNearestTargetPath(waiter)
path = self.__getNearestTargetPath(waiter, target='table')
waiter.setPath([] if path is None else path)
@ -225,7 +201,6 @@ class WaiterManager(threading.Thread):
if waiter.get_target() == 'kitchen':
self._table_manager.pause()
kitchen = self.__drawableManager.get_kitchen()
self.__changeWaiterDirection(waiter, kitchen.getX(), kitchen.getY())
waiter_orders = waiter.getAcceptedOrders()
# print("Waiter near kitchen. Collected orders: {}".format(waiter_orders))
kitchen.add_orders(waiter_orders)

View File

@ -1,6 +0,0 @@
tensorflow==2.0.0
pygame==1.9.6
numpy==1.18.4
Pillow==7.1.2
Keras-Applications==1.0.8
Keras-Preprocessing==1.1.0