资讯专栏INFORMATION COLUMN

小记-用canvas完成图像液化(向前变形)过程

jone5679 / 2862人阅读

摘要:前几天由于团队需要,折腾了一下图像液化的处理过程。现在来整理一下思路,做个记录。用到公式如下,网上拿来的话不多说,上代码本来想尽量写出点逼格。。。后来发现怎么写也还是几个搞定,就那样了。然后再用的把转换后的输出到中效果图如下

前几天由于团队需要,折腾了一下图像液化的处理过程。
现在来整理一下思路,做个记录。

  

用到公式如下,网上拿来的

  

话不多说,上代码
本来想尽量写出点逼格。。。后来发现怎么写也还是几个function搞定,就那样了。

(function(global) {

    // 计算两点距离平方
    function distanceSqr( x1, y1, x2, y2 ) { return sqr(x1-x2) + sqr(y1-y2); }
    // 计算平方
    function sqr(x) { return x*x; }

    // 遍历一个指定圆内的所有点
    // 通过callback传入回调方法,回调传出每一个点的相关信息
    function eachCircleDot( imageData, ox, oy, r, callback ) {

        var imgWidth    = imageData.width,
            imgHeight   = imageData.height,
            data        = imageData.data,
            left        = ox-r,
            right       = ox+r,
            top         = oy-r,
            bottom      = oy+r,
            dotRedOffset,dotGreenOffset,dotBlueOffset,alphaOffset;

        for( var x = left; x < right; x++ )
            for( var y = top; y < bottom; y++ )

                if( distanceSqr( x, y, ox, oy ) <= sqr(r) ) {

                    dotRedOffset      = y*imgWidth*4+x*4;
                    dotGreenOffset    = dotRedOffset    + 1;
                    dotBlueOffset     = dotGreenOffset  + 1;
                    alphaOffset       = dotBlueOffset   + 1;

                    callback(
                        // 当前点的坐标
                        { x:x, y:y },
                        // 点的RGBA四个分量对应字节的下标
                        {
                            r: dotRedOffset,
                            g: dotGreenOffset,
                            b: dotBlueOffset,
                            a: alphaOffset,
                        },
                        // 传进来的ImageData的data部分
                        data

                    );

                }

    }

    // 复制一个imageData的data到一个buff里
    function copyImageDataBuff( imgData ) {

        var data = imgData.data,
            imgDataBuff = [];

        for( var i in data )
            imgDataBuff[i] = data[i];

        return imgDataBuff;

    }

    // 从buff按照指定坐标复制像素点数据到目标imageData里
    function moveDot( imgData, dataBuff, x, y, srcX, srcY ) {

        var imgWidth    = imgData.width,
            imgHeight   = imgData.height,

            data = imgData.data;

        x = Math.floor(x);
        y = Math.floor(y);

        srcX = Math.floor(srcX);
        srcY = Math.floor(srcY);

        var targetStartOffset   = y*imgHeight*4 + x*4,
            srcStartOffset      = srcY*imgHeight*4 + srcX*4;


        for( var i = 0; i < 4; i++ )
            data[ targetStartOffset + i ] = dataBuff[ srcStartOffset + i ];

    }

    // 执行液化过程
    // imgData  通过canvas的getImageData方法得到的数据对象
    // cx,cy    圆心坐标
    // mx,my    移动目标坐标
    // r        作用半径
    // strength 力度百分比(1-100)
    function liquify( imgData, cx, cy, mx, my, r, strenth ) {

        var imgDataBuff = copyImageDataBuff(imgData);

        eachCircleDot( imgData, cx, cy, r, function( posi ) {

            var tx = posi.x,
                ty = posi.y;


            var u = transFormula( cx, cy, mx, my, tx, ty, r, strenth );


            moveDot( imgData, imgDataBuff, tx, ty, u.x, u.y );


            function transFormula( cx, cy, mx, my, tx, ty, r, strenth ) {


                strenth = strenth || 100;

                var relativity = sqr(r) - distanceSqr( tx, ty, cx, cy );

                var distanceMovedSqr    = distanceSqr( mx, my, cx, cy );

                var rate = sqr( relativity / ( relativity + distanceMovedSqr*(100/strenth) ) );


                var ux = tx - rate * (mx-cx),
                    uy = ty - rate * (my-cy);

                return { x:ux, y:uy };

            }

        });

    }

    // 挂到全局对象
    global.LiquifyFilter = {
        liquify: liquify
    };

})(window);
  

使用它

先用canvas的

getImageData();

方法获取到要处理图片的imageData

全局作用域下调用

LiquifyFilter.liquify( imageData, 圆心X, 圆心Y, 目标点X, 目标点Y, 作用半径, [力度百分比] );

完成转换。

然后再用canvas的

puImageData();

把转换后的imageData输出到canvas中

  

效果图如下

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/49538.html

相关文章

  • 小记-canvas完成图像液化向前变形过程

    摘要:前几天由于团队需要,折腾了一下图像液化的处理过程。现在来整理一下思路,做个记录。用到公式如下,网上拿来的话不多说,上代码本来想尽量写出点逼格。。。后来发现怎么写也还是几个搞定,就那样了。然后再用的把转换后的输出到中效果图如下 前几天由于团队需要,折腾了一下图像液化的处理过程。 现在来整理一下思路,做个记录。 用到公式如下,网上拿来的 showImg(https://segm...

    Cheng_Gang 评论0 收藏0
  • 瘦脸之液化算法

    摘要:对上面公式进行改进,加入变形程度控制变量,改进后瘦脸公式如下,优缺点优点形变思路简单直接缺点局部变形算法,只能基于一个中心点,向另外一个点的方向啦。单点拉伸的变形,可以实现瘦脸的效果,但是效果自然度有待提升。 论文:Interactive Image Warping(1993年Andreas...

    BWrong 评论0 收藏0
  • 前端小记4——高性能mobile web开发

    摘要:高性能动画与端场景需要相比,移动端需要考虑的因素也相对复杂,重点考虑流量功耗与流畅度。而在移动端,我们选择性能更优浏览器原生实现方案动画。然而,动画在移动多终端设备场景下,相比会面对更多的性能问题,主要体现在动画的卡顿与闪烁。1.高性能CSS3动画 与PC端场景需要相比,移动web端需要考虑的因素也相对复杂,重点考虑:流量、功耗与流畅度。在pc端上考虑更多的是流畅度,而mobile web中...

    番茄西红柿 评论0 收藏0
  • 使vue完成微信公众号网页小记

    摘要:前言公司最近有一个页面的功能,比较简单的一个调查表功能,嵌套在我们微信公众号里面。同时用到了微信的登录和分享接口。参考链接使用微信接口前端部分我们用微信接口主要是做的登录和分享功能,首先是上微信公众平台上边看看,把权限搞好之后后端配置。 showImg(https://segmentfault.com/img/bVbrOkH); 前言: 公司最近有一个H5页面的功能,比较简单的一个调查...

    phoenixsky 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<