Learn to Paint 光栅图转矢量图生成

27 篇文章 4 订阅
18 篇文章 1 订阅

这个系列项目代码实现:

https://github.com/liangwq/Chatglm_lora_multi-gpu/tree/main/APP_example

Lean to 矢量生成

可微分渲染文章:

平滑矢量图形综述:表示、创建、光栅化和图像矢量化的最新进展
无偏扭曲区域采样在可微分渲染中的应用
可微分矢量图形光栅化用于编辑和学习
图片逐层矢量

矢量图

类人笔触的模型风格化绘画
CLIPDraw:通过语言-图像编码器探索文本到绘图合成
根据参考风格进行矢量图绘制
基于语义感知的对象草图绘制
具有不同类型和抽象级别的场景素描
通过潜在扩散模型实现文本引导矢量草图合成
使用扩散模型进行文本引导的SVG生成
使用神经实现路径表示的文本到向量生成

矢量文字

字就是图,实现语义排版

前面部分回顾了下通过learn的方式来求解图片矢量。现在的learn方式更多是体现的给定光栅图、控制条件来求解矢量模型参数。目前还没有看到类似文本生成图片的生成大模型的,直接通过文本引导生成矢量图的大模型。
在接下来的系列会介绍上面论文的代码实践。先介绍论文主要算法实现,然后介绍代码的应用实例。下面以Diffvg作为这个系列的开场。

Diffvg+html矢量图生成

核心类实现

optimize_svg

这份代码是一个复杂的Python脚本,用于解析和优化SVG(可缩放矢量图形)文件。它包含多个类和方法,用于处理SVG文件的不同部分,如形状、颜色、变换和渐变。下面是对代码的主要部分的解释:

  1. 导入模块
  • 代码开始时导入了多个Python标准库和第三方库,如json, copy, xml.etree.ElementTree, torch, numpy, pydiffvg等,这些库用于处理文件、数据复制、XML解析、机器学习、数值计算和图形渲染。
  1. SvgOptimizationSettings类
  • 这个类定义了SVG优化的默认参数,如颜色优化、透明度优化、变换优化等。它还包含一个字典optims,用于存储不同优化器的实现。
  1. OptimizableSvg类
  • 这个类是主要的SVG处理类,它包含了多个子类和方法,用于解析和优化SVG文件。它包括处理SVG节点、形状、变换、渐变等的子类和方法。
  1. SVG节点类
  • 包括SvgNode, GroupNode, RootNode, ShapeNode, PathNode, RectNode, CircleNode, EllipseNode, PolygonNode, GradientNode等。这些类用于表示SVG文件中的不同类型的节点,如根节点、组节点、形状节点等。
  1. 优化器类
  • 包括ColorOptimizer, StopOptimizer, GradientOptimizer, TransformOptimizer等。这些类用于优化SVG中的颜色、渐变停止点、渐变和变换。
  1. 解析和写入方法
  • 代码中包含了许多方法,用于解析SVG文件的不同部分(如形状、变换、渐变等),并将优化后的结果写回到XML格式。
  1. 优化和渲染
  • 代码提供了方法来优化SVG文件中的元素,并通过pydiffvg库渲染优化后的SVG图形。

解析SVG文件,还能够对其进行优化,并通过机器学习方法(如PyTorch)来调整SVG元素的属性,最终生成优化后的SVG图形。这对于需要处理和优化大量SVG文件的应用场景非常有用。

它定义了一个名为OptimizableSvg的类,用于处理和优化SVG(Scalable Vector Graphics)图像。程序使用了PyTorch库来执行数值计算和优化。以下是代码的主要组成部分和功能的详细解释:

类定义和属性
  • SvgOptimizationSettings:这个类用于存储SVG优化的设置,例如颜色优化、透明度优化、变换优化等。它包含了默认参数和优化器的映射。
  • OptimizableSvg:这是主要的类,用于表示和优化SVG图像。它包含了一系列方法来解析SVG文件、构建场景、执行优化步骤以及渲染图像。
核心功能
  • parseRoot(root):解析SVG文件的根元素,初始化画布尺寸、转换和外观。
  • parseShape(shape, parent):根据SVG中的不同形状(如路径、圆形、矩形等),调用相应的解析函数。
  • parseTransform(node):解析SVG节点中的变换属性。
  • parseAppearance(node, defs, device):解析SVG节点的外观属性,如填充颜色、透明度等。
  • build_scene():根据解析的SVG数据构建场景,准备进行渲染或优化。
  • render(scale=None, seed=0):渲染场景,生成图像。
  • step():执行优化步骤,更新SVG属性。
辅助功能
  • TransformTools:一个嵌套类,提供了一系列静态方法来处理SVG变换,如解析矩阵、应用变换到点等。
  • ColorOptimizerStopOptimizerGradientOptimizerTransformOptimizer:这些嵌套类用于优化SVG的不同属性,如颜色、渐变停止点、渐变属性和变换。
