2値画像から3Dプリンターでスタンプを作るためのobjデータ作成Pythonスクリプト

ラノベのタイトルみたいに長いですけど。
2値画像から3Dプリンターでスタンプを作るためのobjデータ作成Pythonスクリプトです
画像を入力してobjファイルを吐きます

f:id:boxheadroom:20191014211454p:plain
3Dプリンターでスタンプ
CURAでスライス後はこんな感じ 3センチ角 出力してないので ちゃんと出るかは不明ですが 最近 バックアップ用のHDDがまた飛んだので とりあえずメモだけ


import numpy as np
import cv2


fname0="stamp.png"
stampw0=40 #40mm
stamph0=30 #30mm

threashold0=127

#objファイルの座標系は blenderだと x z y に相当する
#スクリプト内では wavefront objに合わせる
vidx=0
rawlist=[]
vlist=[]
flist=[]
vdict={}
vidx2xyz={}


def addv(v1,v2,v3,v4):
global vidx
v1=tuple(v1)
v2=tuple(v2)
v3=tuple(v3)
v4=tuple(v4)

for v in [v1,v2,v3,v4]:
if not v in vdict :
vidx+=1
vdict[v]=vidx
vidx2xyz[vidx]=v
rawlist.append([v1,v2,v3,v4])
#rawlist.append([v1,v4,v3,v2])

def main(fname=fname0, stampw=stampw0, stamph=stamph0,threashold=threashold0):
global vidx,rawlist,vlist,flist,vdict,vidx2xyz
#global v
vidx=0
im=cv2.imread(fname,0)
#2値化 反転
#黒が出っ張るところ 
#普通の画像とは逆になりますが
#スタンプなので
#黒なら高い


im2=im.copy()
im2=im[:,-1::-1] #左右反転
im2[im<threashold]=1
im2[im>=threashold]=0
y0=0
y1=1
y2=2

imh,imw=im.shape
dx=stampw/imw
dy=2.0
dz=stamph/imh
#ベース
#サイド左
x=0
z1=0
z2=imh
addv( (x,y1,z1),
(x,y1,z2),
(x,y0,z2),
(x,y0,z1))
#サイド右
z1=0
z2=imh

z1=0
z2=imh
x1=imw-1
x2=imw
addv( (x2,y1,z1),
(x2,y0,z1),
(x2,y0,z2),
(x2,y1,z2))
#ベース奥
z=0
z1=z
z2=z+1
x1=0
x2=imw
addv( (x1,y1,z1),
(x1,y0,z1),
(x2,y0,z1),
(x2,y1,z1))
#ベース手前
z2=imh
x1=0
x2=imw
addv( (x1,y1,z2),
(x2,y1,z2),
(x2,y0,z2),
(x1,y0,z2))
#ベース天板
z1=0
z2=imh
x1=0
x2=imw
addv( (x1,y1,z1),
(x2,y1,z1),
(x2,y1,z2),
(x1,y1,z2))
#ベース底
z1=0
z2=imh
x1=0
x2=imw

addv( (x1,y0,z1),
(x1,y0,z1),
(x2,y0,z2),
(x2,y0,z2))


for z in range(imh):
z0=z-1
z1=z
z2=z+1
for x in range(imw):
x0=x-1
x1=x
x2=x+1
addv( (x1,y0,z1),
(x1,y0,z2),
(x2,y0,z2),
(x2,y0,z1))

y1=y0
for z in range(imh):
z0=z-1
z1=z
z2=z+1
for x in range(imw):
x0=x-1
x1=x
x2=x+1
c=im2[z,x]
if c==1:
addv( (x1,y2,z1),
(x2,y2,z1),
(x2,y2,z2),
(x1,y2,z2))
addv( (x1,y1,z1),
(x1,y1,z2),
(x2,y1,z2),
(x2,y1,z1))
#左サイド
if 1 or x==0 or im2[z,x0]==0:
addv( (x1,y2,z1),
(x1,y2,z2),
(x1,y1,z2),
(x1,y1,z1))
#右サイド
if 1 or x==(imw-1) or im2[z,x2]==0:
addv( (x2,y2,z1),
(x2,y1,z1),
(x2,y1,z2),
(x2,y2,z2))
#奥サイド
if 1 or z==0 or im2[z0,x]==0:
addv( (x1,y2,z1),
(x1,y1,z1),
(x2,y1,z1),
(x2,y2,z1))
#手前サイド
if 1 or z==(imh-1) or im2[z2,x]==0:
addv( (x1,y2,z2),
(x2,y2,z2),
(x2,y1,z2),
(x1,y1,z2))
elif 0 and c==0:
addv( (x1,y1,z1),
(x2,y1,z1),
(x2,y1,z2),
(x1,y1,z2))

vidxlist=list(vidx2xyz.keys())
vidxlist.sort()
for i in vidxlist:
x,y,z=v=vidx2xyz[i]
vlist.append( (dx*x,dz*z,dy*y))
for t in rawlist:
t1,t2,t3,t4 =t
i1=vdict[t1]
i2=vdict[t2]
i3=vdict[t3]
i4=vdict[t4]
flist.append( (i1,i2,i3,i4))

lines=["# x z y in blender",
"g group1"]
for v in vlist:
# x,y,z=v
# lines.append("v %f %f %f"%(x,y,z))
lines.append("v %f %f %f"%v)

for f in flist:
lines.append("f %d %d %d %d"%f)

with open("%s.obj"%fname,"w") as fp:
fp.write("\n".join(lines))


if __name__=="__main__":
fname="dora.png"
stampw=30 #40mm
stamph=30 #30mm

threashold=127
main(fname=fname, stampw=stampw, stamph=stamph,threashold=threashold)