tBegun implementing GUI - cross-stitch - interactively turn images into patterns for cross stitching
 (HTM) git clone git://src.adamsgaard.dk/cross-stitch
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit d37e43fe9fd4de97dbbe3164bb52d209bb210ab4
 (DIR) parent b3fae888664cc0e16207fce99a9db032c92454d3
 (HTM) Author: Anders Damsgaard <anders.damsgaard@geo.au.dk>
       Date:   Fri, 14 Feb 2014 20:14:07 +0100
       
       Begun implementing GUI
       
       Diffstat:
         D README.rst                          |      64 -------------------------------
         M cross-stitch.py                     |     161 ++++++++++++++++++++++---------
         M fisker-pattern.png                  |       0 
       
       3 files changed, 115 insertions(+), 110 deletions(-)
       ---
 (DIR) diff --git a/README.rst b/README.rst
       t@@ -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
       -
       -
 (DIR) diff --git a/cross-stitch.py b/cross-stitch.py
       t@@ -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()
 (DIR) diff --git a/fisker-pattern.png b/fisker-pattern.png
       Binary files differ.