SVG节点
  • SvgNode:一个抽象基类,定义了SVG节点的基本结构和行为。
  • GroupNodeRootNodeShapeNodePathNodeRectNodeCircleNodeEllipseNodePolygonNodeGradientNode:这些类继承自SvgNode,代表SVG中的不同类型节点,并实现了具体的构建场景和写入XML的方法。
写入和报告
  • write_xml():将优化后的SVG节点写入XML格式。
  • write_defs(root):写入SVG定义(如渐变、样式等)。
  • reportSkippedAttribs(node, non_skipped=[]):报告在解析过程中跳过的SVG属性。
  • reportSkippedChildren(node, skipped):报告在解析过程中跳过的子节点。
其他
  • unit_dict:一个字典,用于将SVG中的尺寸单位转换为像素。
  • parseLength(s)parseOpacity(s)parse_color(s):这些静态方法用于解析SVG中的尺寸、透明度和颜色。

整体来看,这个程序提供了一个完整的框架来加载SVG文件,对其进行解析、优化和重新生成。它特别适用于需要对SVG图像进行数值优化的场景,例如在计算机图形学和机器学习应用中。

render_pytorch

代码是一个基于PyTorch框架的渲染库,使用了diffvg和pydiffvg库来实现矢量图的前向渲染和反向梯度传播。它主要用于生成和操作具有艺术效果的图像,例如绘画风格或者设计图案。下面是代码的主要功能和实现逻辑的详细解释:

主要功能
  1. 矢量图渲染:将矢量图形(如圆形、椭圆形、路径、多边形和矩形)渲染成位图图像。
  2. 多种输出类型:支持颜色图像和符号距离场(SDF)两种输出类型。
  3. 渐变填充:支持线性渐变和径向渐变作为填充颜色。
  4. 笔触宽度和样式:可以设置矢量图形的笔触宽度,并选择是否使用距离近似。
  5. 分组和混合规则:支持将多个形状分组,并使用非零规则或偶奇规则进行渲染。
  6. 前向渲染和梯度传播:能够进行前向渲染以生成图像,并计算梯度以进行反向传播,这对于训练生成模型或优化图形参数非常有用。
实现逻辑
  • RenderFunction 类:这是一个PyTorch Function,它封装了与diffvg库交互的逻辑。
    • serialize_scene 方法:将场景中的图形和形状分组序列化为一个参数列表,以便在PyTorch中使用。
    • forward 方法:执行前向渲染,生成图像或SDF。
    • render_grad 方法:在给定梯度图像的情况下,计算场景中各个元素的梯度。
    • backward 方法:执行反向传播,计算图形参数的梯度。
  • 场景构建:在forward和render_grad方法中,首先构建一个diffvg.Scene对象,该对象包含了渲染所需的所有信息,如图形、形状分组、滤镜等。
  • 渲染过程:使用diffvg.render函数执行实际的渲染操作。这个函数处理了光线追踪、栅格化等底层细节。
  • 参数序列化与反序列化:为了与PyTorch的自动微分系统兼容,需要将场景中的图形和参数序列化为一个扁平化的参数列表,并在前向和后向传递中进行反序列化。
  • 梯度传播:在backward方法中,根据diffvg库提供的梯度信息,计算并返回每个图形参数的梯度。
代码结构
  • 类和枚举定义:定义了OutputType枚举和RenderFunction类。
  • 全局变量和函数:print_timing全局变量控制是否打印计时信息,set_print_timing函数用于设置这个变量。
  • 形状和颜色处理:代码中处理了多种形状和颜色类型,包括圆形、椭圆形、路径、多边形、矩形以及线性渐变和径向渐变。
  • 渲染和梯度计算:实现了前向渲染和梯度计算的逻辑,包括场景构建、渲染调用和梯度传播。
类和函数解释
  • set_print_timing:一个函数,用于设置是否打印渲染过程中的时间信息。
  • OutputType:一个枚举类,定义了输出类型,可以是颜色图像或符号距离场(SDF)。
  • RenderFunction:一个类,实现了PyTorch的Function接口,用于封装diffvg库的渲染功能。
RenderFunction类的主要方法:
  • serialize_scene:序列化场景,将场景中的图形和颜色信息转换为可以由PyTorch处理的线性参数列表。
  • forward:前向渲染方法,根据提供的参数和场景设置,执行渲染操作,生成图像。
  • render_grad:梯度渲染方法,计算给定图像梯度的翻译梯度。
  • backward:后向渲染方法,计算场景参数对图像的梯度。
