Skip to content

Commit 3d091ff

Browse files
author
Loïc Vanden Bemden
committed
Release v2.2 pushed
1 parent fe0ce3d commit 3d091ff

24 files changed

+1086
-144
lines changed

HOWTO.md

Lines changed: 378 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,39 @@
11
# Blob Simulation & Detection
22
Détection d'un blob dans une image ainsi que détection des comprimés de nourriture. Simulation d'un blob dans PyGame à travers un système multi-agents à connaissance partagée.
33

4+
1. [How to use](HOWTO.md)
5+
2. [Requirements](#requirements)
6+
3. [Pour aller plus loin](TOGOFURTHER.md)
7+
4. [Releases](#releases)
8+
5. [License](#license)
9+
6. [Mentions légales](#mentions-legales)
10+
11+
## How to use
12+
Vous trouverez la description détaille des différents scripts et des fichiers de configuration [ici](HOWTO.md).
13+
14+
## Requirements
15+
+ [Python 3.6.8](https://www.python.org/downloads/release/python-368/) - [Documentation](https://docs.python.org/3.6/)
16+
+ [Numpy 1.16.4](https://pypi.org/project/numpy/1.16.4/) - BSD License
17+
+ [Pathfinding 0.0.4](https://pypi.org/project/pathfinding/0.0.4/) - MIT License
18+
+ [PyGame 1.9.6](https://pypi.org/project/pygame/1.9.6/) - LGPL License - [Documentation](https://www.pygame.org/docs/)
19+
+ [Imutils 0.5.2](https://pypi.org/project/imutils/0.5.2/) - MIT License
20+
+ [OpenCV Python 4.1.0.25](https://pypi.org/project/opencv-python/4.1.0.25/) - MIT License - [Documentation](https://docs.opencv.org/4.1.0/)
21+
22+
## Pour aller plus loin
23+
Vous trouverez quelques articles scientifiques et conseils de lecture en lien avec le développement de ce projet [ici](TOGOFURTHER.md).
24+
25+
## Releases
26+
## Release 2.2 - *24/06/2019*
27+
### Modifications :
28+
+ Ajout d'un fichier requirements.txt avec les versions des modules utilisées
29+
+ Transformation de l'argument "input" en argument positionnel
30+
31+
### Scripts :
32+
+ Setup : `python setup.py data/example.jpg`
33+
+ Detection : `python detect.py data/example.jpg`
34+
+ Simulation : `python play.py data/output-examples/example-detect.board -s 3`
35+
+ Compare : `python compare.py data/output-examples/simulation/10_loops/10_loops.board data/output-examples/simulation/100_loops/100_loops.board -s 3`
36+
437
## Release 2.1 - *7/06/2019*
538

639
### Modifications :

TOGOFURTHER.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Pour aller plus loin
2+
## Physarum polycephalum ou Blob
3+
Beaucoup d'articles scientifiques (et des livres de vulgarisation) existent sur le blob mais ceux-ci se concentrent sur l'analyse de son comportement et sur sa faculté à résoudre certains problèmes. La plupart de ses problèmes sont liés à des représentations sous forme de graphe (TSP Problem, Dijkstra, Voronoï diagram, Delaunay triangluation, ...) Il n'y a donc pas d'articles cherchant à modéliser son comportement. Au niveau détection, il existe le code MatLab fourni par le CNRS.
4+
5+
**Dussutour**, Audrey (2017).*Tout ce que vous avez toujours voulu savoir sur le blob sans avoir jamais oser le demander.* Des Équateurs, Hors collection, 179 pages.
6+
7+
**Tsuda**, Soichiro, **Zauner**, Klaus-Peter and **Gunji**, Yukio-Pegio (2006) *Robot Control: From Silicon Circuitry to Cells.* Ijspeert, Auke Jan, Masuzawa, Toshimitsu and Kusumoto, Shinji (eds.) In Biologically Inspired Approaches to Advanced Information Technology, Second International Workshop, BioADIT 2006, Osaka, Japan, January 26-27, 2006, Proceedings. Springer. pp. 20-32.
8+
9+
**Whiting** JG, **Jones** J, **Bull** L, **Levin** M, **Adamatzky** A.* Towards a Physarum learning chip*. *Sci Rep*. 2016;6:19948. Published 2016 Feb 3.
10+
11+
**Jones, Jeff, &amp; Andrew Adamatzky.** [Computation of the travelling salesman problem by a shrinking blob](http://www.phychip.eu/wp-content/uploads/2013/03/Computation-of-the-travelling-salesman-problem-by-a-shrinking-blob.pdf) *Natural Computing,* (13), 1, p. 1-16, (2014).</p>
12+
**Shirakawa**, Tomohiro &amp; **Adamatzky**, Andrew &amp; **Gunji**, Yukio-Pegio &amp; **Miyake**, Yoshihiro. (2009). On Simultaneous Construction of Voronoi Diagram and Delaunay Triangulation by. I. J. Bifurcation and Chaos. 19. 3109-3117. 10.1142/S0218127409024682.
13+
14+
## Système multi-agents
15+
16+
En soi, le blob n'est pas un système multi-agents puisqu'il n'est constitué que d'une seule cellule. Néanmoins, la plupart des problèmes qu'il arrive à résoudre sont aujourd'hui plus facilement résolu par des systèmes multi-agents.
17+
18+
Un type connu de système multi-agents est le comportement d'une colonie de fourmis. On retrouve donc le lien entre blob et fourmis à travers ses différents problèmes. Audrey Dussutour, avant de se concentrer sur le blob, se spécifiait dans le comportement des fourmis également.
19+
20+
NetLogo est un langage de programmation pour système multi-agents, basé sur du Logo (lui-même basé sur du LISP). L'environnement n'est pas ultra-modulable mais il fournit une série de modèles implémentés et prêts à l'emploi. Certains de ceux-ci (listés ci-dessous) correspondent aux problèmes résolus par le blob ou par des algorithmes ACO (Ants Colony Optimization).
21+
22+
Il existe également un pseudo-code permettant de simuler le comportement d'un blob à travers une approche multi-agents.
23+
24+
Wilensky, U. (1999). **NetLogo**. [http://ccl.northwestern.edu/netlogo/](http://ccl.northwestern.edu/netlogo/) Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.</p>
25+
26+
### Modèles
27+
+ Stonedahl, F. and Wilensky, U. (2008). [**NetLogo Virus on a Network model**](http://ccl.northwestern.edu/netlogo/models/VirusonaNetwork). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
28+
29+
+ Wilensky, U. (2005). [**NetLogo Preferential Attachment model**](http://ccl.northwestern.edu/netlogo/models/PreferentialAttachment). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
30+
31+
+ Stonedahl, F. and Wilensky, U. (2008). [**NetLogo Diffusion on a Directed Network model**](http://ccl.northwestern.edu/netlogo/models/DiffusiononaDirectedNetwork). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
32+
33+
+ Grider, R. and Wilensky, U. (2015). [**NetLogo Paths model**](http://ccl.northwestern.edu/netlogo/models/Paths). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL
34+
+ Wilensky, U. (1997). [**NetLogo Ant Lines model**](http://ccl.northwestern.edu/netlogo/models/AntLines). Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
35+
36+
[Pseudo-code multi-agents pour simuler un blob](http://www.simulace.info/index.php/Multi-agent_systems) dans NetLogo.
37+
38+
## IA &amp; Optimization Algorithm Problems
39+
Aucune base de données n'étant disponible pour simuler le blob dans le cas précis du projet, il est nécessaire d'en revenir à des comportements prédits de manière algorithmiques.
40+
41+
Les techniques classiques d'IA utilisées pour résoudre des problèmes par exploration d'arbres de solution sont donc à privilégier. Le blob peut être envisagé comme un joueur devant découvrir au plus vite des ressources dans un environnement inconnu et à optimiser les connexions entre ces ressources. Sur ce second point, il travaille donc comme un algorithme ACO. Pour la partie découverte, il existe également déjà des simulateurs de parcours de fourmis mais ceux trouvés sont difficilement modifiables.
42+
43+
**Russel**, Stuart Jonathan, **Norvig**, Peter (2009). *Artificial Intelligence : A modern approach*. Pearson, 3rd Edition,&nbsp; 1152 pages.
44+
45+
**geoyar**(2013). [*Applying Ant Colony Optimization Algorithms to Solve the Traveling Salesman Problem*](https://www.codeproject.com/articles/644067/applying-ant-colony-optimization-algorithms-to-sol). Code Project.
46+
47+
**Kohout** Peter (2006). [*Genetic and Ant Colony Optimization Algorithms*](https://www.codeproject.com/Articles/5436/Genetic-and-Ant-Colony-Optimization-Algorithms). Code Project.
48+
49+
**Lichtenberg** Malte, **Tittmann** Lucas (2012). [Programmation Project - Ant Simulation](https://github.com/Andarin/Ant-Colony-Simulation-Python). Andarin, Github Code (Python 2, Cython).
50+
51+
**Akavall** (2019). [Ant Colony Optimization Algorithm using Python](https://github.com/Akavall/AntColonyOptimization). Akavall, Github Code (Python 3).
52+
53+
## License
54+
Copyright (C) 2019 - UMons
55+
56+
This library is free software; you can redistribute it and/or
57+
modify it under the terms of the GNU Lesser General Public
58+
License as published by the Free Software Foundation; either
59+
version 2.1 of the License, or (at your option) any later version.
60+
61+
This library is distributed in the hope that it will be useful,
62+
but WITHOUT ANY WARRANTY; without even the implied warranty of
63+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64+
Lesser General Public License for more details.
65+
66+
You should have received a copy of the GNU Lesser General Public
67+
License along with this library; if not, write to the Free Software
68+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
69+
70+
## Mentions légales
71+
Cette publication a été réalisée dans le cadre du projet Interreg de coopération transfrontalière C2L3PLAY, cofinancé par L’Union Européenne. Avec le soutien du Fonds européen de développement régional / Met steun van het Europees Fonds voor Regionale Ontwikkeling
72+
73+
<img src="https://crossborderlivinglabs.eu/wp-content/uploads/2018/02/LogoProjets_GoToS3_C2L3PLAY.png" width="200px"/>

compare.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@
2121

2222

2323
def main():
24-
ap = argparse.ArgumentParser()
25-
ap.add_argument("--first", required=True, help="first board file")
26-
ap.add_argument("--second", required=True, help="second board file")
24+
ap = argparse.ArgumentParser(description="Compare two board files and express it as an image.")
25+
ap.add_argument("input_1", metavar= "FIRST_INPUT", help="first board file")
26+
ap.add_argument("input_2", metavar= "SECOND_INPUT", help="second board file to compare with")
2727
ap.add_argument("-s", "--scale", type=float, default=10,
2828
help="Scales board resolution by this factor (default: x10)")
2929
ap.add_argument("-o", "--output", type=str, help="Give a name to save the jpeg file")
3030
args = ap.parse_args()
3131

3232
board_1 = board.Board(0, 0)
33-
board_1.load(args.first)
33+
board_1.load(args.input_1)
3434

3535
board_2 = board.Board(0, 0)
36-
board_2.load(args.second)
36+
board_2.load(args.input_2)
3737

3838
board_comp = board_1.compare(board_2)
3939

detect.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323

2424
def main():
25-
ap = argparse.ArgumentParser()
26-
ap.add_argument("-i", "--input", required=True, help="Uses this input as image for detection")
25+
ap = argparse.ArgumentParser("Detect a blob and foods in an image.")
26+
ap.add_argument("input", metavar="INPUT", help="Uses this input as image for detection")
2727
ap.add_argument("-s", "--scale", type=float, default=0.10, help="Scales images by this factor (default: x0.1)")
2828
ap.add_argument("-c", "--config", type=str, default="detection/config.json",
2929
help="Loads config from this file (default: detection/config.json)")
@@ -57,7 +57,9 @@ def main():
5757
else:
5858
file_path = None
5959

60-
print_results(orig, blob_mask, blob, food_mask, food_img, dsc_img, args.scale, file_path, args.hide)
60+
labels = ["Original", "Discrete", "Blob Mask", "Blob", "Food Mask", "Food Regions"]
61+
images = [orig, img, blob_mask, blob, food_mask, food_img]
62+
print_results(labels, images, args.scale, file_path, args.hide, nbr_width=2)
6163

6264

6365
if __name__ == "__main__":

detection/detection.py

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,21 @@
1515
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1616

1717
from detection.utils import *
18+
from math import ceil
1819

1920

2021
def detect(input_file, config):
21-
22+
"""
23+
Starts blob detection in the image and returns
24+
- the part of the image used (resized and warp perpective)
25+
- blob mask detected
26+
- blob segmented image
27+
- food mask detected
28+
- the image with food regions
29+
30+
:param input_file: string filename for jpeg image detection
31+
:param config: dict with config used for detection
32+
"""
2233
img = cv2.imread(input_file)
2334
height, width, _ = img.shape
2435

@@ -64,56 +75,62 @@ def detect(input_file, config):
6475
return img, blob_mask, blob, food_mask, food_img
6576

6677

67-
def print_results(orig, blob_mask, blob, food_mask, food, discrete, scale=1.0, filename=None, hide=False):
78+
def print_results(labels, images, scale=1.0, filename=None, hide=False, nbr_width=2):
79+
"""
80+
Aggregate and show images in one window with each label displayed at the top of them.
81+
It can as well save the aggregated image.
82+
Each line contains 'nbr_width' images.
83+
If the number of images doesn't fit the last line, it's padded with a zero image.
84+
85+
:param labels: each label to use for each image in images. assert len(labels) == len(images)
86+
:param images: each image to print in results window
87+
:param scale: the scale to use for results window with respect to image size
88+
:param filename: if provide, save results window under 'filename'.jpg name
89+
:param hide: if true, the results window isn't shown
90+
:param nbr_width: number of images to fit in line
91+
"""
6892
padding = 35
69-
nbr_width = 2
70-
nbr_height = 3
7193
font = cv2.FONT_HERSHEY_SIMPLEX
7294
fontsize = 0.45
7395
thickness = 1
7496

75-
scaled_height = int(orig.shape[0]*scale)
76-
scaled_width = int(orig.shape[1]*scale)
97+
scaled_height = int(images[0].shape[0]*scale)
98+
scaled_width = int(images[0].shape[1]*scale)
99+
pad = np.zeros((scaled_height, padding, 3), dtype=np.uint8)
100+
line_pad = np.zeros((padding, (scaled_width + padding) * nbr_width + padding, 3), dtype=np.uint8)
101+
img_pad = np.zeros((scaled_height, scaled_width, 3), dtype=np.uint8)
102+
103+
print_images = []
104+
for image in images:
105+
full_color = image if len(image.shape) == 3 else cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
106+
print_image = cv2.resize(full_color, (scaled_width, scaled_height))
107+
print_images.append(print_image)
108+
109+
middle = ((0, int(scaled_height / 2)), (scaled_width, int(scaled_height / 2)))
110+
cv2.line(print_images[0], middle[0], middle[1], (0, 255, 0), thickness=1)
111+
cv2.putText(print_images[0], 'Mid Line', (middle[0][0] + 5, middle[0][1] - 5),
112+
font, fontsize, (0, 255, 0), thickness, cv2.LINE_AA)
113+
114+
lines = [line_pad]
115+
for j in range(ceil(len(images)/nbr_width)):
116+
concat_line = [pad]
117+
for i in range(nbr_width):
118+
if i + j * nbr_width < len(images):
119+
concat_line.append(print_images[i + j * nbr_width])
120+
else:
121+
concat_line.append(img_pad)
122+
concat_line.append(pad)
77123

78-
pad = np.zeros((scaled_height, padding, orig.shape[2]), dtype=np.uint8)
79-
line_pad = np.zeros((padding, (scaled_width + padding) * nbr_width + padding, orig.shape[2]), dtype=np.uint8)
80-
print_img = cv2.resize(orig, (scaled_width, scaled_height))
124+
lines.append(np.concatenate(tuple(concat_line), axis=1))
125+
lines.append(line_pad)
81126

82-
middle = ((0, int(scaled_height/2)), (scaled_width, int(scaled_height/2)))
83-
cv2.line(print_img, middle[0], middle[1], (0, 255, 0), thickness=1)
84-
cv2.putText(print_img, 'Mid Line', (middle[0][0] + 5, middle[0][1] - 5),
85-
font, fontsize, (0, 255, 0), thickness, cv2.LINE_AA)
127+
aggregate = np.concatenate(tuple(lines))
86128

87-
print_blob_mask = cv2.resize(cv2.cvtColor(blob_mask, cv2.COLOR_GRAY2BGR), (scaled_width, scaled_height))
88-
print_blob = cv2.resize(blob, (scaled_width, scaled_height))
89-
print_food_mask = cv2.resize(cv2.cvtColor(food_mask, cv2.COLOR_GRAY2BGR), (scaled_width, scaled_height))
90-
print_food = cv2.resize(food, (scaled_width, scaled_height))
91-
print_discrete = cv2.resize(discrete, (scaled_width, scaled_height))
92-
93-
concat_line1 = np.concatenate((pad, print_img, pad, print_discrete, pad), axis=1)
94-
concat_line2 = np.concatenate((pad, print_blob_mask, pad, print_blob, pad), axis=1)
95-
concat_line3 = np.concatenate((pad, print_food_mask, pad, print_food, pad), axis=1)
96-
97-
aggregate = np.concatenate((line_pad, concat_line1, line_pad, concat_line2, line_pad, concat_line3, line_pad))
98-
99-
cv2.putText(aggregate, 'Original:',
100-
(0 * (scaled_width + padding) + padding + 5, 0 * (scaled_height + padding) + padding - 5),
101-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
102-
cv2.putText(aggregate, 'Discrete:',
103-
(1 * (scaled_width + padding) + padding + 5, 0 * (scaled_height + padding) + padding - 5),
104-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
105-
cv2.putText(aggregate, 'Blob Mask:',
106-
(0 * (scaled_width + padding) + padding + 5, 1 * (scaled_height + padding) + padding - 5),
107-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
108-
cv2.putText(aggregate, 'Blob:',
109-
(1 * (scaled_width + padding) + padding + 5, 1 * (scaled_height + padding) + padding - 5),
110-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
111-
cv2.putText(aggregate, 'Food Mask:',
112-
(0 * (scaled_width + padding) + padding + 5, 2 * (scaled_height + padding) + padding - 5),
113-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
114-
cv2.putText(aggregate, 'Food Regions:',
115-
(1 * (scaled_width + padding) + padding + 5, 2 * (scaled_height + padding) + padding - 5),
116-
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
129+
for i in range(len(print_images)):
130+
cv2.putText(aggregate, labels[i],
131+
((i % nbr_width) * (scaled_width + padding) + padding + 5,
132+
int(i/nbr_width) * (scaled_height + padding) + padding - 5),
133+
font, fontsize, (255, 255, 255), thickness, cv2.LINE_AA)
117134

118135
if filename is not None:
119136
cv2.imwrite(filename + ".jpg", aggregate)
@@ -125,6 +142,15 @@ def print_results(orig, blob_mask, blob, food_mask, food, discrete, scale=1.0, f
125142

126143

127144
def discretize(blob_img, food_mask, width, height):
145+
"""
146+
Transform blob and foods into a numeric blob and foods with discrete 'width' and 'height' resolution
147+
148+
:param blob_img: a blob segmented numpy image
149+
:param food_mask: a food mask numpy image
150+
:param width: (int) the discrete width resolution
151+
:param height: (int) the discrete height resolution
152+
:return: the new image (as a saved simulated-like), the blob values in the image and the complete food position list
153+
"""
128154
img_height, img_width, _ = blob_img.shape
129155

130156
discrete_blob = cv2.resize(blob_img, (width, height), interpolation=cv2.INTER_NEAREST)

0 commit comments

Comments
 (0)