commit d37e43fe9fd4de97dbbe3164bb52d209bb210ab4
parent b3fae888664cc0e16207fce99a9db032c92454d3
Author: Anders Damsgaard <anders.damsgaard@geo.au.dk>
Date: Fri, 14 Feb 2014 20:14:07 +0100
Begun implementing GUI
Diffstat:
3 files changed, 115 insertions(+), 110 deletions(-)
diff --git a/README.rst b/README.rst
@@ -1,64 +0,0 @@
-cross-stitch
-============
-
-A Python application to turn your images into patterns for cross stitching.
-
-https://github.com/anders-dc/cross-stitch
-
-Requirements
-------------
-Python 2 or 3, Numpy, Scipy, and Matplotlib.
-
-To install these dependencies in Debian and its derivatives, run:
-
- $ sudo apt-get install python python-numpy python-scipy python-matplotlib
-
-License
--------
-GNU Public License version 3 or newer. See LICENSE.txt for details.
-
-Author
-------
-Anders Damsgaard (andersd@riseup.net)
-
-Todo
-----
-Add color processing functions to enhance colors and limit the number of colors.
-Show product names of needed yarn colors.
-
-Usage
------
-
- usage: cross-stitch.py [-h] --infile file --outfile file [--width WIDTH]
- [--ncolors NCOLORS]
-
-Downsamples and modifies an image in order to create a pattern for cross
-stitching.
-
-optional arguments:
- -h, --help show this help message and exit
- --infile file, -i file
- input image to process
- --outfile file, -o file
- save processed image as file
- --width WIDTH, -w WIDTH
- canvas width, default value = 20
- --ncolors NCOLORS, -c NCOLORS
- number of colors in output image, default value = 16
-
-Example
--------
-
- $ ./cross-stitch.py -i fiskeren.jpg -o fisker-pattern.py -w 80 -c 16
-
-.. image:: fiskeren.jpg
- :scale: 50 %
- :alt: Original image
- :align: center
-
-.. image:: fisker-pattern.png
- :scale: 60 %
- :alt: Cross stitching pattern
- :align: center
-
-
diff --git a/cross-stitch.py b/cross-stitch.py
@@ -6,52 +6,121 @@ import scipy.ndimage
import scipy.misc
import scipy.cluster
import numpy as np
+import matplotlib
import matplotlib.pyplot as plt
+import wx
+class CrossStitch:
-## Process input arguments #####################################################
-program_description = \
- '''Downsamples and modifies an image in order to create a pattern for
- cross stitching.'''
-parser = argparse.ArgumentParser(description = program_description)
-parser.add_argument('--infile', '-i', metavar='file', type=str, nargs=1,
- required=True, help='input image to process')
-parser.add_argument('--outfile', '-o', metavar='file', type=str, nargs=1,
- required=True, help='save processed image as file')
-parser.add_argument('--width', '-w', type=int, nargs=1, default=20,
- help='canvas width, default value = 20')
-parser.add_argument('--ncolors', '-c', type=int, nargs=1, default=16,
- help='number of colors in output image, default value = 16')
-args = parser.parse_args()
-infile = args.infile[0]
-outfile = args.outfile[0]
-width = args.width[0]
-ncolors = args.ncolors
-
-## Read image ##################################################################
-try:
- im = scipy.ndimage.imread(infile)
-except IOError:
- sys.stderr.write('could not open input file "' + infile + '"\n')
- sys.exit(1)
-
-## Downsampling ################################################################
-hw_ratio = float(im.shape[0])/im.shape[1]
-new_size = (int(round(hw_ratio*width)), width)
-im_small = scipy.misc.imresize(im, new_size)
-
-## Process image colors ########################################################
-ar = im_small.reshape(scipy.product(im_small.shape[:2]), im_small.shape[2])
-colors, dist = scipy.cluster.vq.kmeans(ar, ncolors)
-c = ar.copy()
-vecs, dist = scipy.cluster.vq.vq(ar, colors)
-for i, color in enumerate(colors):
- c[scipy.r_[scipy.where(vecs==i)],:] = color
-im_small_reduced = c.reshape(new_size[0], new_size[1], 3)
-
-## Generate output plot ########################################################
-fig = plt.figure()
-imgplot = plt.imshow(im_small_reduced)
-imgplot.set_interpolation('nearest')
-plt.grid()
-plt.savefig(outfile)
+ def __init__(self):
+ pass
+
+ def read_image(self, infile):
+ try:
+ self.img = scipy.ndimage.imread(infile)
+ except IOError:
+ sys.stderr.write('could not open input file "' + infile + '"\n')
+
+ def down_sample(self, width):
+ hw_ratio = float(self.img.shape[0])/self.img.shape[1]
+ size = (int(round(hw_ratio*width)), width)
+ self.img = scipy.misc.imresize(self.img, size)
+ self.orig_img = self.img.copy()
+
+ def limit_colors(self, ncolors):
+ ar = self.img.reshape(scipy.product(self.img.shape[:2]),\
+ self.img.shape[2])
+ self.colors, dist = scipy.cluster.vq.kmeans(ar, ncolors)
+ tmp = ar.copy()
+ vecs, dist = scipy.cluster.vq.vq(ar, self.colors)
+ for i, color in enumerate(self.colors):
+ tmp[scipy.r_[scipy.where(vecs == i)],:] = color
+ self.img = tmp.reshape(self.img.shape[0], self.img.shape[1], 3)
+
+ def save_image(self, filename):
+ fig = plt.figure()
+ imgplot = plt.imshow(self.img)
+ imgplot.set_interpolation('nearest')
+ plt.grid()
+ plt.savefig(filename)
+
+
+class MainScreen(wx.Frame):
+
+ def __init__(self, *args, **kwargs):
+ super(MainScreen, self).__init__(*args, **kwargs)
+ self.InitUI()
+ self.cs = CrossStitch()
+
+ def InitUI(self):
+
+ self.InitMenu()
+ #self.InitToolbar()
+
+ self.SetSize((600, 400))
+ self.SetTitle('Main menu')
+ self.Centre()
+ self.Show(True)
+
+ def InitMenu(self):
+
+ menubar = wx.MenuBar()
+
+ fileMenu = wx.Menu()
+ fitem = fileMenu.Append(wx.ID_OPEN, 'Open', 'Open image')
+ self.Bind(wx.EVT_MENU, self.OnOpen, fitem)
+ fitem = fileMenu.Append(wx.ID_SAVE, 'Save', 'Save image')
+ self.Bind(wx.EVT_MENU, self.OnSave, fitem)
+ fileMenu.AppendSeparator()
+ fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quit application')
+ self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
+ menubar.Append(fileMenu, '&File')
+
+ processingMenu = wx.Menu()
+ fitem = processingMenu.Append(wx.ID_ANY, 'Down sample',
+ 'Down sample image')
+ self.Bind(wx.EVT_MENU, self.OnDownSample, fitem)
+ fitem = processingMenu.Append(wx.ID_ANY, 'Reduce number of colors',
+ 'Reduce number of colors in image')
+ self.Bind(wx.EVT_MENU, self.OnLimitColors, fitem)
+
+ menubar.Append(processingMenu, '&Image processing')
+
+
+ self.SetMenuBar(menubar)
+
+ def InitToolbar(self):
+
+ toolbar = self.CreateToolBar()
+ qtool = toolbar.AddLabelTool(wx.ID_EXIT, 'Quit', wx.Bitmap('textit.png'))
+ self.Bind(wx.EVT_TOOL, self.OnQuit, qtool)
+
+ toolbar.Realize()
+
+
+
+ def OnQuit(self, e):
+ self.Close()
+
+ def OnOpen(self, e):
+ self.cs.read_image("fiskeren.jpg")
+
+ def OnSave(self, e):
+ self.cs.save_image("fisker-pattern.png")
+
+ def OnDownSample(self, e):
+ self.cs.down_sample(80)
+
+ def OnLimitColors(self, e):
+ self.cs.limit_colors(16)
+
+
+
+
+def main():
+ app = wx.App()
+ MainScreen(None, title='Cross Stitch')
+ app.MainLoop()
+
+if __name__ == '__main__':
+ main()
diff --git a/fisker-pattern.png b/fisker-pattern.png
Binary files differ.