逻辑流程
  1. 序列化场景:在serialize_scene中,将场景的图形和颜色信息转换为一系列参数,这些参数随后被用于渲染过程。
  2. 前向渲染:在forward方法中,首先构造一个diffvg场景对象,然后调用diffvg.render函数执行实际的渲染操作。如果有背景图像,它会被合并到输出图像中。
  3. 梯度渲染:在render_grad方法中,计算给定梯度图像的平移梯度,这有助于神经网络训练中的场景优化。
  4. 后向渲染:在backward方法中,计算图像对场景参数的梯度,这对于自动微分和优化场景参数至关重要。
实现细节
  • 使用IntEnum定义输出类型,提高代码的可读性。
  • 通过RenderFunction类封装diffvg库的功能,使其与PyTorch的自动微分系统兼容。
  • 通过forwardbackward方法,实现了自定义的PyTorch函数,可以自动计算梯度。
  • 代码中包含了大量的断言(assert语句),以确保输入数据的正确性。

用于在PyTorch框架中进行矢量图形的渲染和自动微分,可以用于图形设计、计算机视觉和机器学习等领域。
代码通过以下步骤实现图形渲染:

  1. 场景序列化 (serialize_scene 函数):
  • 这个函数将场景中的所有元素(如形状、形状组、颜色、变换等)转换为可以在PyTorch中处理的格式。它将每个元素的参数(如位置、大小、颜色等)转换为张量,并将它们存储在一个列表中,以便在渲染时使用。
  1. 前向传播 (RenderFunctionforward 方法):
  • 在这个方法中,首先从输入参数中解包出场景的序列化参数。
  • 然后,根据这些参数创建一个diffvg.Scene对象,这个对象包含了渲染所需的所有信息。
  • 接着,根据输出类型(颜色或SDF)创建一个空的渲染图像张量。
  • 如果提供了背景图像,将其转换为PyTorch张量并确保其具有正确的形状和设备。
  • 使用diffvg.render函数执行实际的渲染操作,这个函数会根据场景和渲染设置生成图像。
  • 渲染完成后,将渲染图像和场景信息存储在上下文中,以便在反向传播时使用。
  1. 渲染细节:
  • diffvg.render函数是渲染的核心,它使用GPU加速来计算图像。这个函数会根据场景中的形状和颜色信息,以及渲染设置(如分辨率、采样数等),计算每个像素的颜色或SDF值。
  • 渲染过程中,会考虑到形状的遮挡关系、颜色渐变、光照效果等,以生成最终的图像。
  1. 输出:
  • 渲染完成后,返回的渲染图像是一个PyTorch张量,其形状取决于输出类型。如果是颜色图像,形状通常是(height, width, 4),表示每个像素的RGBA值;如果是SDF图像,形状可能是(height, width, 1)(num_positions, 1),取决于是否指定了评估位置。

通过结合PyTorch的自动求导能力和diffvg库的图形渲染功能,实现了高效的图形渲染和梯度计算。这使得它非常适合用于需要通过梯度下降来优化图形参数的应用,例如生成对抗网络(GANs)中的图像生成任务。

DiffVG图渲染例子

光栅图转矢量SVG

编译&安装Diffvg
git clone https://github.com/BachiLi/diffvg.git
cd diffvg
git submodule update --init --recursive
conda install -y -c anaconda cmake
conda install -y -c conda-forge ffmpeg
pip install svgwrite svgpathtools cssutils torch-tools
python setup.py install
光栅图转SVG
#1. 上传一张要处理的图片
#2. 设定需要多少条曲线拟合这幅图、曲线的宽度、用什么loss计算迭代生成图和实际图差异
#3. 把参数设置好执行以下脚本
python painterly_rendering.py imgs/fallingwater.jpg --num_paths 2048 --max_width 4.0 --use_lpips_loss

SVG动画可视化

#1. 把上面生成的svg文件拿出
#2. 用html脚本对生成svg做动画播发可视化
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
	<title>svg path animation</title>
	<style type="text/css">
	.svgContent {
		  width: 100%;
		  max-width: 960px;
		  margin: 0 auto;
		  padding: 0 20px;
	}
	</style>
</head>
<body>
	<div class="svgContent">
		<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="1344" height="768"></svg>
	   <svg xmlns="http://www.w3.org/2000/svg" id="svg" class="svg" viewBox="0 0 1344 768" preserveAspectRatio="xMinYMin meet">
	
		<path d="M 199.27186584472656 -1.17560875415802 C 200.66622924804688 126.04058837890625 193.59605407714844 133.11273193359375 189.6529998779297 86.62046813964844 C 146.4644012451172 53.55277633666992 56.82194900512695 23.302818298339844 89.3664321899414 66.16450500488281" stroke-width="8.0" fill="none" stroke="rgb(0, 255, 255)" stroke-opacity="0.012530866" stroke-linecap="round" stroke-linejoin="round"/> 
	</svg>
    </div>
    <script src="../cobrasvg.js"></script>
	<script src="https://unpkg.com/html2canvas"></script>
