-
Notifications
You must be signed in to change notification settings - Fork 1
/
Mazes Manipulation Script.py
351 lines (290 loc) · 9.54 KB
/
Mazes Manipulation Script.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
#!/usr/bin/env python
# coding: utf-8
# # Mazes Manipulation Script
#
# Authors: https://github.com/Amable-Valdes/Prolog-Mazes
# copyright 2019 Amable José Valdés Cuervo and Sergio Florez
"""
Imports
We use openCV for the manipulation
of images and numpy to treat
the matrices.
"""
import numpy as np
import cv2
"""
Constants
They represent the diferent
elements we can find in a maze.
"""
END = 3
START = 2
WALL = 0
EMPTY = 1
"""
Prolog rules creation
"""
def translate(vectorRGB):
"""
RGB translator.
This function translate a numpy array of 3 positions
(Red, Greens and Blues) and decide if the vector is
a wall, an empty space, the start or the end of a maze.
Parameters
----------
vectorRGB : numpyArray of int[3]
An array with 3 positions (Red, Greens and Blues)
with the color coded as a value between 0 and 255
on the RGB scale
Returns
-------
int
The simbol we are using to identify a element of
the maze; a wall, an empty space, the start or the end.
"""
if(vectorRGB[0] > 150 and vectorRGB[1] > 150 and vectorRGB[2] > 150):
# If white, empty
return EMPTY
if(vectorRGB[0] < 150 and vectorRGB[1] > 150 and vectorRGB[2] < 150):
# If green, end
return END
if(vectorRGB[0] < 150 and vectorRGB[1] < 150 and vectorRGB[2] > 150):
# If blue, start
return START
if(vectorRGB[0] == 0 and vectorRGB[1] == 0 and vectorRGB[2] == 0):
# If black, wall
return WALL
# If is different from above (an strange value), wall
return WALL
def initial_state(maze):
"""
Initial position rule
This function search in a conceptual maze the position
where we will start our steps to solve the maze and
returns a string with the fact that it would
indicate the initial position written in prolog.
Parameters
----------
maze : numpyArray of int[][]
The conceptual maze where we are looking
the start point.
Returns
-------
str
The fact that it would indicate the
initial position written in prolog.
"""
for i,row in enumerate(maze):
for j,value in enumerate(row):
if(value == START):
return ("initial_state( maze, p(%i,%i) )."%(i,j) )
def final_state(maze):
"""
End position rule
This function search in a conceptual maze the position
where we will stop to solve the maze and
returns a string with the fact that it would
indicate the final position written in prolog.
Parameters
----------
maze : numpyArray of int[][]
The conceptual maze where we are looking
the end point.
Returns
-------
str
The fact that it would indicate the
final position written in prolog.
"""
for i,row in enumerate(maze):
for j,value in enumerate(row):
if(value == END):
return ("final_state( maze, p(%d,%d) )."%(i,j) )
def translate_image_to_maze(img):
"""
Image to matrix translator
This function takes a cv2 image and translate it
to a int matrix .
Parameters
----------
img : numpyArray[][] of numpyArray[3]
The image with the RGB vectors that we are reading
and we will translate to a conceptual maze.
Returns
-------
numpyArray of int[][]
The conceptual maze where we are looking
the start point.
"""
# Maze size == Image size
width, height = img.shape[:2]
# At the begining, our maze is a matrix of all ones
maze = np.ones([width,height])
# We iterate in the rows and columns
for i,row in enumerate(img):
for j,pixel in enumerate(row):
# We translate the RGB vector of a pixel to
# a simbolic element (wall, empty space...)
# of our maze
label = translate(pixel)
maze[i][j] = float(label)
return maze
def translate_image_into_rules(img_path, rules=False):
"""
Image to rule translator
This function takes an image path and generate a cv2
image. After that we create a conceptual maze and with
that maze we generate the rules or facts written in prolog.
This function write a .pl file with all the
facts or rules for the prolog program saved in
the same repositore where this program has been download:
https://github.com/Amable-Valdes/Prolog-Mazes
We also print all the rules or facts written in
the file on the console.
Parameters
----------
img_path : str
The str path where the maze image is. This
image must have one (or more) red pixel (start),
black pixels (walls), white pixels (empty spaces)
and one (or more) green pixel (end).
"""
print("New rules for maze " + img_path)
#We read the image
img = cv2.imread(img_path)
# We translate the image to a conceptual maze
maze = translate_image_to_maze(img)
# We create the .pl file where the rules or
# facts will be written
file = open(img_path.split('.')[0] + ".pl","w")
# We write the initial state rule (start)
line = initial_state(maze)
file.write(line)
file.write("\n")
print(line)
print()
# We write the final state rule (end)
line = final_state(maze)
file.write(line)
file.write("\n")
print(line)
print()
if rules:
line = ("c(X, Y, wall) :-\n" )
file.write(line)
print(line)
# We iterate in every matrix[i][j]
# (the maze) value and if it's a
# wall we write a fact or rule with the
# wall position.
for i,row in enumerate(maze):
for j,value in enumerate(row):
if(value == WALL):
if rules:
line = ("\tX = %d, Y = %d\n\t;\n"%(i,j) )
file.write(line)
else:
line = ("c(%d,%d,wall).\n"%(i,j) )
file.write(line)
print(line)
if rules:
width, height = img.shape[:2]
line = ("\tX > %d; Y > %d."%(width, height) )
file.write(line)
print(line)
file.close()
print("New rules for maze in file " + img_path.split('.')[0] + ".pl")
"""
Image with steps creation
"""
def translate_step(step):
"""
Translate the order to a conceptual step
This function takes the order pased as parameter
and translates it to an array with dimension 2
that is the conceptual step. This conceptual step
will be added to the actual position in the
conceptual maze, simulating a movement.
Parameters
----------
step : str
The str that represent the step. This can
be "UP", "DOWN", "LEFT" or "RIGHT".
Returns
-------
array[2]
An array with dimension 2 that represent the
movement in coordenades in a conceptual maze.
"""
if(step == "UP"):
return [-1,0]
if(step == "DOWN"):
return [1,0]
if(step == "LEFT"):
return [0,-1]
if(step == "RIGHT"):
return [0,+1]
def start_point(maze):
"""
Look for the start point
This function look in the conceptual maze
for the start point.
Parameters
----------
maze : numpyArray of int[][]
The conceptual maze where we are looking
the start point.
Returns
-------
int[2]
An array with dimension 2 that represent
the coordenade where the start point is.
"""
for i,row in enumerate(maze):
for j,value in enumerate(row):
if(value == START):
return [i,j]
def draw_path_on_maze(original_image_path,steps):
"""
Drawer of steps in a maze
This function takes the image of a maze and
an array of steps to solve the maze. After
the translation of this information it
draws in a new image the path in
purple to solve the maze.
The new image is saved in the same path
of the image passed as parameter with
the original image name plus "-steps.png".
Parameters
----------
original_image_path : str
The string path where the maze image is. This
image must have one (or more) red pixel (start),
black pixels (walls), white pixels (empty spaces)
and one (or more) green pixel (end).
steps : array of str
An array of strings that represent the
correct path to solve the maze.
"""
# Read the original image.
img = cv2.imread(original_image_path)
# Translate the image to a conceptual maze.
maze = translate_image_to_maze(img)
# We look the start point.
actual_point = start_point(maze)
# For all the steps we have passed as parameter
# (except the last, that is the final position) ...
for step in steps[:-1]:
# ... we change our position adding the value of
# the conceptual step to the actual position ...
movement = translate_step(step)
actual_point[0] = actual_point[0] + movement[0]
actual_point[1] = actual_point[1] + movement[1]
# ... and we change the color of that position
# in the image to purple.
img[actual_point[0]][actual_point[1]][0] = 197
img[actual_point[0]][actual_point[1]][1] = 75
img[actual_point[0]][actual_point[1]][2] = 140
# We draw the new image and we saved it.
cv2.imwrite(original_image_path.split('.')[0] + '-steps.png', img)
print("New image " + original_image_path.split('.')[0] + "-steps.png created!")