一、引子

话说前阵子想把一张照片转换成素描,然后发个微博。结果发现mac上没找到能直接转换素描的软件(PS不算,可要好几步呢),坑爹啊~~google 了下,Web上竟然也是没有直接把照片转换成素描的东西,连让我包含期望的美图秀秀(Web版)竟然都没有素描功能,T_T。

手机上是有很多这类app,但是我只是想一键转换下,发个微博嗟,至于这么折腾么……

所以自己动手整一个在线版的吧,没怎么用过canvas,正好可以顺道熟悉下。等不及的童鞋可以先到这里看看效果(http://appx.imatlas.com/sketching/)。

二、怎么转换

刚冒出这个想法的时候,简直是一头雾水诶~数学不行、PS不懂、图形学忘光了……

还好有万能的google,翻了几页,找到一个ps制作素描图片的步骤——虽然我不懂,但是如果按照这个步骤用PS能做成素描,我用代码也一定可以的。嗯,一定是的。

PS里面最简单的一个转换素描的步骤为:

  1. 去色(黑白化)
  2. 复制一份,反相
  3. 把复制后的图层叠加方式设为颜色减淡
  4. 高斯模糊

PS里面的具体步骤我就不详说了,可以看这篇文章。既然知道了实现步骤,我只要用JS把这些算法都实现了就行啦,哇哈哈哈~

三、原理什么的

去色:把图片变成黑白图,只要把每个像素的R、G、B设为亮度(Y)的值就行了。关于R、G、B、Y的关系可以看到这里看看,这里只要记住这条公式:Y = 0.299R + 0.587G + 0.114B。more

反相:就是将一个颜色换成它的补色。补色就是用255(8位通道模式下,255即2的8次方,16位要用65535去减,即2的16次方)减去它本身得到的值:R(补) = 255 - R。

颜色减淡:其计算公式是:结果色 = 基色 + (混合色 * 基色) / (255 - 混合色),在这里找到的这条公式,原理我就不多说了,因为我也不大懂(^_^,图形学睡过去了……)。

高斯模糊:嗯,这个是最让我抓头摸脑的。一开始没怎么理解到这个算法,纠结了两天。最后终于灵光一闪,想通了(还好没晕过去大睡三天~.~)!网上有很多C++的实现,但是基本没找到JS的。一开始不想去理解高斯模糊,就尝试把C++代码改成JS的,改了半天,终于放弃了~想明白之后,自己照原理写了个,想不到还挺容易的,呃……具体的高斯模糊原理,就在这里这里这里看吧,老衲就不误人子弟了。

本项目已经托管到了Github(https://github.com/iazrael/sketching),这几个方法的源码可以到上面查看。稍微提下实现素描的一个注意事项:去色之后需要拷贝一份像素数组备用,开始是用数组的slice方法来拷贝像素数组的,结果经常需要800ms左右的时间;后来尝试了直接用canvas,putImageData之后再调用getImageData来“曲线救国”,结果只用10几毫秒就可完成,简直让老衲老泪纵横诶~其代码如下:

    /**
     * 素描
     * @param  {Object} imgData  
     * @param  {Number} radius 取样区域半径, 正数, 可选, 默认为 3.0
     * @param  {Number} sigma 标准方差, 可选, 默认取值为 radius / 3
     * @return {Array}
     */
    function sketch(imgData, radius, sigma){
        var pixes = imgData.data,
            width = imgData.width, 
            height = imgData.height,
            copyPixes;

        discolor(pixes);//去色
        canvas.width = width, canvas.height = height;
        //复制一份
        ctx.clearRect(0, 0, width, height);
        ctx.putImageData(imgData, 0, 0);
        copyPixes = ctx.getImageData(0, 0, width, height).data;
        // 拷贝数组太慢
        // copyPixes = Array.prototype.slice.call(pixes, 0);
        invert(copyPixes);//反相
        gaussBlur(copyPixes, width, height, radius, sigma);//高斯模糊
        dodgeColor(pixes, copyPixes);//颜色减淡
        return pixes;
    }

四、怎么用

说起用法啊,那你可以问对人了,哈哈。狠狠的敲入app的网址:http://appx.imatlas.com/sketching/(注意只能用现代浏览器(Chrome,Firefox,Opera,Safari等)打开哦,IE9以前的老古董就甭来啦),然后拖拽一张图片到画布区(就是下面打开的灰色地带~),然后……就没有然后啦,最多2秒之后自动生成素描画。点击download按钮可以下载生成的图片。

如果感觉效果不太好,可以改下取样的半径(Sample size),为正整数,最小为1。如果你一定要填负数、小数,也会被取正取整(抠鼻)。之后点下action按钮,生成新的素描图。

如果你还不明白,下面来看图说明(点击图片可以查看大图)。

sketching

斋说都没益啦,实牙实齿效果才是王道,看看下面的原图:

转换后的素描图:

怎么样,效果是不是还不错咧,嘎嘎嘎。当然,这个算法未必是最好的,欢迎各位童鞋踊跃拍砖,^_^

Comments
Write a Comment
  • GabrielLin reply

    亲,美图秀秀网页版有素描的功能哦,在特效->艺术特效里面,很早就有了

  • Tengs reply

    高手!

Tags

css3   魅力CSS   nodejs   loading   CSS   疯狂的菊花   html5   animation   compiler   编译脚本   png   WordPress   智能   旅行   优化   模板   历史记录   跨域   manifest   frame   canvas   动画   js   离线应用   codelet   transform   抽取   java   兼容问题   发布脚本   富文本   那一年在他乡   htaccess   iframe   帧动画   加载速度   intelligent   跨浏览器   DNS解析   插件   checkbox   单边   step-start   vary   复选框   自动更新   转换   文本溢出   盒子阴影   menu   blob   西安   滑动背景   box-shadow   内存占用   键盘事件   python   auto   text overflow   background   所见所得   android   rotate   字节数   合并   文本框   slide   字符串连接符   协议   伪类   兄弟选择符   网格   节点位置比较   空白   斜线拼接   自定义命令   溢出   clock   素描   无法更新   分隔符   字符编码   body   下载文件   精灵图   step   nodej   ubuntu   apache   css3选择器   创建文件   多级菜单   编辑状态   ajax   阴影   垂直   chrome   管道   时钟   firefox   背景   文件上传   createobjecturl   游记   下载   放射渐变   版本号   宽高   照片   localStorage   渐变背景   图片   图片拼接   属性值检测   自动生成   计算   返回键   oauth   合图   reset   调用   cavnas   漏洞   按钮   margin   线性渐变   xsrf   被黑   tab   checked   修复   border   消失   step-end   sprite   common-upload   菜单   兄弟选择器   字符串   svn   九寨沟   缩进   css遮罩   svg   添加系统服务   gzip   插入代码   动态   加速   模拟