tBegun implementing GUI - cross-stitch - interactively turn images into pattern… | |
git clone git://src.adamsgaard.dk/cross-stitch | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit d37e43fe9fd4de97dbbe3164bb52d209bb210ab4 | |
parent b3fae888664cc0e16207fce99a9db032c92454d3 | |
Author: Anders Damsgaard <[email protected]> | |
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(-) | |
--- | |
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 ([email protected]) | |
- | |
-Todo | |
----- | |
-Add color processing functions to enhance colors and limit the number of color… | |
-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 | |
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() | |
diff --git a/fisker-pattern.png b/fisker-pattern.png | |
Binary files differ. |