From a415c73c9178a3dad211a7842a69819350c6d1dd Mon Sep 17 00:00:00 2001 From: hagrid67 <jdhwatson@gmail.com> Date: Sat, 18 May 2019 17:03:52 +0100 Subject: [PATCH] added transparency / opacity with PIL. moved test_player.py to using PIL and tkinter instead of QT --- examples/play_model.py | 4 +- examples/tkplay.py | 59 ++++++++++++++ flatland/utils/graphics_layer.py | 2 +- flatland/utils/graphics_pil.py | 56 ++++++++++--- flatland/utils/rendertools.py | 132 +++++++++++++++++++------------ images/basic-env.npz | Bin 36398 -> 10007 bytes tests/test_player.py | 5 +- tests/test_rendertools.py | 4 +- 8 files changed, 193 insertions(+), 69 deletions(-) create mode 100644 examples/tkplay.py diff --git a/examples/play_model.py b/examples/play_model.py index 5ed6feb..777f2d3 100644 --- a/examples/play_model.py +++ b/examples/play_model.py @@ -100,7 +100,7 @@ def max_lt(seq, val): return None -def main(render=True, delay=0.0, n_trials=3, n_steps=50): +def main(render=True, delay=0.0, n_trials=3, n_steps=50, sGL="QT"): random.seed(1) np.random.seed(1) @@ -111,7 +111,7 @@ def main(render=True, delay=0.0, n_trials=3, n_steps=50): if render: # env_renderer = RenderTool(env, gl="QTSVG") - env_renderer = RenderTool(env, gl="QT") + env_renderer = RenderTool(env, gl=sGL) oPlayer = Player(env) diff --git a/examples/tkplay.py b/examples/tkplay.py new file mode 100644 index 0000000..b337253 --- /dev/null +++ b/examples/tkplay.py @@ -0,0 +1,59 @@ + +import tkinter as tk +from PIL import ImageTk, Image +from examples.play_model import Player +from flatland.envs.rail_env import RailEnv +from flatland.envs.generators import complex_rail_generator +from flatland.utils.rendertools import RenderTool +import time + + +def tkmain(n_trials=2): + # This creates the main window of an application + window = tk.Tk() + window.title("Join") + window.configure(background='grey') + + # Example generate a random rail + env = RailEnv(width=15, height=15, + rail_generator=complex_rail_generator(nr_start_goal=5, nr_extra=20, min_dist=12), + number_of_agents=5) + + env_renderer = RenderTool(env, gl="PIL") + + oPlayer = Player(env) + n_trials = 1 + n_steps = 20 + delay = 0 + for trials in range(1, n_trials + 1): + + # Reset environment8 + oPlayer.reset() + env_renderer.set_new_rail() + + first = True + + for step in range(n_steps): + oPlayer.step() + env_renderer.renderEnv(show=True, frames=True, iEpisode=trials, iStep=step, + action_dict=oPlayer.action_dict) + img = env_renderer.getImage() + img = Image.fromarray(img) + tkimg = ImageTk.PhotoImage(img) + + if first: + panel = tk.Label(window, image = tkimg) + panel.pack(side = "bottom", fill = "both", expand = "yes") + else: + # update the image in situ + panel.configure(image=tkimg) + panel.image = tkimg + + window.update() + if delay > 0: + time.sleep(delay) + first = False + + +if __name__ == "__main__": + tkmain() \ No newline at end of file diff --git a/flatland/utils/graphics_layer.py b/flatland/utils/graphics_layer.py index 4cfcc64..40bf319 100644 --- a/flatland/utils/graphics_layer.py +++ b/flatland/utils/graphics_layer.py @@ -51,7 +51,7 @@ class GraphicsLayer(object): elif type(color) is tuple: if type(color[0]) is not int: gcolor = array(color) - color = tuple((gcolor[:3] * 255).astype(int)) + color = tuple((gcolor[:4] * 255).astype(int)) else: color = self.tColGrid diff --git a/flatland/utils/graphics_pil.py b/flatland/utils/graphics_pil.py index 41516fd..ceda3fd 100644 --- a/flatland/utils/graphics_pil.py +++ b/flatland/utils/graphics_pil.py @@ -18,28 +18,32 @@ class PILGL(GraphicsLayer): # Total grid size at native scale self.widthPx = self.width * self.nPixCell + self.linewidth self.heightPx = self.height * self.nPixCell + self.linewidth - self.beginFrame() + self.layers = [] + self.draws = [] self.tColBg = (255, 255, 255) # white background # self.tColBg = (220, 120, 40) # background color self.tColRail = (0, 0, 0) # black rails self.tColGrid = (230,) * 3 # light grey for grid - def plot(self, gX, gY, color=None, linewidth=3, **kwargs): - color = self.adaptColor(color) + self.beginFrame() - # print(gX, gY) + def plot(self, gX, gY, color=None, linewidth=3, layer=0, opacity=255, **kwargs): + color = self.adaptColor(color) + if len(color) == 3: + color += (opacity,) + elif len(color) == 4: + color = color[:3] + (opacity,) gPoints = np.stack([array(gX), -array(gY)]).T * self.nPixCell gPoints = list(gPoints.ravel()) - # print(gPoints, color) - self.draw.line(gPoints, fill=color, width=self.linewidth) + self.draws[layer].line(gPoints, fill=color, width=self.linewidth) - def scatter(self, gX, gY, color=None, marker="o", s=50, *args, **kwargs): + def scatter(self, gX, gY, color=None, marker="o", s=50, layer=0, opacity=255, *args, **kwargs): color = self.adaptColor(color) r = np.sqrt(s) gPoints = np.stack([np.atleast_1d(gX), -np.atleast_1d(gY)]).T * self.nPixCell for x, y in gPoints: - self.draw.rectangle([(x - r, y - r), (x + r, y + r)], fill=color, outline=color) + self.draws[layer].rectangle([(x - r, y - r), (x + r, y + r)], fill=color, outline=color) def text(self, *args, **kwargs): pass @@ -51,8 +55,8 @@ class PILGL(GraphicsLayer): pass def beginFrame(self): - self.img = Image.new("RGBA", (self.widthPx, self.heightPx), (255, 255, 255, 255)) - self.draw = ImageDraw.Draw(self.img) + self.create_layer(0) + self.create_layer(1) def show(self, block=False): pass @@ -62,5 +66,35 @@ class PILGL(GraphicsLayer): pass # plt.pause(seconds) + def alpha_composite_layers(self): + img = self.layers[0] + for img2 in self.layers[1:]: + img = Image.alpha_composite(img, img2) + return img + def getImage(self): - return array(self.img) + """ return a blended / alpha composited image composed of all the layers, + with layer 0 at the "back". + """ + img = self.alpha_composite_layers() + return array(img) + + def create_image(self, opacity=255): + img = Image.new("RGBA", (self.widthPx, self.heightPx), (255, 255, 255, opacity)) + return img + + def create_layer(self, iLayer=0): + if len(self.layers) <= iLayer: + for i in range(len(self.layers), iLayer+1): + if i==0: + opacity = 255 # "bottom" layer is opaque (for rails) + else: + opacity = 0 # subsequent layers are transparent + img = self.create_image(opacity) + self.layers.append(img) + self.draws.append(ImageDraw.Draw(img)) + else: + opacity = 0 if iLayer > 0 else 255 + self.layers[iLayer] = img = self.create_image(opacity) + self.draws[iLayer] = ImageDraw.Draw(img) + diff --git a/flatland/utils/rendertools.py b/flatland/utils/rendertools.py index e9a94ec..4def953 100644 --- a/flatland/utils/rendertools.py +++ b/flatland/utils/rendertools.py @@ -15,12 +15,14 @@ from flatland.utils.graphics_layer import GraphicsLayer class MPLGL(GraphicsLayer): - def __init__(self, width, height): + def __init__(self, width, height, show=False): self.width = width self.height = height self.yxBase = array([6, 21]) # pixel offset self.nPixCell = 700 / width self.img = None + if show: + plt.figure(figsize=(10, 10)) def plot(self, *args, **kwargs): plt.plot(*args, **kwargs) @@ -70,6 +72,7 @@ class MPLGL(GraphicsLayer): def beginFrame(self): self.img = None plt.figure(figsize=(10, 10)) + plt.clf() pass def endFrame(self): @@ -115,7 +118,7 @@ class RenderTool(object): gTheta = np.linspace(0, np.pi / 2, 5) gArc = array([np.cos(gTheta), np.sin(gTheta)]).T # from [1,0] to [0,1] - def __init__(self, env, gl="MPL"): + def __init__(self, env, gl="MPL", show=False): self.env = env self.iFrame = 0 self.time1 = time.time() @@ -123,7 +126,7 @@ class RenderTool(object): # self.gl = MPLGL() if gl == "MPL": - self.gl = MPLGL(env.width, env.height) + self.gl = MPLGL(env.width, env.height, show=show) elif gl == "QT": self.gl = QTGL(env.width, env.height) elif gl == "PIL": @@ -219,17 +222,19 @@ class RenderTool(object): if static: color = self.gl.adaptColor(color, lighten=True) + color = color + # print("Agent:", rcPos, iDir, rcDir, xyDir, xyPos) - self.gl.scatter(*xyPos, color=color, marker="o", s=100) # agent location + self.gl.scatter(*xyPos, color=color, layer=1, marker="o", s=100) # agent location xyDirLine = array([xyPos, xyPos + xyDir / 2]).T # line for agent orient. - self.gl.plot(*xyDirLine, color=color, lw=5, ms=0, alpha=0.6) + self.gl.plot(*xyDirLine, color=color, layer=1, lw=5, ms=0, alpha=0.6) if selected: self._draw_square(xyPos, 1, color) if target is not None: rcTarget = array(target) xyTarget = np.matmul(rcTarget, rt.grc2xy) + rt.xyHalf - self._draw_square(xyTarget, 1 / 3, color) + self._draw_square(xyTarget, 1 / 3, color, layer=1) def plotTrans(self, rcPos, gTransRCAg, color="r", depth=None): """ @@ -397,6 +402,13 @@ class RenderTool(object): visit = visit.prev xyPrev = xy + def drawTrans(self, oFrom, oTo, sColor="gray"): + self.gl.plot( + [oFrom[0], oTo[0]], # x + [oFrom[1], oTo[1]], # y + color=sColor + ) + def drawTrans2( self, xyLine, xyCentre, @@ -489,47 +501,14 @@ class RenderTool(object): for visited_cell in observation_dict[agent]: cell_coord = array(visited_cell[:2]) cell_coord_trans = np.matmul(cell_coord, rt.grc2xy) + rt.xyHalf - self._draw_square(cell_coord_trans, 1 / 3, color) - - def renderEnv( - self, show=False, curves=True, spacing=False, - arrows=False, agents=True, obsrender=True, sRailColor="gray", frames=False, iEpisode=None, iStep=None, - iSelectedAgent=None, action_dict=None): - """ - Draw the environment using matplotlib. - Draw into the figure if provided. - - Call pyplot.show() if show==True. - (Use show=False from a Jupyter notebook with %matplotlib inline) - """ - - if not self.gl.is_raster(): - self.renderEnv2(show, curves, spacing, - arrows, agents, sRailColor, - frames, iEpisode, iStep, - iSelectedAgent, action_dict) - return - - # cell_size is a bit pointless with matplotlib - it does not relate to pixels, - # so for now I've changed it to 1 (from 10) - cell_size = 1 - self.gl.beginFrame() + self._draw_square(cell_coord_trans, 1 / (agent+1.1), color, layer=1, opacity=100) - # self.gl.clf() - # if oFigure is None: - # oFigure = self.gl.figure() - def drawTrans(oFrom, oTo, sColor="gray"): - self.gl.plot( - [oFrom[0], oTo[0]], # x - [oFrom[1], oTo[1]], # y - color=sColor - ) + def renderRail(self, spacing=False, sRailColor="gray", curves=True, arrows=False): + cell_size = 1 # TODO: remove cell_size env = self.env - # t1 = time.time() - # Draw cells grid grid_color = [0.95, 0.95, 0.95] for r in range(env.height + 1): @@ -613,7 +592,7 @@ class RenderTool(object): rotation, spacing=spacing, bArrow=arrows, sColor=sRailColor) else: - drawTrans(from_xy, to_xy, sRailColor) + self.drawTrans(self, from_xy, to_xy, sRailColor) if False: print( @@ -626,6 +605,54 @@ class RenderTool(object): "rot:", rotation, ) + + + def renderEnv( + self, show=False, curves=True, spacing=False, + arrows=False, agents=True, obsrender=True, sRailColor="gray", frames=False, + iEpisode=None, iStep=None, + iSelectedAgent=None, action_dict=None): + """ + Draw the environment using matplotlib. + Draw into the figure if provided. + + Call pyplot.show() if show==True. + (Use show=False from a Jupyter notebook with %matplotlib inline) + """ + + if not self.gl.is_raster(): + self.renderEnv2(show, curves, spacing, + arrows, agents, sRailColor, + frames, iEpisode, iStep, + iSelectedAgent, action_dict) + return + + # cell_size is a bit pointless with matplotlib - it does not relate to pixels, + # so for now I've changed it to 1 (from 10) + cell_size = 1 + + if type(self.gl) in (QTGL, PILGL): + self.gl.beginFrame() + + if type(self.gl) is MPLGL: + #self.gl.clf() + # plt.clf() + self.gl.beginFrame() + pass + + # self.gl.clf() + # if oFigure is None: + # oFigure = self.gl.figure() + + + + env = self.env + + # t1 = time.time() + + + self.renderRail() + # Draw each agent + its orientation + its target if agents: self.plotAgents(targets=True, iSelectedAgent=iSelectedAgent) @@ -657,23 +684,26 @@ class RenderTool(object): # TODO: for MPL, we don't want to call clf (called by endframe) # for QT, we need to call endFrame() # if not show: - self.gl.endFrame() + if type(self.gl) is QTGL: + self.gl.endFrame() + if show: + self.gl.show(block=False) - # t2 = time.time() - # print(t2 - t1, "seconds") + if type(self.gl) is MPLGL: + if show: + self.gl.show(block=False) + #self.gl.endFrame() - if show: - self.gl.show(block=False) - self.gl.pause(0.00001) + self.gl.pause(0.00001) return - def _draw_square(self, center, size, color): + def _draw_square(self, center, size, color, opacity=255, layer=0): x0 = center[0] - size / 2 x1 = center[0] + size / 2 y0 = center[1] - size / 2 y1 = center[1] + size / 2 - self.gl.plot([x0, x1, x1, x0, x0], [y0, y0, y1, y1, y0], color=color) + self.gl.plot([x0, x1, x1, x0, x0], [y0, y0, y1, y1, y0], color=color, layer=layer, opacity=opacity) def getImage(self): return self.gl.getImage() diff --git a/images/basic-env.npz b/images/basic-env.npz index 356da5d70146b3b8081dd99c0fe5e6bd70646e53..8ffaf023e1116b0c92702212ddb04c71b82f0655 100644 GIT binary patch literal 10007 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 literal 36398 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 diff --git a/tests/test_player.py b/tests/test_player.py index 82f6f67..7b2745f 100644 --- a/tests/test_player.py +++ b/tests/test_player.py @@ -1,7 +1,8 @@ -from examples.play_model import main +# from examples.play_model import main +from examples.tkplay import tkmain def test_main(): - main(n_trials=2) + tkmain(n_trials=2) diff --git a/tests/test_rendertools.py b/tests/test_rendertools.py index 3259ed3..7d3ddf6 100644 --- a/tests/test_rendertools.py +++ b/tests/test_rendertools.py @@ -46,8 +46,8 @@ def test_render_env(save_new_images=False): ) sfTestEnv = "env-data/tests/test1.npy" oEnv.rail.load_transition_map(sfTestEnv) - oRT = rt.RenderTool(oEnv) - oRT.renderEnv() + oRT = rt.RenderTool(oEnv, gl="PIL", show=False) + oRT.renderEnv(show=False) checkFrozenImage(oRT, "basic-env.npz", resave=save_new_images) -- GitLab