Javascript图像处理之平滑处理

  原理来自Justany_WhiteSnowJavascript图像处理——平滑处理一文。

/*

 * BORDER_REPLICATE:     aaaaaaaa|abcdefgh|hhhhhhhh

 * BORDER_REFLECT:       hgfedcba|abcdefgh|hgfedcba

 * BORDER_REFLECT_101:   hgfedcb|abcdefgh|gfedcba

 * BORDER_WRAP:          efgh|abcdefgh|abcd

 * BORDER_CONSTANT:      iiiiiiii|abcdefgh|iiiiiiii  with some specified 'i'(default value [0, 0, 0, 255])

*/



(function () {

    function imageBlur(iCanvas, url, borderType, orientation, blurType, value) {

        this.canvas = iCanvas;

        this.iCtx = this.canvas.getContext("2d");

        this.url = url;

        this.borderType = borderType;

        this.orientation = orientation || "bottom";

        this.value = value || [0, 0, 0, 255];

        this.blurType = blurType || "blur";

    }



    imageBlur.prototype = {

        imread: function (_image) {

            var width = _image.width,

                height = _image.height;

            this.iResize(width, height);

            this.iCtx.drawImage(_image, 0, 0);

            var imageData = this.iCtx.getImageData(0, 0, width, height),

                tempMat = new Mat(height, width, imageData.data);

            imageData = null;

            this.iCtx.clearRect(0, 0, width, height);

            return tempMat;

        },

        iResize: function (_width, _height) {

            this.canvas.width = _width;

            this.canvas.height = _height;

        },

        RGBA2ImageData: function (_imgMat) {

            var width = _imgMat.col,

                height = _imgMat.row;

            var imageData = this.iCtx.createImageData(width, height);

            imageData.data.set(_imgMat.data);

            return imageData;

        },

        render: function () {

            var img = new Image();

            var _this = this;

            img.onload = function () {

                var myMat = _this.imread(img);

                var newImage = null;

                if (_this.blurType == "blur") {

                    newImage = blur(myMat, 11, 11, _this.borderType);

                } else if (_this.blurType == "median") {

                    newImage = medianBlur(myMat, 11, 11, _this.borderType);

                } else {

                    newImage = GaussianBlur(myMat, 11, 11, 0, 0, _this.borderType);

                }

                var newIamgeData = _this.RGBA2ImageData(newImage);

                _this.iCtx.putImageData(newIamgeData, 0, 0);

            };

            img.src = this.url;

        }

    };



    function Mat(_row, _col, _data, _buffer) {

        this.row = _row || 0;

        this.col = _col || 0;

        this.channel = 4;

        this.buffer = _buffer || new ArrayBuffer(_row * _col * 4);

        this.data = new Uint8ClampedArray(this.buffer);

        _data && this.data.set(_data);

        this.bytes = 1;

        this.type = "CV_RGBA";

    }



    function blur(__src, __size1, __size2, __borderType, __dst) {

        if (__src.type && __src.type == "CV_RGBA") {

            var height = __src.row,

                width = __src.col,

                dst = __dst || new Mat(height, width, __src.data),

                dstData = dst.data;

            var size1 = __size1 || 3,

                size2 = __size2 || size1,

                size = size1 * size2;

            if (size1 % 2 !== 1 || size2 % 2 !== 1) {

                console.error("size大小必须是奇数");

                return __src;

            }

            var startX = Math.floor(size1 / 2),

                startY = Math.floor(size2 / 2);

            var withBorderMat = copyMakeBorder(__src, startY, startX, 0, 0, __borderType),

                mData = withBorderMat.data,

                mWidth = withBorderMat.col;



            var newValue, nowX, offsetY, offsetI;

            var i, j, c, y, x;



            for (i = height; i--;) {

                offsetI = i * width;

                for (j = width; j--;) {

                    for (c = 3; c--;) {

                        newValue = 0;

                        for (y = size2; y--;) {

                            offsetY = (y + i) * mWidth * 4;

                            for (x = size1; x--;) {

                                nowX = (x + j) * 4 + c;

                                newValue += mData[offsetY + nowX];

                            }

                        }

                        dstData[(j + offsetI) * 4 + c] = newValue / size;

                    }

                    dstData[(j + offsetI) * 4 + 3] = mData[offsetY + startY * mWidth * 4 + (j + startX) * 4 + 3];

                }

            }



        } else {

            console.error("不支持类型。");

        }

        return dst;

    }



    function getGaussianKernel(__n, __sigma) {

        var SMALL_GAUSSIAN_SIZE = 7,

            smallGaussianTab = [[1],

                                [0.25, 0.5, 0.25],

                                [0.0625, 0.25, 0.375, 0.25, 0.0625],

                                [0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125]

            ];



        var fixedKernel = __n & 2 == 1 && __n <= SMALL_GAUSSIAN_SIZE && __sigma <= 0 ? smallGaussianTab[__n >> 1] : 0;



        var sigmaX = __sigma > 0 ? __sigma : ((__n - 1) * 0.5 - 1) * 0.3 + 0.8,

            scale2X = -0.5 / (sigmaX * sigmaX),

            sum = 0;



        var i, x, t, kernel = [];



        for (i = 0; i < __n; i++) {

            x = i - (__n - 1) * 0.5;

            t = fixedKernel ? fixedKernel[i] : Math.exp(scale2X * x * x);

            kernel[i] = t;

            sum += t;

        }



        sum = 1 / sum;



        for (i = __n; i--;) {

            kernel[i] *= sum;

        }



        return kernel;

    };



    function GaussianBlur(__src, __size1, __size2, __sigma1, __sigma2, __borderType, __dst) {

        if (__src.type && __src.type == "CV_RGBA") {

            var height = __src.row,

                width = __src.col,

                dst = __dst || new Mat(height, width, __src.data),

                dstData = dst.data;

            var sigma1 = __sigma1 || 0,

                sigma2 = __sigma2 || __sigma1;

            var size1 = __size1 || Math.round(sigma1 * 6 + 1) | 1,

                size2 = __size2 || Math.round(sigma2 * 6 + 1) | 1,

                size = size1 * size2;

            if (size1 % 2 !== 1 || size2 % 2 !== 1) {

                console.error("size必须是奇数。");

                return __src;

            }

            var startX = Math.floor(size1 / 2),

                startY = Math.floor(size2 / 2);

            var withBorderMat = copyMakeBorder(__src, startY, startX, 0, 0, __borderType),

                mData = withBorderMat.data,

                mWidth = withBorderMat.col;



            var kernel1 = getGaussianKernel(size1, sigma1),

                kernel2,

                kernel = new Array(size1 * size2);



            if (size1 === size2 && sigma1 === sigma2)

                kernel2 = kernel1;

            else

                kernel2 = getGaussianKernel(size2, sigma2);



            var i, j, c, y, x;



            for (i = kernel2.length; i--;) {

                for (j = kernel1.length; j--;) {

                    kernel[i * size1 + j] = kernel2[i] * kernel1[j];

                }

            }



            var newValue, nowX, offsetY, offsetI;



            for (i = height; i--;) {

                offsetI = i * width;

                for (j = width; j--;) {

                    for (c = 3; c--;) {

                        newValue = 0;

                        for (y = size2; y--;) {

                            offsetY = (y + i) * mWidth * 4;

                            for (x = size1; x--;) {

                                nowX = (x + j) * 4 + c;

                                newValue += (mData[offsetY + nowX] * kernel[y * size1 + x]);

                            }

                        }

                        dstData[(j + offsetI) * 4 + c] = newValue;

                    }

                    dstData[(j + offsetI) * 4 + 3] = mData[offsetY + startY * mWidth * 4 + (j + startX) * 4 + 3];

                }

            }



        } else {

            console.error("不支持的类型");

        }

        return dst;

    }



    function medianBlur(__src, __size1, __size2, __borderType, __dst) {

        if (__src.type && __src.type == "CV_RGBA") {

            var height = __src.row,

                width = __src.col,

                dst = __dst || new Mat(height, width, __src.data),

                dstData = dst.data;

            var size1 = __size1 || 3,

                size2 = __size2 || size1,

                size = size1 * size2;

            if (size1 % 2 !== 1 || size2 % 2 !== 1) {

                console.error("size必须是奇数");

                return __src;

            }

            var startX = Math.floor(size1 / 2),

                startY = Math.floor(size2 / 2);

            var withBorderMat = copyMakeBorder(__src, startY, startX, 0, 0, __borderType),

                mData = withBorderMat.data,

                mWidth = withBorderMat.col;



            var newValue = [], nowX, offsetY, offsetI;

            var i, j, c, y, x;



            for (i = height; i--;) {

                offsetI = i * width;

                for (j = width; j--;) {

                    for (c = 3; c--;) {

                        for (y = size2; y--;) {

                            offsetY = (y + i) * mWidth * 4;

                            for (x = size1; x--;) {

                                nowX = (x + j) * 4 + c;

                                newValue[y * size1 + x] = mData[offsetY + nowX];

                            }

                        }

                        newValue.sort();

                        dstData[(j + offsetI) * 4 + c] = newValue[Math.round(size / 2)];

                    }

                    dstData[(j + offsetI) * 4 + 3] = mData[offsetY + startY * mWidth * 4 + (j + startX) * 4 + 3];

                }

            }



        } else {

            console.error("类型不支持");

        }

        return dst;

    };



    function copyMakeBorder(_src, _top, _left, _bottom, _right, _borderType, _value) {

        if (_src.type != "CV_RGBA") {

            console.log("not support this type");

        } else if (_borderType == "BORDER_CONSTANT") {

            return copyMakeConstBorder_8U(_src, _top, _left, _bottom, _right, _value);

        } else {

            return copyMakeBorder_8U(_src, _top, _left, _bottom, _right, _borderType);

        }

    }



    function borderInterpolate(_p, _len, _borderType) {

        if (_p < 0 || _p >= _len) {

            switch (_borderType) {

                case "BORDER_REPLICATE":

                    _p = _p < 0 ? 0 : _len - 1;

                    break;

                case "BORDER_REFLECT":

                case "BORDER_REFLECT_101":

                    var delta = (_borderType == "BORDER_REFLECT_101");

                    if (_len == 1) {

                        return 0;

                    }

                    do {

                        if (_p < 0) {

                            _p = -_p - 1 + delta;

                        } else {

                            _p = _len - 1 - (_p - _len) - delta;

                        }

                    } while (_p < 0 || _p >= _len);

                    break;

                case "BORDER_WRAP":

                    if (_p < 0) {

                        _p -= ((_p - _len + 1) / _len | 0) * _len;

                    }

                    if (_p >= _len) {

                        _p %= _len;

                    }

                    break;

                case "BORDER_CONSTANT":

                    _p = -1;

                default:

                    console.log(arguments.callee, "UNSPPORT_BORDER_TYPE");

            }

        }

        return _p;

    }



    function copyMakeBorder_8U(_src, _top, _left, _bottom, _right, _borderType) {

        var i, j;

        var width = _src.col,

            height = _src.row;

        var top = _top,

            left = _left || _top,

            right = _right || left,

            bottom = _bottom || top,

            dstWidth = width + left + right,

            dstHeight = height + top + bottom,

            borderType = _borderType || "BORDER_REFLECT";

        var buffer = new ArrayBuffer(dstHeight * dstWidth * 4),

            tab = new Uint32Array(left + right);



        for (i = 0; i < left; i++) {

            tab[i] = borderInterpolate(i - left, width, borderType);

        }

        for (i = 0; i < right; i++) {

            tab[i + left] = borderInterpolate(width + i, width, borderType);

        }



        var tempArray, data;



        for (i = 0; i < height; i++) {

            tempArray = new Uint32Array(buffer, (i + top) * dstWidth * 4, dstWidth);

            data = new Uint32Array(_src.buffer, i * width * 4, width);

            for (j = 0; j < left; j++)

                tempArray[j] = data[tab[j]];

            for (j = 0; j < right; j++)

                tempArray[j + width + left] = data[tab[j + left]];

            tempArray.set(data, left);

        }



        var allArray = new Uint32Array(buffer);

        for (i = 0; i < top; i++) {

            j = borderInterpolate(i - top, height, _borderType);

            tempArray = new Uint32Array(buffer, i * dstWidth * 4, dstWidth);

            tempArray.set(allArray.subarray((j + top) * dstWidth, (j + top + 1) * dstWidth));

        }

        for (i = 0; i < bottom; i++) {

            j = borderInterpolate(i + height, height, borderType);

            tempArray = new Uint32Array(buffer, (i + top + height) * dstWidth * 4, dstWidth);

            tempArray.set(allArray.subarray((j + top) * dstWidth, (j + top + 1) * dstWidth));

        }



        return new Mat(dstHeight, dstWidth, new Uint8ClampedArray(buffer));

    }



    function copyMakeConstBorder_8U(_src, _top, _left, _bottom, _right, _value) {

        var i, j;

        var width = _src.col,

            height = _src.row;

        var top = _top,

            left = _left || _top,

            right = _right || left,

            bottom = _bottom || top,

            dstWidth = width + left + right,

            dstHeight = height + top + bottom,

            value = _value || [0, 0, 0, 255];

        var constBuf = new ArrayBuffer(dstWidth * 4),

            constArray = new Uint8ClampedArray(constBuf);

        buffer = new ArrayBuffer(dstHeight * dstWidth * 4);



        for (i = 0; i < dstWidth; i++) {

            for (j = 0; j < 4; j++) {

                constArray[i * 4 + j] = value[j];

            }

        }



        constArray = new Uint32Array(constBuf);

        var tempArray;



        for (i = 0; i < height; i++) {

            tempArray = new Uint32Array(buffer, (i + top) * dstWidth * 4, left);

            tempArray.set(constArray.subarray(0, left));

            tempArray = new Uint32Array(buffer, ((i + top + 1) * dstWidth - right) * 4, right);

            tempArray.set(constArray.subarray(0, right));

            tempArray = new Uint32Array(buffer, ((i + top) * dstWidth + left) * 4, width);

            tempArray.set(new Uint32Array(_src.buffer, i * width * 4, width));

        }



        for (i = 0; i < top; i++) {

            tempArray = new Uint32Array(buffer, i * dstWidth * 4, dstWidth);

            tempArray.set(constArray);

        }



        for (i = 0; i < bottom; i++) {

            tempArray = new Uint32Array(buffer, (i + top + height) * dstWidth * 4, dstWidth);

            tempArray.set(constArray);

        }



        return new Mat(dstHeight, dstWidth, new Uint8ClampedArray(buffer));

    }



    window.imageBlur = imageBlur;

})();

  调用示例:

var iCanvas = document.getElementById("blur");

var imgBlur = new imageBlur(iCanvas, "images/1.jpg", "BORDER_REFLECT", "right", "blur");

imgBlur.render();

  效果(核的横向和纵向大小均取为11):

Javascript图像处理之平滑处理

 

Javascript图像处理之平滑处理

 

Javascript图像处理之平滑处理

 

Javascript图像处理之平滑处理

你可能感兴趣的:(JavaScript)