Completed
Branch master (5cc02c)
by Andrei
01:30
created

pyclustering.nnet.examples.digit_application   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 107
Duplicated Lines 0 %
Metric Value
dl 0
loc 107
rs 10
wmc 24
1
"""!
2
3
@brief Example of application for digit recognition based on self-organized feature map.
4
       Digits for 0 to 9 can be recognized. The application has GUI that provides following 
5
       function: learning, drawing, recognition, dump saving/loading. 
6
7
@authors Andrei Novikov ([email protected])
8
@date 2014-2016
9
@copyright GNU Public License
10
11
@cond GNU_PUBLIC_LICENSE
12
    PyClustering is free software: you can redistribute it and/or modify
13
    it under the terms of the GNU General Public License as published by
14
    the Free Software Foundation, either version 3 of the License, or
15
    (at your option) any later version.
16
    
17
    PyClustering is distributed in the hope that it will be useful,
18
    but WITHOUT ANY WARRANTY; without even the implied warranty of
19
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
    GNU General Public License for more details.
21
    
22
    You should have received a copy of the GNU General Public License
23
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24
@endcond
25
26
"""
27
28
from pyclustering.nnet.som import som, type_conn, type_init;
29
30
from pyclustering.samples.definitions import IMAGE_DIGIT_SAMPLES;
31
32
from pyclustering.utils import read_image, rgb2gray;
33
34
35
from tkinter import *;
36
from tkinter import messagebox;
37
38
import math;
39
import pickle;
40
import os;
41
import random;
42
43
class recognizer:
44
    __network = None;
45
    
46
    def __init__(self):
47
        self.__decode_map = [];
48
    
49
        for index_digit in range(0, 10, 1):
50
            list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit);
51
            
52
            for file_name in list_file_digit_sample:
53
                self.__decode_map.append(index_digit);
54
    
55
    
56
    def train(self):
57
        samples = [];
58
        
59
        print("Digit images preprocessing...");
60
        
61
        for index_digit in range(0, 10, 1):
62
            list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit);
63
            
64
            for file_name in list_file_digit_sample:
65
                data = read_image(file_name);
66
                
67
                image_pattern = rgb2gray(data);
68
                
69
                for index_pixel in range(len(image_pattern)):
70
                    if (image_pattern[index_pixel] < 128):
71
                        image_pattern[index_pixel] = 1;
72
                    else:
73
                        image_pattern[index_pixel] = 0;
74
                
75
                samples += [ image_pattern ];
76
        
77
       
78
        print("SOM initialization...");
79
        self.__network = som(2, 5, type_conn.grid_four, None, True);
80
        
81
        print("SOM training...");
82
        self.__network.train(samples, 300);
83
        
84
        print("SOM is ready...");
85
        
86
    def recognize(self, input_pattern):
87
        index_neuron = self.__network.simulate(input_pattern);
88
            
89
        decoded_capture_objects = [];
90
            
91
        for index_capture_object in self.__network.capture_objects[index_neuron]:
92
            # print("\t%s" % decode_map[index_capture_object]);
93
            decoded_capture_objects.append(self.__decode_map[index_capture_object]);
94
            
95
        frequent_index = max(set(decoded_capture_objects), key = decoded_capture_objects.count);
96
        print(decoded_capture_objects);
97
        return frequent_index;
98
        
99
    def save_knowledge(self):
100
        result_saving = False;
101
        
102
        if (self.__network is not None):
103
            file_network_dump = open("knowledge_recognition_memory_dump", "wb");
104
            pickle.dump(self.__network, file_network_dump);
105
            result_saving = True;
106
            
107
        return result_saving;
108
    
109
    def load_knowledge(self):
110
        result_loading = False;
111
        
112
        if (os.path.isfile("knowledge_recognition_memory_dump") is True):
113
            file_network_dump = open("knowledge_recognition_memory_dump", "rb");
114
            self.__network = pickle.load(file_network_dump);
115
            
116
            result_loading = True;
117
        
118
        return result_loading;
119
120
121
class digit_application:
122
    __color = "#000000";
123
    
124
    __widget = None;
125
    
126
    __user_pattern = None;
127
    __recognizer = None;
128
    
129
    __master = None;
130
    
131
    def __init__(self):
132
        self.__master = Tk();
133
        self.__master.title("Recognition");
134
        
135
        self.__widget = Canvas(self.__master, width = 320, height = 320);
136
        self.__widget.pack(expand = YES, fill = BOTH);
137
        self.__widget.bind("<B1-Motion>", self.__paint);
138
        
139
        button_recognize = Button(self.__master, text = "Recognize", command = self.click_recognize, width = 25);
140
        button_recognize.pack(side = BOTTOM);
141
        
142
        button_recognize = Button(self.__master, text = "Random Image", command = self.click_image_load, width = 25);
143
        button_recognize.pack(side = BOTTOM);
144
        
145
#         button_save = Button(self.__master, text = "Save", command = self.click_save, width = 25);
146
#         button_save.pack(side = BOTTOM);
147
#         
148
#         button_load = Button(self.__master, text = "Load", command = self.click_load, width = 25);
149
#         button_load.pack(side = BOTTOM);
150
        
151
        button_train = Button(self.__master, text = "Train", command = self.click_train, width = 25);
152
        button_train.pack(side = BOTTOM);
153
        
154
        button_clean = Button(self.__master, text = "Clean", command = self.click_clean, width = 25);
155
        button_clean.pack(side = BOTTOM);
156
        
157
        self.__user_pattern = [ 0 for i in range(32 * 32) ];
158
        self.__recognizer = recognizer();
159
160
    def __paint(self, event):
161
        # calculate square that is belong this click
162
        if ( (event.x >= 0) and (event.x < 320) and (event.y >= 0) and (event.y < 320) ):
163
            x1, y1 = math.floor(event.x / 10), math.floor(event.y / 10);
164
            
165
            self.__user_pattern[y1 * 32 + x1] = 1;
166
            
167
            index2 = (y1 + 1) * 32 + x1;
168
            index3 = y1 * 32 + (x1 + 1);
169
            index4 = (y1 + 1) * 32 + (x1 + 1);
170
            
171
            
172
            if (index2 < len(self.__user_pattern)): 
173
                self.__user_pattern[index2] = 1;
174
            if (index3 < len(self.__user_pattern)): 
175
                self.__user_pattern[index3] = 1;
176
            if (index4 < len(self.__user_pattern)): 
177
                self.__user_pattern[index4] = 1;
178
            
179
            display_x1, display_y1 = x1 * 10, y1 * 10;
180
            display_x2, display_y2 = display_x1 + 20, display_y1 + 20;
181
            
182
            self.__widget.create_rectangle(display_x1, display_y1, display_x2, display_y2, fill = self.__color, width = 0);
183
184
    def click_train(self):
185
        self.__recognizer.train();
186
187
    def click_load(self):
188
        if (self.__recognizer.load_knowledge() is not True):
189
            messagebox.showwarning("Recognition - Knowledge Loading", "Knowledge represented by self-organized feature map has not been "
190
                                   "load from hardware to recognizer due to lack of saved dump of that object. "
191
                                   "Please save knowledge dump after training and after that it will be possible "
192
                                   "to use load it at any time.");
193
    
194
    def click_save(self):
195
        if (self.__recognizer.save_knowledge() is not True):
196
            messagebox.showwarning("Recognition - Knowledge Saving", "Knowledge represented by self-organized feature map has been created "
197
                                   "because training has been performed. Please train recognizer and after save result of training.");
198
199
    def click_recognize(self):               
200
        digit_index = self.__recognizer.recognize(self.__user_pattern);
201
        messagebox.showinfo("Recognition - Result", "Most probably input digit is " + str(digit_index));
202
203
    def click_clean(self):
204
        self.__user_pattern = [ 0 for i in range(32 * 32) ];
205
        Canvas.delete(self.__widget, "all");
206
        
207
    def click_image_load(self):
208
        self.__user_pattern = [ 0 for i in range(32 * 32) ];
209
        Canvas.delete(self.__widget, "all");
210
        
211
        index_digit = int(math.floor(random.random() * 10));
212
        list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit);
213
        
214
        index_image = int(math.floor( random.random() * len(list_file_digit_sample) ));
215
        file_name = list_file_digit_sample[index_image];
216
        data = read_image(file_name);
217
                
218
        image_pattern = rgb2gray(data);
219
        for y in range(32):
220
            for x in range(32):
221
                linear_index = y * 32 + x;
222
                if (image_pattern[linear_index] < 128):
223
                    self.__user_pattern[linear_index] = 1;
224
                    self.__widget.create_rectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10, fill = self.__color, width = 0);
225
        
226
    def start(self):  
227
        mainloop();
228
229
app = digit_application();
230
app.start();
231
232
# digit_recognition();