zoukankan      html  css  js  c++  java
  • 小记-用canvas完成图像液化(向前变形)过程

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

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

    image_thumb_1.png

    image_thumb_2.png

    话不多说,上代码
    本来想尽量写出点逼格。。。后来发现怎么写也还是几个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);
    

    使用它

    1. 先用canvas的

      getImageData();
      

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

    2. 全局作用域下调用

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

      完成转换。

    3. 然后再用canvas的

      puImageData();
      

      把转换后的imageData输出到canvas中

    效果图如下

    图片描述

  • 相关阅读:
    虚函数
    class与struct的区别
    HTTP是什么连接
    长连接与短连接
    多线程的主要优点
    overload、override、overwrite的介绍
    常用的Linux命令
    IO模型——IO多路复用机制
    栈区与堆区的区别
    软链接和硬链接到底有啥区别
  • 原文地址:https://www.cnblogs.com/10manongit/p/12677791.html
Copyright © 2011-2022 走看看