Skip to content
Advertisement

Automated cross stich pattern

I’m trying to create a cross stitch pattern with python as shown in the attached image.

So far I simply have the pixilated image. I could import it in excel and manually add the grid and colors etc. But how can I ‘easily’ automate this in python? Can I use any of the normal figure plotting functions (pyplot), or should I look into tkinter?

I’m fairly ok making scripts in python for engineering purposes, but completely new to GUI-stuff.

Ideally my output would be a vectored pdf

Cross stitch pattern

from scipy import misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as plticker

arr = misc.imread('Fox_drawing_pixelized.png', mode= 'RGBA') # 640x480x3 array

fig = plt.figure()
imgplot = plt.imshow(arr) # RGBA
ax = plt.gca()
ax.grid(True)
ax.grid(b=True, which='major', color='b', linestyle='-')
plt.minorticks_on()
loc = plticker.MultipleLocator(base=1)
ax.xaxis.set_minor_locator(loc)
ax.yaxis.set_minor_locator(loc)
ax.grid(b=True, which='minor', color='k', linestyle='-',linewidth=.3)
fig.savefig("foo.pdf", bbox_inches='tight')
  • How do I set the gridlines at 0.5 rather than on the units (in the middle through each pixel)?

  • How do I plot text throught each pixel, I already have the image in an array with numbers how to plot this on top?

Advertisement

Answer

  • To shift the gridlines, you can simply change the ticks position:
    ax.set_xticks(np.arange(-0.5, arr.shape[1], 5))
    will put one major tick each 5 pixels starting from the border of the first pixel.
    ax.set_xticks(np.arange(-0.5, arr.shape[1], 1), minor=True)
    does the same thing but every pixel for minor ticks. And then do the same for y but with arr.shape[0].

  • To add text, you can simply use ax.text(x, y, 'text'). I used a dictionary to match the colors (in hex format because rgb lists cannot be dictionary keys) to the texts. What you need to pay attention to is that (i, j) matrix indexes correspond to (y, x) coordinates.

Here is the full code:

from scipy import misc
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as plticker
from matplotlib.colors import to_hex

arr = misc.imread('image.png', mode= 'RGB') # array
# adapt figure size to the image size.
fig = plt.figure(figsize=(0.2*arr.shape[1], 0.2*arr.shape[0]))
imgplot = plt.imshow(arr) # RGB
ax = plt.gca()
ax.grid(True)
ax.grid(b=True, which='major', color='b', linestyle='-')
plt.minorticks_on()
ax.grid(b=True, which='minor', color='k', linestyle='-',linewidth=.3)

# put a major gridline every 5 pixels
ax.set_xticks(np.arange(-0.5, arr.shape[1], 5))
ax.set_yticks(np.arange(-0.5, arr.shape[0], 5))
# set ticks label
ax.set_xticklabels(np.arange(0, arr.shape[1], 5))
ax.set_yticklabels(np.arange(0, arr.shape[0], 5))
# put a minor gridline every pixel
ax.set_xticks(np.arange(-0.5, arr.shape[1], 1), minor=True)
ax.set_yticks(np.arange(-0.5, arr.shape[0], 1), minor=True)
fig.tight_layout(pad=0)  # reduce space around image

# display text
colors_to_text = {'#000000': 'B', '#ffffff': 'W', '#f58a35': 'O', '#bcbbbb': 'G'}

for i in range(arr.shape[0]):
    for j in range(arr.shape[1]):
        # get the text corresponding to the pixel color
        txt = colors_to_text.get(to_hex(arr[i,j]/255), '')
        # display text (x, y are inverted compared to the i, j indexes of the matrix)
        ax.text(j, i, txt, color='#888888', horizontalalignment='center', 
                verticalalignment='center', fontsize=7)

fig.savefig("foo.pdf", bbox_inches='tight')

The image pixelated image gave me this result: result

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement