<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>canvas &#8211; 萧邦的博客</title>
	<atom:link href="https://www.zlhlab.top/tag/canvas/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.zlhlab.top</link>
	<description>If not me who, If not now when</description>
	<lastBuildDate>Wed, 30 Jul 2025 06:52:52 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.6</generator>
	<item>
		<title>中国人保在线理赔小程序</title>
		<link>https://www.zlhlab.top/%e4%b8%ad%e5%9b%bd%e4%ba%ba%e4%bf%9d%e5%9c%a8%e7%ba%bf%e7%90%86%e8%b5%94%e5%b0%8f%e7%a8%8b%e5%ba%8f/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Wed, 30 Jul 2025 05:41:12 +0000</pubDate>
				<category><![CDATA[APP]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[实时音视频]]></category>
		<category><![CDATA[小程序]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=684</guid>

					<description><![CDATA[人保理赔小程序是一款远程视频实时报案、留存、在线签章的小程序，帮助客户实现快捷理赔。 小程序技术方案 小程序设<div class="more-link">
				 <a href="https://www.zlhlab.top/%e4%b8%ad%e5%9b%bd%e4%ba%ba%e4%bf%9d%e5%9c%a8%e7%ba%bf%e7%90%86%e8%b5%94%e5%b0%8f%e7%a8%8b%e5%ba%8f/" class="link-btn theme-btn"><span>Read More </span> <i class="fa fa-caret-right"></i></a>
			</div>]]></description>
										<content:encoded><![CDATA[
<p>人保理赔小程序是一款远程视频实时报案、留存、在线签章的小程序，帮助客户实现快捷理赔。</p>



<p><strong>小程序技术方案</strong></p>



<ol class="wp-block-list">
<li>小程序采用<a href="https://cloud.tencent.com/solution/video">腾讯云音视频解决方案</a>，实现多客服在线远程直播报案，支持远程抓拍留存；</li>



<li>支持多文档展示和基于canvas进行在线手写签名授权；</li>
</ol>



<p><strong>小程序设计稿</strong></p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="332" height="1024" src="https://www.zlhlab.top/wp-content/uploads/2025/07/picc-332x1024.jpg" alt="" class="wp-image-687" srcset="https://www.zlhlab.top/wp-content/uploads/2025/07/picc-332x1024.jpg 332w, https://www.zlhlab.top/wp-content/uploads/2025/07/picc-97x300.jpg 97w, https://www.zlhlab.top/wp-content/uploads/2025/07/picc-768x2369.jpg 768w, https://www.zlhlab.top/wp-content/uploads/2025/07/picc-498x1536.jpg 498w, https://www.zlhlab.top/wp-content/uploads/2025/07/picc-664x2048.jpg 664w, https://www.zlhlab.top/wp-content/uploads/2025/07/picc-scaled.jpg 830w" sizes="(max-width: 332px) 100vw, 332px" /></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>为双十一疯狂打CALL</title>
		<link>https://www.zlhlab.top/%e4%b8%ba%e5%8f%8c%e5%8d%81%e4%b8%80%e7%96%af%e7%8b%82%e6%89%93call/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Wed, 17 Jan 2018 15:39:08 +0000</pubDate>
				<category><![CDATA[H5]]></category>
		<category><![CDATA[canvas]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=512</guid>

					<description><![CDATA[这是一款名叫“为双十疯狂打CALL”的H5小游戏。产生背景：网易的互动H5小游戏刷爆朋友圈，刚好项目处于空档期。]]></description>
										<content:encoded><![CDATA[<h4>项目背景：</h4>
<p>这是一款名叫“为双十疯狂打CALL”的H5小游戏。产生背景：网易的互动H5小游戏刷爆朋友圈，刚好项目处于空档期。于是策划和设计找了一些游戏关卡，我这边进行技术实现。</p>
<h4>项目技术：</h4>
<p>整体项目采用canvas绘图展示+手指触摸检测+碰撞检测+输入控件，以及控制场景切换。</p>
<p>需要注意：<strong>canvas高倍像素屏幕图片展示</strong>和<strong>机型适配</strong>。</p>
<h4>项目设计：</h4>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2018/01/call-1.jpg" alt=""></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>驭胜S330新车上市H5</title>
		<link>https://www.zlhlab.top/%e9%a9%ad%e8%83%9cs330%e6%96%b0%e8%bd%a6%e4%b8%8a%e5%b8%82h5/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Wed, 11 Oct 2017 14:42:32 +0000</pubDate>
				<category><![CDATA[H5]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[iScroll]]></category>
		<category><![CDATA[swiper]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=349</guid>

					<description><![CDATA[这个H5项目是给驭胜S330新车上市做的。项目开屏信封进入，点击进入，随手指滚动进行场景和内容展现。场景采用手绘动效的。还包含展示车型详情、活动规则、预约试驾以及中奖结果页面。]]></description>
										<content:encoded><![CDATA[<h4><strong>项目描述</strong></h4>
<hr>
<p>这个H5项目是给驭胜S330新车上市做的。项目开屏信封进入，点击进入，随手指滚动进行场景和内容展现。场景采用手绘动效的。还包含展示车型详情、活动规则、预约试驾以及中奖结果页面。</p>
<h4><strong>技术选型和方案</strong></h4>
<hr>
<p>项目有4处采用了flash动画（开屏页、滚动页3处）。由于IOS和安卓的特性，手机对flash的支持各异。初步进行flv-&gt;MP4视频，然后使用PS将视频转成单张图片（使用gif或者制作精灵图，机型不同手机内存和性能展现结果不一）。</p>
<p>技术方案和问题解决如下：</p>
<p>1、加载和缓存动画图片；<br />
2、采用canvas播放，播放缓存图片（750&#215;1206），实现帧动画；<br />
3、解决canvas播放动画手机端模糊问题，使用下面的解决方案：</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var getPixelRatio = function(context) {
  var backingStore = context.backingStorePixelRatio ||
    context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio || 1;
   return (window.devicePixelRatio || 1) / backingStore;
};

//调用
var ratio = getPixelRatio(ctx);
</code></pre>
<p>4、使用iscroll-prob.js实现基于位置滚动加载；<br />
5、使用swiper实现详情页的动态展示。解决swiper安卓机型滑动问题，修改参数如下：</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">observer: true,//修改swiper自己或子元素时，自动初始化swiper  
observeParents: true,//修改swiper的父元素时，自动初始化swiper  
</code></pre>
<h4><strong>待优化</strong></h4>
<hr>
<p>项目已进行了优化，基本满足客户上线需求。</p>
<p>1.由于存在大量图片加载，会出现页面99%的时间较长。如果加载更平滑一些，loading页面看起来会自然一些。<br />
2.后续建议：针对简单的帧动画能用代码实现，尽量用代码实现，减少使用图片。</p>
<h4><strong>设计与发布地址</strong></h4>
<hr>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/10/%E6%A1%88%E4%BE%8B%E5%9B%BE-%E9%A9%AD%E8%83%9C-1.jpg" alt=""></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>前端图像处理指南</title>
		<link>https://www.zlhlab.top/%e5%89%8d%e7%ab%af%e5%9b%be%e5%83%8f%e5%a4%84%e7%90%86%e6%8c%87%e5%8d%97/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Fri, 29 Sep 2017 02:55:01 +0000</pubDate>
				<category><![CDATA[技术]]></category>
		<category><![CDATA[推荐]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[css3]]></category>
		<category><![CDATA[图像处理]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=333</guid>

					<description><![CDATA[本文会介绍canvas位图处理，SVG矢量图和CSS3图像处理，重点是canvas，并且最后会附上一个[TrimPNG小应用]]]></description>
										<content:encoded><![CDATA[<p>计算机图像处理是一门很成熟的技术，任何一门可操作系统接口的语言都能很轻易的实现各种处理操作。但是前端限于浏览器环境和接口限制，处理起来会有诸多不便，这里所说的前端图像处理，是真的指不借助任何后端服务纯前端实现的图像处理。本文会介绍canvas位图处理，SVG矢量图和CSS3图像处理，重点是canvas，并且最后会附上一个<a href="http://quanfeng.tech/trimpng/" title="TrimPNG小应用" target="_blank">TrimPNG小应用</a>。</p>
<h4><strong>1. canvas位图处理</strong></h4>
<hr>
<p>HTML5 canvas为我们提供了一块画布，让前端也有了操作位图的功能：图片旋转、缩放、滤镜、压缩等都可以通过JS来实现。</p>
<p><strong>图像基本处理</strong></p>
<p>通过设置drawImage参数可以实现图片绘制、缩放、拉伸和裁剪等操作(注意: canvas无法绘制体积过大图片，否则会卡甚至崩掉，大图可以分块读取绘制)：</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/canvas_drawImage_DEMO_-_JS_Bin.png-q80.png" alt="图像基本处理" title="图像基本处理"></p>
<blockquote><p>
  详细用法参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage" title="drawImage()" target="_blank">drawImage()</a>，DEMO源码戳这里 <a href="http://jsbin.com/nuqojowayi/edit?html,output" title="JS Bin" target="_blank">JS Bin</a>.
</p></blockquote>
<p>只需要drawImage一个方法，就可以实现基本图形处理功能，再结合鼠标或滚轮事件，就可以实现更复杂的局部放大预览，缩放等功能了。</p>
<p><strong>图像滤镜处理</strong></p>
<p>现在的朋友圈发个图都要用滤镜美一下，复古清纯胶片LOMO各种风格应有尽有。canvas提供了getImageData方法来获取图像上每一个像素点的RGBA信息，这样我们就能对图片进行像素级处理了。通过特定算法来重写imageData中的像素信息，然后用setImageData方法把新的数据重新绘制在canvas上，这样就可以实现图像滤镜打码加特效等一系列功能。</p>
<p>比如我们现在要实现一个复古滤镜:</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 复古滤镜处理算法：获取每个像素的RGB信息，并按特定权重返回其加权平均值
let sepiaFilter = function(imgData) {
  let d = imgData.data
  for (let i = 0; i &lt; d.length; i += 4) {
    let r = d[i]
    let g = d[i + 1]
    let b = d[i + 2]
    d[i] = (r * 0.393) + (g * 0.769) + (b * 0.189) // red
    d[i + 1] = (r * 0.349) + (g * 0.686) + (b * 0.168) // green
    d[i + 2] = (r * 0.272) + (g * 0.534) + (b * 0.131) // blue
  }
  return imgData
}
//图像地址必须和当前页面同域，否则会报cross-origin错误 
img.src = '/img/logo@2x.png' 
img.onload = () =&gt; {
  ctx.drawImage(img, 0, 0) // 绘制原图
  let imgData = ctx.getImageData(0, 0, img.width, img.height) // 获取图片信息
  ctx.putImageData(sepiaFilter(imgData), 100, 0) // 绘制处理后图片
}
</code></pre>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/3834833829-58706ff1760a3_articlex.png" alt="图像滤镜处理" title="图像滤镜处理"></p>
<blockquote><p>
  详细用法参考 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/getImageData" title="getImageData() " target="_blank">getImageData() </a>和 <a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/putImageData" title="putImageData()" target="_blank">putImageData()</a>，DEMO源码戳这里 <a href="https://jsfiddle.net/vghszt61/2/" title="JSFiddle" target="_blank">JSFiddle</a>
</p></blockquote>
<p>滤镜处理关键在于滤镜算法，要想写出更高级的特效需要有计算机图形学基础，对卷积矩阵、拉普拉斯变换、傅里叶变换等数学知识也要了解，这个坑很大我就不挖了。</p>
<p><strong>图像base64存储</strong><br />
加完特效后如果我们想把图像保存下来，就可以用toDataURL方法来对图片进行格式转换、压缩存储了。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">// 支持三种文件类型：image/png(默认) | image/jpeg | image/webp(仅Chrome)
canvas.toDataURL() // 默认存储为png
// 仅jpeg/webp支持质量参数(0~1,默认0.92)
canvas.toDataURL("image/jpeg", 0.1) // 存储为质量为0.1的jpeg
</code></pre>
<p>由于存储形式是base64编码，原来图片的每三个字节都会被扩展成4字节，所以整体上编码后数据会比原来多约1/3。以下是通过toDataURL存储后的图片和原图大小相关对比数据(数据仅供参考，不具通用性)：</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/yy.jpg" alt="图像base64存储" title="图像base64存储"></p>
<p>可见存储后图片体积并不是原来的4/3，实际上处理后的图片都会比原图大好几倍，并且不同的图片增大的体积也是不确定的。如果是要上传图片到服务器，可以把base64转化成Blob二进制数据压缩上传；如果要直接在前端显示或供用户下载，jpg还好可以设置质量参数，要是png就没法压缩了。</p>
<p>只是用toDataURL还不够，用户需要通过手动点击图片-右键图片存储为来保存图片，如果要实现点击下载按钮自动下载图片还需要修改图片类型为octet-stream，然后利用HTML5的download属性强制让浏览器下载。</p>
<blockquote><p>
  详细用法参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toDataURL" title="toDataURL()" target="_blank">toDataURL()</a>. 自动下载图片DEMO源码快戳我 <a href="https://jsfiddle.net/0326/vghszt61/4/#" title="JSFiddle" target="_blank">JSFiddle</a>.
</p></blockquote>
<p><strong>程序员的备胎</strong></p>
<p>有了以上基础，再结合成熟的图形处理算法，我们可以完成日常工作中大部分图像处理需求，以下列出了一些相关轮子可做备胎。备胎这种东西多多益善，万一以后用到了呢？</p>
<p><a href="http://html2canvas.hertzen.com/documentation.html" title="html2canvas" target="_blank"><strong>html2canvas</strong></a></p>
<p>将web页面通过canvas来实现截屏，其原理就是遍历DOM结构和样式，然后在canvas中绘制出来，通过toDataURL输出图片。但由于canvas图片的同源策略限制，如果图片和网站不同源的话会截取不出来的。另外在微信中测试时，即使用同源的图片截取出来的图片也有问题，所以要想将其用于生产环境，还是得看场景，有很多坑要踩。</p>
<p><a href="https://github.com/akira-cn/code-to-image" title="code-to-image" target="_blank"><strong>code-to-image</strong></a></p>
<p>代码转图片工具。有时候你在不同的平台写文章贴代码，由于不同平台代码格式化规范不一，所以经常会出现代码排版问题，通过这个工具将代码转成图片就可以避免排版问题了。</p>
<p><a href="https://fengyuanchen.github.io/cropper/" title="Cropper" target="_blank"><strong>Cropper</strong></a></p>
<p>一个专门用来做图片裁剪的应用。</p>
<p><a href="https://github.com/eduardolundgren/tracking.js/" title="tracking.js" target="_blank"><strong>tracking.js</strong></a></p>
<p>这是一个专业的计算机视觉处理JS库，包含了大量图形处理算法，可用来做人脸识别，色彩追踪等酷炫功能。</p>
<p><a href="https://github.com/nicolaszhao/qrcode2" title="qrcode2" target="_blank"><strong>qrcode2</strong></a></p>
<p>用JS动态生成二维码，这个库还是很实用的，原理就是qrcode算法+canvas绘图，不支持canvas的用table兼容。</p>
<p><a href="https://github.com/AlloyTeam/AlloyImage" title="AlloyImage" target="_blank"><strong>AlloyImage</strong></a><br />
腾讯出的基于HTML5的专业级图像处理开源引擎，功能很强大，简直就是Web版的PS。</p>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/09/TB1qqF.PXXXXXXFXXXXXXXXXXXX-1381-597.png" title="AlloyImage" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/TB1qqF.PXXXXXXFXXXXXXXXXXXX-1381-597.png" alt="AlloyImage" title="AlloyImage"></a></p>
<p>以上列举部分，更多备胎在此： <a href="https://github.com/0326/canvas" title="https://github.com/0326/canvas" target="_blank">https://github.com/0326/canvas</a></p>
<h4><strong>2. SVG矢量图处理</strong></h4>
<hr>
<p>讲完位图再说矢量图。矢量图在绘制图标、商业LOGO、动画元素上应用非常广范。Web最开始支持的矢量图形并不是现在的SVG，而是微软主推的VML，所以在低版本IE下面只支持VML而不支持SVG，直到后来SVG成为W3C标准并被普及，微软才在IE9中支持SVG。</p>
<p>SVG遵循XML规范，可以很好的集成在HTML里面，同时支持JS脚本控制，还有基于SMIL标准的动态内容支持，做起动画来也是非常方便。目前基于SVG的JS图形库轮子也是非常多，如svg.js, Snap.svg, Velocity.js, D3.js等等，目前暂无SVG应用需求，等用的时候再翻牌子吧。</p>
<h4><strong>3. CSS图像处理</strong></h4>
<hr>
<p>如果你的图像特效只是用来给用户展示，并不需要存储的话，可以直接用CSS处理，基本的调整图片大小、拉伸、旋转、裁切等操作直接几个CSS属性width/height/skew/rotate/clip-path等就能搞定了。如果想加特效，使用CSS滤镜Duang的一下就出来了，不需要任何图形学基础和数学知识：</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/591D15F1-F2EB-410A-983B-62F698769406.jpg" alt="CSS图像处理" title="CSS图像处理"></p>
<blockquote><p>
  详细说明见 <a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/filter" title="CSS filter - MDN" target="_blank">CSS filter &#8211; MDN</a>, <a href="http://jsbin.com/cejifa/edit?html,output" title="DEMO 源码见JS Bin" target="_blank">DEMO 源码见JS Bin</a>.
</p></blockquote>
<h4><strong>4. 总结</strong></h4>
<hr>
<p>最后介绍个小工具TrimPNG。大家都知道TinyPNG可以压缩PNG, TrimPNG顾名思义就是去除图片空白和白边的，实现了自动抠图和切图的功能（logo我是直接抄的TinyPNG，都是熊猫，应该不要紧?）</p>
<p><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/448077878-5871e8180d77c_articlex.png" alt="TrimPng" title="TrimPng"></p>
<p>用到的技术点上面都说到了，裁切实现原理就是横向纵向分别扫描两次像素点阵，找出上下左右最外面的非透明点，然后定位出有效图像区域。<del>去除白边算法目前还比较傻逼，只要是接近白色的点都被我干掉了，后面再完善好了</del> 去白边算法优化了一下，采用标记清除策略（听着耳熟吧，其实就是从GC受的启发&#8230;），先扫描一遍标记出可疑白点，然后再扫描一遍，凡是与透明区域相邻的可疑白点就清除，当然这个算法也比较死，如果有更专业更智能的请务必告诉我。</p>
<p>体验地址：<a href="http://quanfeng.tech/trimpng/" title="http://quanfeng.tech/trimpng/" target="_blank">http://quanfeng.tech/trimpng/</a></p>
<p>本文仅作技术分享和学习。原文地址：<a href="https://segmentfault.com/a/1190000008044204" title="https://segmentfault.com/a/1190000008044204" target="_blank">https://segmentfault.com/a/1190000008044204</a>。</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Face++人脸检测与识别初试</title>
		<link>https://www.zlhlab.top/face%e4%ba%ba%e8%84%b8%e6%a3%80%e6%b5%8b%e4%b8%8e%e8%af%86%e5%88%ab%e5%88%9d%e8%af%95/</link>
		
		<dc:creator><![CDATA[萧邦]]></dc:creator>
		<pubDate>Thu, 07 Sep 2017 15:37:14 +0000</pubDate>
				<category><![CDATA[技术]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[html]]></category>
		<category><![CDATA[人脸检测]]></category>
		<guid isPermaLink="false">https://www.zlhlab.top/?p=292</guid>

					<description><![CDATA[项目背景： 最近被人民日报换军装的H5刷爆朋友圈，于是有汽车厂商想做类似的项目。用于旅游照片换脸分享朋友圈，植<div class="more-link">
				 <a href="https://www.zlhlab.top/face%e4%ba%ba%e8%84%b8%e6%a3%80%e6%b5%8b%e4%b8%8e%e8%af%86%e5%88%ab%e5%88%9d%e8%af%95/" class="link-btn theme-btn"><span>Read More </span> <i class="fa fa-caret-right"></i></a>
			</div>]]></description>
										<content:encoded><![CDATA[<h4>项目背景：</h4>
<p>最近被人民日报换军装的H5刷爆朋友圈，于是有汽车厂商想做类似的项目。用于旅游照片换脸分享朋友圈，植入汽车公众号进行宣传。</p>
<p>可是之前没有类似的项目经验，于是搜集相关代码和当前人脸识别市场进行调研。主要有以下几大阵营：</p>
<blockquote>
<ol>
<li>Face++<a href="https://www.faceplusplus.com.cn/" title="https://www.faceplusplus.com.cn/" target="_blank">https://www.faceplusplus.com.cn/</a></li>
<li>腾讯优图和天天P图。天天P图和腾讯优图是不同部门负责<a href="http://open.youtu.qq.com/welcome/experience" title="http://open.youtu.qq.com/welcome/experience" target="_blank">http://open.youtu.qq.com/welcome/experience</a></li>
<li>百度AI开发平台<a href="http://ai.baidu.com/tech/face" title="http://ai.baidu.com/tech/face" target="_blank">http://ai.baidu.com/tech/face</a></li>
<li>其他阵营，如美图秀秀等</li>
</ol>
</blockquote>
<p>人民日报换军装的H5，就是由天天P图公司制作的。</p>
<h4>对比API和技术支持</h4>
<p>Face++、腾迅优图API以及百度AI平台图像处理方面产品线都比较全，都在进行产品线更新。</p>
<ol>
<li>首先联系的Face++, Face++不支持换军装定制开发。</li>
<li>然后联系腾讯优图，说会转个天天P图的同事，然后一直没有回音。</li>
<li>最后在腾讯优图找到了换军装的Demo，里面找到了作者联系方式，报价10+万。</li>
<li>没有联系百度公司。</li>
</ol>
<p>估计成本太高，客户后面就没有了反馈。<br />
等待总是漫长的，作为技术总是爱折腾和尝试。以下是进行的折腾之旅：</p>
<h4>思路一 Face++背景融合：</h4>
<p>用户上传个人全身照，选择场景进行图片叠加处理。</p>
<h5>1. 注册开发者获取api_key和api_secret</h5>
<p>进行接口权限认证和数据请求需要用到。</p>
<h5>2. 上传原始图片</h5>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/09/facetest2.jpg" title="facetest2" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/facetest2.jpg" alt="facetest2" title="facetest2"></a></p>
<h5>3. 获取灰度图</h5>
<p>发送原始图片，获取返回的灰度图。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var params = $('form').serializeArray();
$.ajax({
    url: 'https://api-cn.faceplusplus.com/humanbodypp/beta/segment',
    type: 'POST',
    data: params,
    dataType: 'json',
    success: function(data){
        console.log(data);
        var grayImg =  'data:image/jpeg;base64,'+data.result;
        $('#resultImg').attr('src', grayImg);
        $('#addedImg').attr('src', clipImgWithGrayImg( grayImg));
    },
    error: function (msg) {
        console.log(msg);
    }
});
</code></pre>
<p>调用接口返回二进制数据流，增加<code>data:image/jpeg;base64,</code>前缀，即可使用<code>img</code>读取图片。</p>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/09/2Q.jpg" title="灰度图" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/2Q.jpg" alt="灰度图" title="灰度图"></a></p>
<h5>4. 裁剪原始图片与背景图片融合</h5>
<p>根据获取的灰度图，使用canvas对原图进行像素级操作，裁剪原图。针对非人像部分，进行像素透明操作。可以进行对边界部分进行参数调节操作，如下：</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">&lt;!-- 已知灰度图裁切原始图片 --&gt;
function clipImgWithGrayImg(grayImg) {
    var canvas = document.getElementById("myCanvas");
    var image = document.getElementById("resultImg");
    image.crossOrigin="Anonymous";

    &lt;!-- 将得到的图像绘制在Canvas对象中的代码如下：--&gt;
        canvas.width=image.width;
    canvas.height=image.height;
    var ctx=canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    &lt;!-- 从Canvas对象中获取图像像素数据的代码如下：--&gt;

        var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    &lt;!-- 读取像素值与实现灰度计算的代码如下：--&gt;

        for ( var x = 0; x &lt; canvasData.width; x++) {
            for ( var y = 0; y &lt; canvasData.height; y++) {

                // Index of the pixel in the array
                var idx = (x + y * canvasData.width) * 4;
                var r = canvasData.data[idx + 0];
                var g = canvasData.data[idx + 1];
                var b = canvasData.data[idx + 2];

                if (r &lt; 128 || g &lt; 128 || b &lt; 128) {
                    canvasData.data[idx + 3] = 0; // Alpha channel
                }
            }
        }

    var data = canvasData.data;
    ctx.clearRect(0,0, canvas.width, canvas.height);
    var srcImage = document.getElementById("srcImg");
    ctx.drawImage(srcImage, 0, 0);
    srcImage.crossOrigin="Anonymous";

    &lt;!-- 从Canvas对象中获取图像像素数据的代码如下：--&gt;
        var canvasData2 = ctx.getImageData(0, 0, canvas.width, canvas.height);

    for ( var j = 0; j &lt; canvasData2.width; j++) {
        for ( var k = 0; k &lt; canvasData2.height; k++) {
            // Index of the pixel in the array
            var idx = (j + k * canvasData2.width) * 4;
            canvasData2.data[idx + 3] = data[idx + 3];
        }
    }

    ctx.putImageData(canvasData2,0,0);
    return canvas.toDataURL();
}

</code></pre>
<p>与背景图合成结果：</p>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/09/4R@3TD56IKKS46T6DC1.png" title="图像融合" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/4R@3TD56IKKS46T6DC1.png" alt="图像融合" title="图像融合"></a></p>
<p>总结：边界判断还需要优化，不能够满足商用的完美融合需求。</p>
<h4>思路二 人脸检测与人脸替换：</h4>
<p>使用换脸的正常流程： 人脸检测&#8211;&gt;人脸特征提取&#8211;&gt;模型脸型匹配&#8211;&gt;替换人脸&#8211;&gt;肤色更换</p>
<h5>1. 获取人脸检测数据</h5>
<p>上传图片，调用人脸检测的接口，获取人脸特征数。</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">var params = $('form').serializeArray();
$.ajax({
    url: 'https://api-cn.faceplusplus.com/facepp/v3/detect', // 人脸检测API
    type: 'POST',
    data: params,
    dataType: 'json',
    crossDomain: true,
    success: function(data){
        console.log(data);
        if (data.faces.length &gt; 0) {
            drawFace(data.faces[0].face_rectangle, data.faces[0].landmark);
        }
    },
    error: function (msg) {
        console.log(msg);
    }
});
</code></pre>
<h5>2. 识别人脸</h5>
<p>调用Face++人脸识别接口，返回的特征可以正常匹配，但是人脸的位置异常。</p>
<p><a href="https://www.zlhlab.top/wp-content/uploads/2017/09/WL311WKAIBD_2S1@9HW.png" title="人脸识别" target="_blank"><img decoding="async" src="https://www.zlhlab.top/wp-content/uploads/2017/09/WL311WKAIBD_2S1@9HW.png" alt="人脸识别" title="人脸识别"></a></p>
<p>代码如下：</p>
<pre class="line-numbers prism-highlight" data-start="1"><code class="language-javascript">&lt;!-- 显示面部区域draw face --&gt;
function drawFace(rect, landmark) {
    var canvas = document.getElementById("myCanvas");
    var image = document.getElementById("srcImg");
    image.crossOrigin="Anonymous";
    var points = [
        {'x': landmark.contour_left1.x, 'y':landmark.contour_left1.y},
        {'x': landmark.contour_left2.x, 'y':landmark.contour_left2.y},
        {'x': landmark.contour_left3.x, 'y':landmark.contour_left3.y},
        {'x': landmark.contour_left4.x, 'y':landmark.contour_left4.y},
        {'x': landmark.contour_left5.x, 'y':landmark.contour_left5.y},
        {'x': landmark.contour_left6.x, 'y':landmark.contour_left6.y},
        {'x': landmark.contour_left7.x, 'y':landmark.contour_left7.y},
        {'x': landmark.contour_left8.x, 'y':landmark.contour_left8.y},
        {'x': landmark.contour_left9.x, 'y':landmark.contour_left9.y},
        {'x': landmark.contour_chin.x, 'y':landmark.contour_chin.y},
        {'x': landmark.contour_right9.x, 'y':landmark.contour_right9.y},
        {'x': landmark.contour_right8.x, 'y':landmark.contour_right8.y},
        {'x': landmark.contour_right7.x, 'y':landmark.contour_right7.y},
        {'x': landmark.contour_right6.x, 'y':landmark.contour_right6.y},
        {'x': landmark.contour_right5.x, 'y':landmark.contour_right5.y},
        {'x': landmark.contour_right4.x, 'y':landmark.contour_right4.y},
        {'x': landmark.contour_right3.x, 'y':landmark.contour_right3.y},
        {'x': landmark.contour_right2.x, 'y':landmark.contour_right2.y},
        {'x': landmark.contour_right1.x, 'y':landmark.contour_right1.y},
        {'x': landmark.right_eyebrow_right_corner.x, 'y':landmark.right_eyebrow_right_corner.y},
        {'x': landmark.right_eyebrow_upper_middle.x, 'y':landmark.right_eyebrow_upper_middle.y},
        {'x': landmark.left_eyebrow_upper_middle.x, 'y':landmark.left_eyebrow_upper_middle.y},
        {'x': landmark.left_eyebrow_left_corner.x, 'y':landmark.left_eyebrow_left_corner.y}
    ];

    &lt;!-- 将得到的图像绘制在Canvas对象中的代码如下：--&gt;
        canvas.width=image.width;
    canvas.height=image.height;
    var ctx=canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    ctx.beginPath();
    ctx.rect(rect.top, rect.left, rect.width, rect.height);
    $.each(points, function (index, item) {
        if (index === 0) {
            ctx.moveTo(item.x, item.y);
        } else {
            ctx.lineTo(item.x, item.y);
        }
    });
    ctx.closePath();
    ctx.strokeStyle = "green";
    ctx.stroke();
}
</code></pre>
<h5>3. 人脸替换</h5>
<p>待完成</p>
<h5>4. 制作滤镜，更换肤色</h5>
<p>待完成</p>
<h4>总结</h4>
<p>换脸H5中，还是有过程需要完成。当前主要涉及Face++的接口调用和Canvas图片处理能力。商用过程，还有很多情况需要考虑，比如人脸位置检测与校验、滤镜换肤。听说腾讯优图1个月左右会开放换脸API，敬请期待。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
