中文字幕在线一区二区在线,久久久精品免费观看国产,无码日日模日日碰夜夜爽,天堂av在线最新版在线,日韩美精品无码一本二本三本,麻豆精品三级国产国语,精品无码AⅤ片,国产区在线观看视频

      使用JavaScript進(jìn)行基本圖形操作與處理

      時(shí)間:2024-10-17 06:22:09 JavaScript 我要投稿
      • 相關(guān)推薦

      使用JavaScript進(jìn)行基本圖形操作與處理

        前言

        上一篇文章,我們講解了圖像的虛擬邊緣,這篇文章開(kāi)始進(jìn)行平滑(也就是模糊)處理。

        基本原理

        這里直接引用OpenCV 2.4+ C++ 平滑處理和OpenCV 2.4+ C++ 邊緣梯度計(jì)算的相關(guān)內(nèi)容:

        平滑也稱(chēng)模糊, 是一項(xiàng)簡(jiǎn)單且使用頻率很高的圖像處理方法。

        平滑處理時(shí)需要用到一個(gè)濾波器

        。 最常用的濾波器是線性濾波器,線性濾波處理的輸出像素值(例如:

        )是輸入像素值(例如:

        )的加權(quán)平均:

        稱(chēng)為核

        , 它僅僅是一個(gè)加權(quán)系數(shù)。

        這里涉及一種叫做“卷積”的運(yùn)算,那么卷積是什么呢?

        卷積是在每一個(gè)圖像塊與某個(gè)算子(核)之間進(jìn)行的運(yùn)算。

        核?!

        nbsp;

        dsds

        核就是一個(gè)固定大小的數(shù)值數(shù)組。該數(shù)組帶有一個(gè)錨點(diǎn)

        ,一般位于數(shù)組中央。

        可是這怎么運(yùn)算啊?

        假如你想得到圖像的某個(gè)特定位置的卷積值,可用下列方法計(jì)算:

        將核的錨點(diǎn)放在該特定位置的像素上,同時(shí),核內(nèi)的其他值與該像素鄰域的各像素重合;將核內(nèi)各值與相應(yīng)像素值相乘,并將乘積相加;將所得結(jié)果放到與錨點(diǎn)對(duì)應(yīng)的像素上;對(duì)圖像所有像素重復(fù)上述過(guò)程。

        用公式表示上述過(guò)程如下:

        在圖像邊緣的卷積怎么辦呢?

        計(jì)算卷積前,需要通過(guò)復(fù)制源圖像的邊界創(chuàng)建虛擬像素,這樣邊緣的地方也有足夠像素計(jì)算卷積了。這就是為什么上一篇文章需要做虛擬邊緣函數(shù)。

        均值平滑

        均值平滑實(shí)際上就是內(nèi)核元素全是1的卷積運(yùn)算,然后再除以內(nèi)核的大小,用數(shù)學(xué)表達(dá)式來(lái)表示就是:

        下面我們來(lái)實(shí)現(xiàn)均值平滑函數(shù)blur:

        復(fù)制代碼 代碼如下:

        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, CV_RGBA),

        dstData = dst.data;

        var size1 = __size1 || 3,

        size2 = __size2 || size1,

        size = size1 * size2;

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

        console.error("size大小必須是奇數(shù)");

        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("不支持類(lèi)型。");

        }

        return dst;

        }

        其中size1和size2分別是核的橫向和縱向大小,并且必須是正奇數(shù)。

        高斯平滑

        最有用的濾波器 (盡管不是最快的)。 高斯濾波是將輸入數(shù)組的每一個(gè)像素點(diǎn)與高斯內(nèi)核

        卷積將卷積和當(dāng)作輸出像素值。

        參考一維高斯函數(shù),我們可以看見(jiàn),他是個(gè)中間大兩邊小的函數(shù)。

        所以高斯濾波器其加權(quán)數(shù)是中間大,四周小的。

        其二維高斯函數(shù)為:

        其中

        為均值 (峰值對(duì)應(yīng)位置),

        代表標(biāo)準(zhǔn)差 (變量

        和 變量

        各有一個(gè)均值,也各有一個(gè)標(biāo)準(zhǔn)差)。

        這里參考OpenCV的實(shí)現(xiàn),不過(guò)應(yīng)該還有優(yōu)化空間,因?yàn)檫沒(méi)用到分離濾波器。

        首先我們做一個(gè)getGaussianKernel來(lái)返回高斯濾波器的一維數(shù)組。

        復(fù)制代碼 代碼如下:

        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="" __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;

        };

        然后通過(guò)兩個(gè)這個(gè)一維數(shù)組,便可以計(jì)算出一個(gè)完整的高斯內(nèi)核,再利用blur里面用到的循環(huán)方法,就可以算出高斯平滑后的矩陣了。

        復(fù)制代碼 代碼如下:

        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, CV_RGBA),

        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必須是奇數(shù)。");

        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("不支持的類(lèi)型");

        }

        return dst;

        }

        中值平滑

        中值濾波將圖像的每個(gè)像素用鄰域 (以當(dāng)前像素為中心的正方形區(qū)域)像素的

        中值代替 。

        依然使用blur里面用到的循環(huán),只要得到核中的所有值,再通過(guò)sort排序便可以得到中值,然后錨點(diǎn)由該值替代。

        復(fù)制代碼 代碼如下:

        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, CV_RGBA),

        dstData = dst.data;

        var size1 = __size1 || 3,

        size2 = __size2 || size1,

        size = size1 * size2;

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

        console.error("size必須是奇數(shù)");

        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("類(lèi)型不支持");

        }

        return dst;

        };

      【使用JavaScript進(jìn)行基本圖形操作與處理】相關(guān)文章:

      javascript編程異常處理的方法08-04

      使用ajax操作JavaScript對(duì)象的方法09-28

      詳解JavaScript中的splice()使用方法08-20

      javascript中for/in循環(huán)以及常見(jiàn)的使用技巧06-24

      Javascript中arguments對(duì)象的詳解和使用方法08-20

      有關(guān)深入理解JavaScript中的并行處理的介紹10-14

      電腦使用的幾個(gè)基本技巧10-18

      華為的基本使用命令10-22

      使用幻燈片進(jìn)行演講的技巧07-03

      關(guān)于javascript對(duì)象之內(nèi)置和對(duì)象Math的使用方法10-08

      主站蜘蛛池模板: 在线观看精品视频一区二区三区| 陵川县| 久久蜜臀一区二区三区av| 佛教| 无码啪啪人妻| 亚洲av粉色一区二区三区| 波多野无码AV中文专区| 来凤县| 久久精品熟女亚洲av艳妇| 无码AV大香线蕉伊人久久| 亚洲是图一区二区视频| 在线中文字幕人妻视频| 武威市| 麻豆久久久国内精品| 成人精品国产亚洲欧洲| 成人精品免费av不卡在线观看| 日本一区二区三区高清日韩| 一本久道免费高清视频| 亚洲精品高清av在线播放| 日产精品一区二区免费| 国产福利一区二区三区视频在线看 | 达孜县| 日产精品一区二区三区| 亚洲中文字幕女同一区二区三区| 一区二区特别黄色大片| 久久国产高潮流白浆免费观看 | 国语国产激情对白在线| 青青青伊人色综合久久| 青青草视频在线网站观看| 久久久www成人免费无遮挡大片| 国产西西裸体一级黄色大片| 中文字幕有码在线视频| 亚洲中文字幕一区二区不卡| 家庭乱码伦区中文字幕在线| 加勒比东京热久久综合| 97人妻无码免费专区| 亚洲AV手机专区久久精品| AV熟妇导航网| 一级无码啪啪| 国产伦理自拍视频在线| 好看午夜一鲁一鲁一鲁|