tk_canvas.py 5.56 KB
Newer Older
1 2 3 4
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
"""
5 6 7 8
    Provides structured graphics interface from Tkinter package.
    
    Name: tk_canvas.py
    Author: Alessandro dos Santos Ferreira ( santosferreira.alessandro@gmail.com )
9 10 11 12 13 14 15 16 17 18 19
"""

import sys
if sys.version_info[0] < 3:
    import Tkinter as Tk
else:
    import tkinter as Tk
    
import matplotlib
matplotlib.use('TkAgg')

20 21 22 23 24 25
from matplotlib import pylab as plt
import sys
if sys.version_info[0] < 3:
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
else:
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
26 27

class Image(object):
28
    """Class to manipulate structured graphics interface."""
29 30
    
    
31
    def __init__(self, parent):
32 33 34 35 36 37 38
        """Constructor.

        Parameters
        ----------
        parent : Tk widget
            Parent widget of this class.
        """
39 40
        self.parent = parent
        
41 42 43 44 45 46 47 48 49 50 51
        self._im = None
        self._canvas = None
        self._fig = None
        self._ax = None
        self._toolbar = None
        
        self._axes_visible = True
        self._toolbar_visible = True
        
            
    def toggle_axes(self):
52 53
        """Toogle the axes of image.
        """
54 55 56 57 58 59 60 61 62 63
        self._axes_visible = not self._axes_visible

        if self._canvas is not None:
            self._ax.get_xaxis().set_visible(self._axes_visible)
            self._ax.get_yaxis().set_visible(self._axes_visible)
            
            self._fig.tight_layout()
            self._canvas.draw()
            
    def toggle_toolbar(self):
64 65
        """Toogle the matplotlib image toolbar.
        """
66 67
        self._toolbar_visible = not self._toolbar_visible
        
68
        self._show_toolbar() if self._toolbar_visible else self._hide_toolbar()
69 70 71
    
        
    def render(self, image, onclick = None):
72 73 74 75 76 77 78 79 80
        """Render a image in window GUI.

        Parameters
        ----------
        image : opencv 3-channel color image
            OpenCV Image.
        onclick : function, optional, default = None
            Callback to be executed on image click.
        """
81 82
        self.parent.image = image
            
83
        self._fig = plt.figure(facecolor='white', edgecolor='black', linewidth=1)
84
        self._im = plt.imshow(self.parent.image) # later use a.set_data(new_data)
85 86 87 88
        
        self._ax = plt.gca()
        self._ax.get_xaxis().set_visible(self._axes_visible)
        self._ax.get_yaxis().set_visible(self._axes_visible)
89 90

        # a tk.DrawingArea
91 92
        self._fig.tight_layout()
        self._canvas = FigureCanvasTkAgg(self._fig, master=self.parent)
93 94 95 96 97
        if sys.version_info[0] < 3:
            self._canvas.show()
        else:
            self._canvas.draw()

98
        self._canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
99 100
        
        if onclick is not None:
101 102 103 104 105 106
            self._fig.canvas.mpl_connect('button_press_event', func = onclick)
            
        if self._toolbar_visible == True:
            self._show_toolbar()
            
    
107
    def refresh(self, image = None):
108 109 110 111 112 113 114
        """Refresh the image content.

        Parameters
        ----------
        image : opencv 3-channel color image, optional, default = None
            OpenCV Image.
        """
115
        if self._canvas is not None:
116 117
            if image is not None:
                self.parent.image = image
118
            self._im.set_data(self.parent.image)
119
            
120
            self._fig.tight_layout()
121
            self._canvas.draw()
122 123

    def close(self):
124 125
        """Close the image.
        """
126
        if self._canvas is not None:
127
            self.parent.image = None
128 129
            #self._im.set_data(np.zeros((0,0,3), float))
            #self._canvas.draw()
130 131 132 133 134 135
            self._canvas.get_tk_widget().pack_forget()
            self._canvas.get_tk_widget().destroy()

            if self._toolbar is not None:
                self._toolbar.pack_forget()
                self._toolbar.destroy()
136 137 138 139 140 141

            # The command plt.clf() is used to minimize the effects of follow warning:
            # "RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface 
            # (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory."
            # However this part of code need to be refactored to prevent the memory leak!!!
            plt.clf()
142
            
143 144
            self._im = None
            self._canvas = None
145 146 147
            self._fig = None
            self._ax = None
            self._toolbar = None
148 149 150
            
            return True
        return False
151 152 153

        
    def _show_toolbar(self):
154 155
        """Show the matplotlib image toolbar.
        """
156
        if self._toolbar is None and self._canvas is not None:
157 158 159 160
            if sys.version_info[0] < 3:
                self._toolbar = NavigationToolbar2TkAgg(self._canvas, self.parent)
            else:
                self._toolbar = NavigationToolbar2Tk(self._canvas, self.parent)
161 162
            self._toolbar.configure(background='white', borderwidth=0)
            for child in self._toolbar.winfo_children():
163 164 165 166
                if sys.version_info[0] < 3:
                    child.configure(background='white', foreground='black')
                else:
                    child.configure(background='white')
167 168 169 170
            #self._toolbar.update()
            self._toolbar.pack(side=Tk.TOP, fill=Tk.X, expand=False)
            
    def _hide_toolbar(self):
171 172
        """Hide the matplotlib image toolbar.
        """
173 174 175 176
        if self._toolbar is not None:
            self._toolbar.pack_forget()
            self._toolbar.destroy()
            self._toolbar = None