• <sub id="h4knl"><ol id="h4knl"></ol></sub>
    <sup id="h4knl"></sup>
      <sub id="h4knl"></sub>

      <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
      1. <strong id="h4knl"></strong>

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

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

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

          前言

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

          基本原理

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

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

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

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

          )是輸入像素值(例如:

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

          稱為核

          , 它僅僅是一個(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ù)上述過程。

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

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

          計(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ù)組的每一個(gè)像素點(diǎn)與高斯內(nèi)核

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

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

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

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

          其中

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

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

          和 變量

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

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

          首先我們做一個(gè)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;

          };

          然后通過兩個(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("不支持的類型");

          }

          return dst;

          }

          中值平滑

          中值濾波將圖像的每個(gè)像素用鄰域 (以當(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;

          };

        《&.doc》
        将本文的Word文档下载到电脑,方便收藏和打印
        推荐度:
        点击下载文档

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

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

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

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

        javascript中for/in循環(huá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

        在线咨询
        国产高潮无套免费视频_久久九九兔免费精品6_99精品热6080YY久久_国产91久久久久久无码
      3. <sub id="h4knl"><ol id="h4knl"></ol></sub>
        <sup id="h4knl"></sup>
          <sub id="h4knl"></sub>

          <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
          1. <strong id="h4knl"></strong>

          2. 思思热视频精品在线播放 | 五月天久久成人AV | 亚洲不卡中文字幕 | 一级a一级a爰片免费免免久久 | 天天在线精品一区 | 伊人久久综在合线亚洲2019人澡 |

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

              前言

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

              基本原理

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

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

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

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

              )是輸入像素值(例如:

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

              稱為核

              , 它僅僅是一個(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ù)上述過程。

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

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

              計(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ù)組的每一個(gè)像素點(diǎn)與高斯內(nèi)核

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

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

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

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

              其中

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

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

              和 變量

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

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

              首先我們做一個(gè)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;

              };

              然后通過兩個(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("不支持的類型");

              }

              return dst;

              }

              中值平滑

              中值濾波將圖像的每個(gè)像素用鄰域 (以當(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;

              };