python版李相夷

news2025/3/10 21:09:06

1、我们绘制原图是这张lxy.jpg

在这里插入图片描述

2、具体代码如下

运行python main.py lxy.jpg就可以实现绘制过程了!(可能会比较慢)

# -*- coding: utf-8 -*-


import turtle as te
from bs4 import BeautifulSoup
import argparse
import sys
import numpy as np
import cv2
import os
from win32api import GetSystemMetrics

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):  # 二阶贝塞尔函数
    te.goto(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)
        te.goto(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  # 坐标变换
    te.goto(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)
    te.penup()
    te.goto(-Width / 2 + x, Height / 2 - y)
    te.pendown()


def Moveto_r(dx, dy):
    te.penup()
    te.goto(te.xcor() + dx, te.ycor() - dy)
    te.pendown()


def line(x1, y1, x2, y2):  # 连接svg坐标下两点
    te.penup()
    te.goto(-Width / 2 + x1, Height / 2 - y1)
    te.pendown()
    te.goto(-Width / 2 + x2, Height / 2 - y2)
    te.penup()


def Lineto_r(dx, dy):  # 连接当前点和相对坐标(dx,dy)的点
    te.pendown()
    te.goto(te.xcor() + dx, te.ycor() - dy)
    te.penup()


def Lineto(x, y):  # 连接当前点和svg坐标下(x,y)
    te.pendown()
    te.goto(-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):
    ulist = w_attr.split(' ')
    for i in ulist:
        # print("now cmd:", i)
        if i.isdigit() or i.isalpha():
            yield float(i)
        elif i[0].isalpha():
            yield i[0]
            yield float(i[1:])
        elif i[-1].isalpha():
            yield float(i[0: -1])
        elif i[0] == '-':
            yield float(i)


def drawSVG(filename, w_color):
    global first
    SVGFile = open(filename, 'r')
    SVG = BeautifulSoup(SVGFile.read(), 'lxml')
    Height = float(SVG.svg.attrs['height'][0: -2])
    Width = float(SVG.svg.attrs['width'][0: -2])
    transform(SVG.g.attrs['transform'])
    if first:
        te.setup(height=Height, width=Width)
        te.setworldcoordinates(-Width / 2, 300, Width -
                               Width / 2, -Height + 300)
        first = False
    te.tracer(100)
    te.pensize(1)
    te.speed(Speed)
    te.penup()
    te.color(w_color)

    for i in SVG.find_all('path'):
        attr = i.attrs['d'].replace('\n', ' ')
        f = readPathAttrD(attr)
        lastI = ''
        for i in f:
            if i == 'M':
                te.end_fill()
                Moveto(next(f) * scale[0], next(f) * scale[1])
                te.begin_fill()
            elif i == 'm':
                te.end_fill()
                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.close()


def drawBitmap(w_image):
    print('Reducing the colors...')
    Z = w_image.reshape((-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)
    res = center[label.flatten()]
    res = res.reshape(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.bitwise_not(res2)
        cv2.imwrite('.tmp.bmp', res2)
        os.system('potrace.exe .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, close the window to exit.')
    te.done()


if __name__ == '__main__':
    paser = argparse.ArgumentParser(
        description="Convert an bitmap to SVG and use turtle libray to draw it.")
    paser.add_argument('filename', type=str,
                       help='The file(*.jpg, *.png, *.bmp) name of the file you want to convert.')
    paser.add_argument(
        "-c", "--color", help="How many colors you want to draw.(If the number is too large that the program may be very slow.)", type=int, default=32)
    args = paser.parse_args()
    K = args.color
    try:
        bitmapFile = open(args.filename, mode='r')
    except FileNotFoundError:
        print(__file__ + ': error: The file is not exists.')
        quit()
    if os.path.splitext(args.filename)[1].lower() not in ['.jpg', '.bmp', '.png']:
        print(__file__ + ': error: The file is not a bitmap file.')
        quit()
    bitmap = cv2.imread(args.filename)
    if bitmap.shape[0] > GetSystemMetrics(1):
        bitmap = cv2.resize(bitmap, (int(bitmap.shape[1] * (
            (GetSystemMetrics(1) - 50) / bitmap.shape[0])), GetSystemMetrics(1) - 50))
    drawBitmap(bitmap)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1102062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux常用指令

ls指令(对属性操作,查看文件相关属性) 用法:ls[选项][目录或文件] 功能:1. 对于目录,该命令列出该目录下的所有子目录和文件。2. 对于文件,将列出文件名以及其他信息。 常用选项: …

jmeter 解决查看结果树响应内容中文乱码问题

jmeter 解决查看结果树响应内容中文乱码问题 查看结果树中,接口响应内容中,包含中文,显示乱码; 临时解决方法,添加BeanShell 后置处理程序,添加内容prev.setDataEncoding("utf-8"); 运行压测…

矫正图片背景

在利用明场或荧光显微镜成像时,往往会由于样品厚度不一、镜头污渍或者光照不均等因素,降低图片质量,从而影响分析以及展示。 这篇文章就为大家介绍:怎样利用 ImageJ 对图片进行背景校正,包括两个方面:白平…

前端跨域问题解决

一、同源策略 同源策略是一个重要的安全策略,它用于限制一个Origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。 Origin:指web文档的来源,Web 内容的来源取决于访问的U…

数据结构: 二叉搜索树

目录 1.二叉搜索树概念 2.二叉搜索树的操作 3.二叉搜索树的实现 3.1定义BST 3.2功能实现 1.默认成员函数 2.非递归 插入 查找 删除 3.递归 插入 查找 删除 4.二叉搜索树的应用 1.二叉搜索树概念 二叉搜索树又称二叉排序树,它可以是一棵空树&#xff…

Java连接PostGreSql

本次试验怎么用jdbc连接PostGreSql数据库。首先需要安装一个pgsql数据库,安装就不介绍了。安装后自己用SQL创建表,如有下图的库和表,怎么用java带SQL参数连接他取的数据。 PG库下载地址 首先到官网上根据自己的Java版本下载jdbc驱动jdbc下载…

HCIP静态路由综合实验

题目: 步骤: 第一步:搭建上图所示拓扑; 第二步:为路由器接口配置IP地址; R1: [R1]display current-configuration intinterface GigabitEthernet0/0/0ip address 192.168.1.1 255.255.255.252 interfa…

FL Studio 2023中文安装设置指南!四招教你玩转FL Studio21!

Fl Studio是一款极具时尚元素的音乐制作软件,对于粉丝群体来说简直是一大福利!不仅可以充分发挥你的创造力,还能展现你的音乐才华。这里给你分享几个设置中文的技巧,让你的Fl Studio体验更上一层楼! 编曲软件FL Studi…

警惕这款记录音频和电话的Android木马软件SpyNote

导语:近日,一款名为SpyNote的Android木马软件被揭示出其多样化的信息收集功能。该木马软件通常通过短信钓鱼攻击传播,攻击链通过欺骗潜在受害者点击嵌入链接来安装该应用程序。除了要求入侵性权限以访问通话记录、摄像头、短信和外部存储等&a…

vite react react-pdf pdfjs-dist 加载不全的解决方案 cmaps本地路径

pdf.js 字体无法显示 pdfjs-dist加载不全的解决方案 Rollup 配置 rollup-plugin-copy插件,进行打包构建时的文件复制 参考了网上诸多解决方案,都是webpack的引入包方式, 照猫画虎,把vite解决方案奉献给大家 vite.config.js impo…

小程序:uniapp解决主包体积过大的问题

已经分包但还是体积过大 运行时勾选“运行时是否压缩代码”进行压缩 在manifest.json配置(开启分包优化) "mp-weixin" : {"optimization" : {"subPackages" : true}//.... },在app.json配置(设置组件按需注入…

【CANN训练营】UART、SPI、I2C串口通信介绍笔记

UART、SPI、I2C串口通信介绍 UART通信 串行通信和并行通信 数据通信:若干个数据设备之间的信息交换称为数据通信。 两种方式:并行通信和串行通信 并行通信:数据的各位同时传送,每一位数据都需要一条传输线并且需要若干条控制…

H5+Vue3编写官网,并打包发布到同一个域名下

背景 因为html5有利于搜索引擎抓取和收录我们网站更多的内容,对SEO很友好,可以为网站带来更多的流量,并且多端适配,兼容性和性能都非常不错,所以使用h5来编写官网首页。 因为用户个人中心可以通过官网跳转,不需要被浏…

jmeter压测

jmeter强大到很强大 hh~也要压测go的一些东西&#xff0c;这是三年前做的东西了&#xff0c;jmeter不支持grpc调用所以写了一个spring小服务中间层&#xff1a; 具体的jmeter开始了 这里设置线程相关 <h3>调用哪个服务的哪个方法</h3> <h3>BeanShell PrePro…

“脆皮大学生”上热搜,体质变差不能轻视

蕞近&#xff0c;“脆皮大学生”这一词条在网络上走红。“脆皮大学生”指现在新一代大学生&#xff0c;虽然年纪轻轻&#xff0c;但是身体毛病却极多&#xff0c;脆弱到了一碰就坏的地步&#xff0c;出现了“脆皮现象”。 仅2023年9月一个月&#xff0c;郑州一家医院急诊科接诊…

Spring5应用之高级注解开发

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Spring5应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言Conf…

JOSEF约瑟 10KV高压漏电保护继电器BLD-20 φ100mm 50-500mA 导轨安装

系列型号 BLD-20A高压漏电保护继电器 BLD-20高压漏电继电器 BLD-20高压漏电保护继电器 BLD-20X高压漏电保护装置 BLD-G20X高压漏电保护装置 BLD-20RG高压漏电保护继电器 用途 BLD-20漏电继电器(以下简称继电器)主用于交流电压1-10KV系统中,频率为50HZ,对供电系 统的漏…

【C语言】#define宏与函数的优劣对比

本篇文章目录 1. 预处理指令#define宏2. #define定义标识符或宏&#xff0c;要不要最后加上分号&#xff1f;3.宏的参数替换后产生的运算符优先级问题3.1 问题产生3.2 不太完美的解决办法3.3 完美的解决办法 4.#define的替换规则5. 有副作用的宏参数6. 宏与函数的优劣对比6.1 宏…

从0开始学Java:运算符(Operator)与标点符号(Separators)

文章目录 1. 运算符的分类2. 算术运算符3. 赋值运算符4. 关系运算符/比较运算符5. 逻辑运算符6. 条件运算符练习 7. 位运算符&#xff08;了解&#xff09;左移&#xff1a;<<右移&#xff1a;>>无符号右移&#xff1a;>>>按位与&#xff1a;&按位或&…

阿里云优惠券(代金券)免费领取方法及使用教程分享

阿里云优惠券是阿里云提供给用户的一种优惠凭证&#xff0c;通常包括代金券和折扣券&#xff0c;领取之后支付订单时可以抵扣或者打折&#xff0c;是阿里云的一种重要优惠方式。本文将为大家详细介绍阿里云优惠券的免费领取方法及使用教程&#xff0c;帮助大家在购买阿里云产品…