<script src="https://unpkg.com/@ffmpeg/ffmpeg"></script>
<script src="https://unpkg.com/@ffmpeg/core"></script>
	<script>
	 

	  /**
 * cobrasvg
 *
 *
 * 一个用来使用SVG的路径(path)来制作动画效果的插件
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright 2015,janily
 *
 */

(function(window) {

'use strict';

/**
 * 针对不支持SVG的浏览器的检测,如果不支持svg的话,会在html元素上添加一个noSvg的class,反之则添加一个svg的class
 * 可以使用这个class来做一些降级处理,如不支持svg的浏览器,则直接显示一张png或者是jpg图片
 * 参考:http://stackoverflow.com/questions/654112/how-do-you-detect-support-for-vml-or-svg-in-a-browser
 */

cobrasvg.prototype._supportSvg = function() {
	return !!document.createElementNS && !! document.createElementNS('http://www.w3.org/2000/svg', "svg").createSVGRect;
}

/* 探测浏览器种类 
 * 使用JavaScript来检测浏览器动画事件是否完成
 * 参考http://davidwalsh.name/css-animation-callback
 */

function whichTransitionEvent() {
	var t;
	var el = document.createElement('fakeelement');
	var transitions = {
		'transition': 'transitionend',
		'OTransition': 'oTransitionEnd',
		'MozTransition': 'transitionend',
		'WebkitTransition': 'webkitTransitionEnd'
	}

	for (t in transitions) {
		if (el.style[t] !== undefined) {
			return transitions[t];
		}
	}
}

var transitionEvent = whichTransitionEvent();
/**
 * 扩展
 */

function extend(a, b) {
	for (var key in b) {
		if (b.hasOwnProperty(key)) {
			a[key] = b[key];
		}
	}
	return a;
}

/**
 * 构造函数
 */

function cobrasvg(options) {
	this.options = extend({}, this.options);
	extend(this.options, options);
	this._init();
}

/**
 * 配置选项
 * 指定要产生动画效果SVG元素的ID,默认为svg
 * 是否开启填充动画效果
 */

cobrasvg.prototype.options = {
	elementId: "svg",    //指定要产生path动画效果的SVG元素的ID
	fillPath: true       //是否开启填充的动画效果
}

/**
 * cobrasvg _init
 * 初始化方法
 */

cobrasvg.prototype._init = function() {
	if (!this._supportSvg()) {
		document.documentElement.className = "noSvg";
	} else {
		document.documentElement.className = "svg";
	}
	this.svg = document.getElementById(this.options.elementId);
	this.fillDraw = this.options.fillPath;
	this.paths = this.svg.querySelectorAll("path");
	this._initAnimation();
}

/**
 * cobrasvg _initAnimation()
 * 动画方法,主要是初始化一些属性的值,首先是获取path元素的长度;
 * 然后设置path的透明度。
 */
cobrasvg.prototype._initAnimation = function() {
	for (var i = 0; i < this.paths.length; i++) {
		var path = this.paths[i];
		var length = path.getTotalLength();

		// 重置透明度
		path.style.fillOpacity = 0;
		path.style.strokeOpacity = 1;

		// 重置transition
		path.style.transition = path.style.transitionEvent = "none";

		// 重置path的strokeDasharray和strokeDashoffset属性
		path.style.strokeDasharray = length + " " + length;
		path.style.strokeDashoffset = length;
		path.getBoundingClientRect();

		// 应用transition
		path.style.transition = path.style.transitionEvent = "stroke-dashoffset 23s ease-in-out";

		// 设置strokeDashoffset的值为0
		path.style.strokeDashoffset = 0;

		// 是否填充路径
		if(this.fillDraw == true) {
			this._fillPath(path);
		}
	}
}

/**
 * cobrasvg _fillPath()
 *
 * 重置transition并设置路径的透明度
 *
 */

cobrasvg.prototype._fillPath = function(path) {
	path.addEventListener(transitionEvent, function() {
		// 重置transition
		path.style.transition = path.style.transitionEvent = "none";
		path.style.transition = path.style.transitionEvent = "fill-opacity 3s ease-in-out, stroke-opacity 3s ease-in-out";

		// 修改透明度
		path.style.fillOpacity = 1;
		path.style.strokeOpacity = 0;
	});
}

/**
 * 添加命名空间
 */

window.cobrasvg = cobrasvg;

})(window);

(function() {
	var myAnimation = new cobrasvg({
	  elementId: "svg"
	});
  })();

	</script>
</body>
</html>

svg_path_draw.mov

Live矢量分层

clip引导矢量作图

diffusion矢量作图

文字矢量

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值