Skip to content

Instantly share code, notes, and snippets.

@beantowel
Created September 15, 2018 12:08
Show Gist options
  • Save beantowel/b92204c266e0d3090a4db822629ba6fb to your computer and use it in GitHub Desktop.
Save beantowel/b92204c266e0d3090a4db822629ba6fb to your computer and use it in GitHub Desktop.
generate .stl format mesh from fragmented text
from PIL import Image, ImageFont, ImageDraw
from stl import mesh
from mpl_toolkits import mplot3d
from matplotlib import pyplot as plt
from cv2 import cv2
import itertools as its
import numpy as np
import random
import sys
def createImage(width, height, size, text, fontname = 'Ubuntu-B.ttf'):
# mode = 'L' -- 8-bit pixels, black and white
image = Image.new('L', (width, height))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype(fontname, size)
draw.text((0, 0), text, font=font, fill=0xff)
# image.show()
return image
def showMesh(filename):
# Create a new plot
figure = plt.figure()
# text = 'Laura10X'
# facetCnt = 1000
axes = mplot3d.Axes3D(figure)
# Load the STL files and add the vectors to the plot
your_mesh = mesh.Mesh.from_file(filename)
axes.add_collection3d(mplot3d.art3d.Poly3DCollection(your_mesh.vectors))
# Auto scale to the mesh size
scale = your_mesh.points.flatten(-1)
axes.auto_scale_xyz(scale, scale, scale)
# Show the plot to the screen
plt.show()
class facetGen:
def __init__(self, image, edges, depth):
self.image = image
self.edges = edges
self.depth = depth
self.nonZeros = [] # nonZero pixels' coordinate:np.array
height = edges.shape[0]
width = edges.shape[1] # shape->(height, width)
for j, i in its.product(range(width), range(height)):
if edges[i, j] != 0:
self.nonZeros.append(np.array((i, j)))
self.len = len(self.nonZeros)
print('nonZeros:', self.len, 'shape:', image.shape)
def checkVertices(self, vertices, checkCnt):
def weightedMeanVertex(vertices, weights):
x = np.array((0.0, 0.0))
for v, w in zip(vertices, weights):
x += w * v
meanVertex = x // np.sum(weights)
return meanVertex.astype('int64')
def randomCheckPoint():
weights = tuple(random.random() for i in range(3))
return weightedMeanVertex(vertices, weights)
checkPoints = (randomCheckPoint() for i in range(checkCnt))
if all(self.image[tuple(p)] for p in checkPoints):
return True
else:
return False
def randomVertices(self):
# i = random.randrange(self.len)
# j = random.randrange(max(1, i - 300))
# k = random.randrange(i, min(i + 300, self.len))
i, j, k = (random.randrange(self.len) for x in range(3))
vertices = tuple(self.nonZeros[x] for x in (i, j, k))
return vertices
def generateVertices(self, checkCnt):
vertices = self.randomVertices()
while not self.checkVertices(vertices, checkCnt):
vertices = self.randomVertices()
z1 = random.randrange(self.depth)
z2 = random.randrange(max(0, z1 - 50), min(self.depth, z1 + 50))
z3 = random.randrange(max(0, z1 - 50), min(self.depth, z1 + 50))
vertices3D = list(
np.append(v, z) for v, z in zip(vertices, [z1, z2, z3]))
print('vertices generated')
return vertices3D
print('arguments(name, text, cnt):', sys.argv)
name, text, facetCnt = sys.argv[1:]
facetCnt = int(facetCnt)
stlname = name + '.stl'
filename = name + '.png'
size = 300
random.seed(10)
checkCnt = 30
width = int(len(text) * size)
height = 2 * size
textImage = createImage(width, height, size, text, 'NotoSansCJK-Bold.ttc')
textImage.save(filename)
image = cv2.imread(filename, flags=cv2.IMREAD_GRAYSCALE)
edges = cv2.Canny(image, 10, 50)
gen = facetGen(image, edges, size)
fragMesh = mesh.Mesh(np.zeros(facetCnt, dtype=mesh.Mesh.dtype))
for i in range(facetCnt):
print(i, end = ' ')
fragMesh.vectors[i] = gen.generateVertices(checkCnt)
print('gen done')
fragMesh.save(stlname)
showMesh(stlname)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment