timgtrans.py - imgtrans - interactive BMP to txt converter
HTML git clone git://src.adamsgaard.dk/imgtrans
DIR Log
DIR Files
DIR Refs
DIR LICENSE
---
timgtrans.py (8881B)
---
1 #!/usr/bin/env python
2
3 import sys, os
4 import argparse
5 import scipy.ndimage
6 import scipy.misc
7 import scipy.cluster
8 import numpy
9 import matplotlib
10 matplotlib.use('WXAgg')
11 import matplotlib.figure
12 import matplotlib.backends
13 import matplotlib.backends.backend_wxagg
14 import matplotlib.pyplot
15 import wx
16
17
18 class ImgTrans:
19
20 def __init__(self):
21 self.img = numpy.zeros(3)
22
23 def read_image(self, infile):
24 try:
25 self.img = scipy.ndimage.imread(infile)
26 except IOError:
27 sys.stderr.write('could not open input file "' + infile + '"\n')
28
29 self.orig_img = self.img.copy()
30
31 def down_sample(self, width):
32 hw_ratio = float(self.orig_img.shape[0])/self.orig_img.shape[1]
33 size = (int(round(hw_ratio*width)), width)
34 self.img = scipy.misc.imresize(self.orig_img, size)
35
36 def limit_colors(self, ncolors):
37 ar = self.img.reshape(scipy.product(self.img.shape[:2]),\
38 self.img.shape[2])
39 self.colors, dist = scipy.cluster.vq.kmeans(ar, ncolors)
40 tmp = ar.copy()
41 vecs, dist = scipy.cluster.vq.vq(ar, self.colors)
42 for i, color in enumerate(self.colors):
43 tmp[scipy.r_[scipy.where(vecs == i)],:] = color
44 self.img = tmp.reshape(self.img.shape[0], self.img.shape[1], 3)
45
46 def convert_256_colors(self):
47 palette = Palette('256colors')
48 tmp = self.img.reshape(scipy.product(self.img.shape[:2]),\
49 self.img.shape[2])
50 for i in range(tmp.size/3):
51 tmp[i] = palette.nearest256color(tmp[i])
52 self.img = tmp.reshape(self.img.shape[0], self.img.shape[1], 3)
53
54 def save_image(self, filename, grid=True):
55 fig = matplotlib.pyplot.figure()
56 imgplot = matplotlib.pyplot.imshow(self.img, interpolation='nearest')
57 matplotlib.pyplot.grid(grid)
58 matplotlib.pyplot.savefig(filename)
59
60 def save_txt_file(self, filename):
61 #import pdb; pdb.set_trace()
62 out = self.img/numpy.max(self.img)
63 if self.img.ndim > 2:
64 out = out[:,:,0]
65 numpy.savetxt(filename,
66 out,
67 header='{:d} {:d}'.format(self.img.shape[0], self.img.shape[1]),
68 comments='',
69 fmt='%1.0f')
70
71 def image(self):
72 return self.img
73
74
75 class MainScreen(wx.Frame):
76
77 def __init__(self, *args, **kwargs):
78 super(MainScreen, self).__init__(*args, **kwargs)
79 self.cs = ImgTrans()
80 self.InitUI()
81 self.contentNotSaved = False
82 self.grid = True
83
84 def InitUI(self):
85
86 self.InitMenu()
87 #self.InitToolbar()
88 self.InitPreview()
89
90 self.SetSize((600, 600))
91 self.SetTitle('ImgTrans')
92 self.Centre()
93 self.Show(True)
94
95 def InitMenu(self):
96
97 menubar = wx.MenuBar()
98
99 fileMenu = wx.Menu()
100 fitem = fileMenu.Append(wx.ID_OPEN, 'Open image', 'Open image')
101 self.Bind(wx.EVT_MENU, self.OnOpen, fitem)
102 fitem = fileMenu.Append(wx.ID_SAVE, 'Save text file', 'Save text file')
103 self.Bind(wx.EVT_MENU, self.OnSave, fitem)
104 fileMenu.AppendSeparator()
105 fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')
106 self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
107 menubar.Append(fileMenu, '&File')
108
109 helpMenu = wx.Menu()
110 fitem = helpMenu.Append(wx.ID_ABOUT, 'About', 'About')
111 self.Bind(wx.EVT_MENU, self.OnAbout, fitem)
112 menubar.Append(helpMenu, '&Help')
113
114 self.SetMenuBar(menubar)
115
116 def InitToolbar(self):
117
118 toolbar = self.CreateToolBar()
119 qtool = toolbar.AddLabelTool(wx.ID_EXIT, 'Quit',
120 wx.Bitmap('textit.png'))
121 self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)
122
123 toolbar.Realize()
124
125 def InitPreview(self):
126 self.figure = matplotlib.figure.Figure()
127 self.axes = self.figure.add_subplot(111)
128 self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg(self,
129 -1, self.figure)
130 self.sizer = wx.BoxSizer(wx.VERTICAL)
131 self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW)
132 self.SetSizer(self.sizer)
133 self.Fit()
134
135 def DrawPreview(self):
136 self.axes.grid(self.grid)
137 imgplot = self.axes.imshow(self.cs.image(), interpolation='nearest')
138 imgplot.set_cmap('gray_r')
139 self.canvas.draw()
140
141 def OnQuit(self, event):
142 if self.contentNotSaved:
143 if wx.MessageBox('Current image is not saved! Proceed?',
144 'Please confirm', wx.ICON_QUESTION | wx.YES_NO, self) == \
145 wx.NO:
146 return
147 self.Close()
148
149 def OnOpen(self, event):
150 if self.contentNotSaved:
151 if wx.MessageBox('Current image is not saved! Proceed?',
152 'Please confirm', wx.ICON_QUESTION | wx.YES_NO, self) == \
153 wx.NO:
154 return
155
156 self.dirname = ''
157 openFileDialog = wx.FileDialog(self, 'Open image file', self.dirname,
158 '', 'Image files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)|'
159 + '*.jpg;*.jpeg;*.png;*.gif;*.bmp',
160 wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
161
162 if openFileDialog.ShowModal() == wx.ID_OK:
163 self.filename = openFileDialog.GetFilename()
164 self.dirname = openFileDialog.GetDirectory()
165 self.cs.read_image(openFileDialog.GetPath())
166 self.SetTitle('ImgTrans: ' + openFileDialog.GetPath())
167 self.DrawPreview()
168 openFileDialog.Destroy()
169
170 def OnSave(self, event):
171 #saveFileDialog = wx.FileDialog(self, 'Save image file', self.dirname,
172 # '', 'PNG files (*.png)|*.png|'
173 # + 'JPEG files (*.jpg,*.jpeg)|*.jpg*.jpeg|'
174 # + 'GIF files (*.gif)|*.gif|'
175 # + 'BMP files (*.bmp)|*.bmp',
176 # wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
177 saveFileDialog = wx.FileDialog(self, 'Save text file', self.dirname,
178 '', 'TXT files (*.txt)|*.txt',
179 wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
180 basename = os.path.splitext(self.filename)[0]
181 saveFileDialog.SetFilename(basename + '.txt')
182
183 if saveFileDialog.ShowModal() == wx.ID_CANCEL:
184 return
185
186 #self.cs.save_image(saveFileDialog.GetPath(), grid=self.grid)
187 self.cs.save_txt_file(saveFileDialog.GetPath())
188 self.contentNotSaved = False
189
190 def OnDownSample(self, event):
191 dlg = wx.TextEntryDialog(None, 'Enter new width', defaultValue='50')
192 ret = dlg.ShowModal()
193 if ret == wx.ID_OK:
194 width = int(dlg.GetValue())
195 self.cs.down_sample(int(width))
196 self.contentNotSaved = True
197 self.DrawPreview()
198
199 def OnLimitColors(self, event):
200 dlg = wx.TextEntryDialog(None, 'Enter the number of colors to include',
201 defaultValue='16')
202 ret = dlg.ShowModal()
203 if ret == wx.ID_OK:
204 self.cs.limit_colors(int(dlg.GetValue()))
205 self.contentNotSaved = True
206 self.DrawPreview()
207
208 def On256Colors(self, event):
209 self.cs.convert_256_colors()
210 self.contentNotSaved = True
211 self.DrawPreview()
212
213 def ToggleGrid(self, event):
214 if self.gridtoggle.IsChecked():
215 self.grid = True
216 self.DrawPreview()
217 else:
218 self.grid = False
219 self.DrawPreview()
220
221 def OnAbout(self, event):
222
223 description = '''ImgTrans is a image converter.'''
224
225 license = '''ImgTrans is free software; you can redistribute it
226 and/or modify it under the terms of the GNU General Public License as published
227 by the Free Software Foundation; either version 3 of the License, or (at your
228 option) any later version.
229
230 ImgTrans is distributed in the hope that it will be useful, but WITHOUT ANY
231 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
232 PARTICULAR PURPOSE.
233 See the GNU General Public License for more details. You should have recieved a
234 copy of the GNU General Public License along with ImgTrans; if not, write to
235 the Free Software Foundation, Inc., 59 Temple Palace, Suite 330, Boston, MA
236 02111-1307 USA'''
237
238 info = wx.AboutDialogInfo()
239
240 info.SetIcon(wx.Icon('icon.png', wx.BITMAP_TYPE_PNG))
241 info.SetName('ImgTrans')
242 info.SetVersion('1.0')
243 info.SetDescription(description)
244 info.SetCopyright('(C) 2015 Anders Damsgaard')
245 info.SetWebSite('https://cs.au.dk/~adc')
246 info.SetLicense(license)
247 info.AddDeveloper('Anders Damsgaard')
248 info.AddDocWriter('Anders Damsgaard')
249 info.AddArtist('Anders Damsgaard')
250
251 wx.AboutBox(info)
252
253
254
255 def main():
256 app = wx.App()
257 MainScreen(None, title='ImgTrans')
258 app.MainLoop()
259
260 if __name__ == '__main__':
261 main()