亚洲AV日韩AⅤ综合手机在线观看,激情婷婷久久综合色,欧美色五月婷婷久久,久久国产精品99久久人人澡

  • <abbr id="uk6uq"><abbr id="uk6uq"></abbr></abbr>
  • <tbody id="uk6uq"></tbody>
  • 使用JavaScript進(jìn)行基本圖形操作與處理

    時間:2020-11-20 15:37:16 JavaScript 我要投稿

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

      前言

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

      基本原理

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

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

      平滑處理時需要用到一個濾波器

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

     。┦禽斎胂袼刂担ɡ纾

     。┑募訖(quán)平均:

      稱為核

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

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

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

      核?!

      nbsp;

      dsds

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

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

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

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

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

      用公式表示上述過程如下:

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

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

      均值平滑

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

      下面我們來實(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("不支持類型。");

      }

      return dst;

      }

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

      高斯平滑

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

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

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

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

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

      其中

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

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

      和 變量

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

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

      首先我們做一個getGaussianKernel來返回高斯濾波器的一維數(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;

      };

      然后通過兩個這個一維數(shù)組,便可以計(jì)算出一個完整的高斯內(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("不支持的類型");

      }

      return dst;

      }

      中值平滑

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

      中值代替 。

      依然使用blur里面用到的循環(huán),只要得到核中的所有值,再通過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("類型不支持");

      }

      return dst;

      };

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

    1.淺析JavaScript基本類型與引用類型

    2.javascript數(shù)組使用調(diào)用方法

    3.Javascript高級手勢使用介紹

    4.JavaScript基本語法分析

    5.Javascript的基本內(nèi)容

    6.javascript編程異常處理的方法

    7.javascript工廠方式的使用

    8.Javascript中的isNaN函數(shù)使用