python+Potrace实现⾃动作画——程序员的浪漫
连续看了快⼀个⽉的spark源码,吃饭脑⼦⾥蹦出来的都是rpc私有协议、DAGschedule⼈、TASKscheduler、调度、
资源申请.....总之⼀句话就是看的快吐了,该换换脑⼦再做打算。那怎么换脑⼦呢,做些啥好玩有意思的事呢;看电影、看⼩说
觉得有点浪费时间还没意思。灵光⼀现想到前⼀阵⼦和朋友吃饭,聊到程序员怎么样才浪漫。谈到MIT⼤学⽣⿊了⼀栋宿舍楼做灯光秀,控制楼层显⽰”** ilove you“、⿊进她前男友加密的QQ空间,看⼀看然后在乱做评论到此⼀游然后录制视频图⽚发给他前男友.....
从技术实现⾓度讲呢,这两件有趣的事到也不难实现:
1)灯光秀,现在电⽹控制基本都是单⽚机数字化的管理控制,安全防护不⾼只要知道控制板在哪,电脑编个程序替换现有控制板就可以任你控制了;⽆⾮就是把整座楼当成事⼀个LED阵列,控制它显⽰你要的字符;难度系数和可执⾏系数都不算⼤;⽆奈这事情是不合法的,抓到要⾥⾯待两周以上,就此作罢
2)⿊进某⼈⽹站,然后撒泡尿到此⼀游难度系数稍微⼤些,因为QQ毕竟是商业公司安全也做了这么多年,不过⼈社⼯程+⽹络技术要做到也不是完全不可能,然⽽这个呢也是不合法的啊....
所以另辟蹊径找点有意思的玩玩,对于我这种和平⼈⼠,创造性的玩法估计⽐较适合我,那具体可以做些啥呢。寻思了⼀阵画个画什么的可好。可艺术细胞稀缺画画这种事不适合程序员啊....唉,别急,我是不会画,我让机器画估计还是可以的嘛。
我最感激的人
有了这主意,马上⾕歌百度“机器作画”发现没啥有创意的,换了个词程序动画...还是⽐较严肃没啥有意思的;在继续换换“ python 游戏”有点意思了,有些兄弟⽤python开发了不少好玩简单游戏,但还是和我想要的有些差距,继续“python 动画”、“python 动漫”慢慢有点意思了。找到⼀个不错的玩法——给程序⼀张图⽚,程序可以按顺序把图⽚给⼀笔⼀画的画出来。听起来还是挺有趣的,总⽐深度学习风格转化、换脸有意思,你可以看到机器是怎么⼀笔⼀画的画画还是可以的嘛。
⾸先到github找到项⽬,代码拉下来看了看,分析下作者实现思路:
1、把png、jpg图⽚⽮量化,转化成SVG格式
2、有了SVG格式就知道图画的边界,如果可以有个软件可以按⼀定速度沿边界移动不就有作画效果了
3、做完边界然后把每个区域颜⾊填充,这样⼀幅画就画好了
A.因为图⽚的颜⾊会⽐较多,在这⾥作者通过opencv对图像先做聚类,⽤更少颜⾊去表⽰更多颜⾊
通过opencv读⼊图⽚:
bitmap = cv2.imread(args.filename)
drawBitmap(bitmap)圣物之盾
通过opencv对图⽚做颜⾊聚类&Potrace对图⽚做⽮量图转化:
def drawBitmap(w_image):
print('Reducing ')
Z = shape((-1, 3))
# convert to np.float32
Z = np.float32(Z)
# define criteria, number of clusters(K) and apply kmeans()
criteria = (cv2.TERM_CRITERIA_EPS, 10, 1.0)
global K
ret, label, center = cv2.kmeans(
Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
# Now convert back into uint8, and make original image
center = np.uint8(center)
print(center)
res = center[label.flatten()]
res = shape(w_image.shape)
no = 1
for i in center:
sys.stdout.write('\rDrawing: %.2f%% [' % (
no / K * 100) + '#' * no + ' ' * (K - no) + ']')
no += 1
res2 = cv2.inRange(res, i, i)
res2 = cv2.bitwi_not(res2)
#print(i)
res2 = res北京跑步
cv2.imwrite('.tmp.bmp', res2)
os.system('potrace .tmp.bmp -s --flat')
print(i)
drawSVG('.tmp.svg', '#%02x%02x%02x' % (i[2], i[1], i[0]))
#os.remove('.tmp.bmp')
#os.remove('.tmp.svg')
全球最美女性排行榜
print('\n\rFinished, clo the window to exit.')
te.done()
按⽮量图轨迹作画,利⽤了python turtle库:
def drawSVG(filename, w_color):
global first
SVGFile = open(filename, 'r')
SVG = ad(), 'lxml')
Height = float(SVG.svg.attrs['height'][0: -2])
Width = float(SVG.svg.attrs['width'][0: -2])
attrs['transform'])
if first:
te.tup(height=Height, width=Width)
te.tworldcoordinates(-Width / 2, 300, Width -
Width / 2, -Height + 300)
first = Fal
te.pensize(1)
te.speed(Speed)
te.penup()
for i in SVG.find_all('path'):
attr = i.attrs['d'].replace('\n', ' ')
f = readPathAttrD(attr)
lastI = ''
for i in f:
if i == 'M':
Moveto(next(f) * scale[0], next(f) * scale[1]) te.begin_fill()
elif i == 'm':
Moveto_r(next(f) * scale[0], next(f) * scale[1]) te.begin_fill()
elif i == 'C':
Curveto(next(f) * scale[0], next(f) * scale[1], next(f) * scale[0], next(f) * scale[1],
next(f) * scale[0], next(f) * scale[1])
lastI = i
elif i == 'c':
Curveto_r(next(f) * scale[0], next(f) * scale[1], next(f) * scale[0], next(f) * scale[1],
next(f) * scale[0], next(f) * scale[1])
lastI = i
elif i == 'L':
Lineto(next(f) * scale[0], next(f) * scale[1])
elif i == 'l':
Lineto_r(next(f) * scale[0], next(f) * scale[1]) lastI = i
elif lastI == 'C':
Curveto(i * scale[0], next(f) * scale[1],
next(f) * scale[0], next(f) * scale[1],
next(f) * scale[0], next(f) * scale[1])
elif lastI == 'c':
Curveto_r(i * scale[0], next(f) * scale[1],
next(f) * scale[0], next(f) * scale[1],
写比喻句
next(f) * scale[0], next(f) * scale[1])
elif lastI == 'L':
Lineto(i * scale[0], next(f) * scale[1])
elif lastI == 'l':
Lineto_r(i * scale[0], next(f) * scale[1])
燕窝的营养价值te.penup()
te.hideturtle()
te.update()
SVGFile.clo()
具体代码:
# -*- coding: utf-8 -*-
# Author: tfx2001
# Licen: GNU GPLv3
# Time: 2018-08-09 18:27
import turtle as te
from bs4 import BeautifulSoup
import argpar
import sys
import numpy as np
import cv2
import os
WriteStep = 15 # 贝塞尔函数的取样次数
Speed = 1000
Width = 600 # 界⾯宽度
Height = 600 # 界⾯⾼度
Xh = 0 # 记录前⼀个贝塞尔函数的⼿柄
Yh = 0
scale = (1, 1)
first = True
K = 32
def Bezier(p1, p2, t): # ⼀阶贝塞尔函数
return p1 * (1 - t) + p2 * t
def Bezier_2(x1, y1, x2, y2, x3, y3): # ⼆阶贝塞尔函数
<(x1, y1)
te.pendown()
for t in range(0, WriteStep + 1):
x = Bezier(Bezier(x1, x2, t / WriteStep),
Bezier(x2, x3, t / WriteStep), t / WriteStep)
y = Bezier(Bezier(y1, y2, t / WriteStep),
可口可乐配方
Bezier(y2, y3, t / WriteStep), t / WriteStep)
<(x, y)
te.penup()
def Bezier_3(x1, y1, x2, y2, x3, y3, x4, y4): # 三阶贝塞尔函数
x1 = -Width / 2 + x1
y1 = Height / 2 - y1
x2 = -Width / 2 + x2
y2 = Height / 2 - y2
x3 = -Width / 2 + x3
y3 = Height / 2 - y3
x4 = -Width / 2 + x4
y4 = Height / 2 - y4 # 坐标变换
<(x1, y1)
te.pendown()
for t in range(0, WriteStep + 1):
x = Bezier(Bezier(Bezier(x1, x2, t / WriteStep), Bezier(x2, x3, t / WriteStep), t / WriteStep),
Bezier(Bezier(x2, x3, t / WriteStep), Bezier(x3, x4, t / WriteStep), t / WriteStep), t / WriteStep) y = Bezier(Bezier(Bezier(y1, y2, t / WriteStep), Bezier(y2, y3, t / WriteStep), t / WriteStep),
Bezier(Bezier(y2, y3, t / WriteStep), Bezier(y3, y4, t / WriteStep), t / WriteStep), t / WriteStep) te.goto(x, y)
te.penup()
def Moveto(x, y): # 移动到svg坐标下(x,y)
def Moveto(x, y): # 移动到svg坐标下(x,y)
te.penup()
<(-Width / 2 + x, Height / 2 - y)
te.pendown()
def Moveto_r(dx, dy):
te.penup()
<(te.xcor() + dx, te.ycor() - dy)
te.pendown()
def line(x1, y1, x2, y2): # 连接svg坐标下两点
te.penup()
<(-Width / 2 + x1, Height / 2 - y1)
te.pendown()
<(-Width / 2 + x2, Height / 2 - y2)
te.penup()
def Lineto_r(dx, dy): # 连接当前点和相对坐标(dx,dy)的点
te.pendown()
<(te.xcor() + dx, te.ycor() - dy)
te.penup()
def Lineto(x, y): # 连接当前点和svg坐标下(x,y)
te.pendown()
<(-Width / 2 + x, Height / 2 - y)
te.penup()
def Curveto(x1, y1, x2, y2, x, y): # 三阶贝塞尔曲线到(x,y)
te.penup()
X_now = te.xcor() + Width / 2
Y_now = Height / 2 - te.ycor()
Bezier_3(X_now, Y_now, x1, y1, x2, y2, x, y)
global Xh
global Yh
Xh = x - x2
Yh = y - y2
def Curveto_r(x1, y1, x2, y2, x, y): # 三阶贝塞尔曲线到相对坐标(x,y) te.penup()
X_now = te.xcor() + Width / 2
Y_now = Height / 2 - te.ycor()
Bezier_3(X_now, Y_now, X_now + x1, Y_now + y1,
X_now + x2, Y_now + y2, X_now + x, Y_now + y)
中国戏曲种类global Xh
global Yh
Xh = x - x2
Yh = y - y2
def transform(w_attr):
funcs = w_attr.split(' ')
for func in funcs:
func_name = func[0: func.find('(')]
if func_name == 'scale':
global scale
scale = (float(func[func.find('(') + 1: -1].split(',')[0]),
-float(func[func.find('(') + 1: -1].split(',')[1]))
def readPathAttrD(w_attr):