<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      Javascript圖像處理——虛擬邊緣

      2012-12-27 09:58  Justany_WhiteSnow  閱讀(3652)  評論(4)    收藏  舉報

      前言

      上一篇文章,我們來給矩陣添加一些常用方法,這篇文章將講解圖像的虛擬邊緣。

       

      虛擬邊緣

      虛擬邊緣就是按照一定映射關系,給圖像添加邊緣。

      那么虛擬邊緣有什么用呢?比如可以很容易做一個倒影的效果:

      當然這只是附帶效果了,虛擬邊緣主要用在圖像卷積運算(例如平滑操作)時候,由于卷積運算的特點,需要將圖片擴大才能對邊角進行卷積運算,這時候就需要對圖片進行預處理,添加虛擬邊緣。

      說白了,就是在一些圖片處理前進行預處理。

       

      邊緣類型

      這里參考OpenCV相關文檔的邊緣描述:

      /*
       Various border types, image boundaries are denoted with '|'
      
       * BORDER_REPLICATE:     aaaaaa|abcdefgh|hhhhhhh
       * BORDER_REFLECT:       fedcba|abcdefgh|hgfedcb
       * BORDER_REFLECT_101:   gfedcb|abcdefgh|gfedcba
       * BORDER_WRAP:          cdefgh|abcdefgh|abcdefg
       * BORDER_CONSTANT:      iiiiii|abcdefgh|iiiiiii  with some specified 'i'
       */

      舉個例子BODER_REFLECT就是對于某一行或某一列像素點:

        abcdefgh

      其左的虛擬邊緣對應為fedcba,右邊對應為hgfedcb,也就是反射映射。上圖就是通過對圖片底部進行添加BORDER_REFLECT類型的虛擬邊緣得到的。

      而BORDER_CONSTANT則是所有邊緣都是固定值i。

       

      實現

      因為BORDER_CONSTANT比較特殊,所以和其他類型分開處理。

      function copyMakeBorder(__src, __top, __left, __bottom, __right, __borderType, __value){
          if(__src.type != "CV_RGBA"){
              console.error("不支持類型!");
          }
          if(__borderType === CV_BORDER_CONSTANT){
              return copyMakeConstBorder_8U(__src, __top, __left, __bottom, __right, __value);
          }else{
              return copyMakeBorder_8U(__src, __top, __left, __bottom, __right, __borderType);
          }
      };

      這個函數接受一個輸入矩陣src,每個方向要添加的像素大小top,left,bottom,right,邊緣的類型borderType,還有一個數組value,即如果是常數邊緣時候添加的常數值。

      然后我們引入一個邊緣的映射關系函數borderInterpolate。

      function borderInterpolate(__p, __len, __borderType){
          if(__p < 0 || __p >= __len){
              switch(__borderType){
                  case CV_BORDER_REPLICATE:
                      __p = __p < 0 ? 0 : __len - 1;
                      break;
                  case CV_BORDER_REFLECT:
                  case CV_BORDER_REFLECT_101:
                      var delta = __borderType == CV_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 CV_BORDER_WRAP:
                      if(__p < 0)
                          __p -= (((__p - __len + 1) / __len) | 0) * __len;
                      if(__p >= __len)
                          __p %= __len;
                      break;
                  case CV_BORDER_CONSTANT:
                      __p = -1;
                  default:
                      error(arguments.callee, UNSPPORT_BORDER_TYPE/* {line} */);
              }
          }
          return __p;
      };

      這個函數的意義是對于原長度為len的某一行或者某一列的虛擬像素點p(p一般是負數或者大于或等于該行原長度的數,負數則表示該行左邊的像素點,大于或等于原長度則表示是右邊的像素點),映射成這一行的哪一個像素點。我們拿CV_BORDER_REPLICATE分析一下,其表達式是:

        __p = __p < 0 ? 0 : __len - 1;

      也就是說p為負數時(也就是左邊)的時候映射為0,否則映射成len - 1。

      然后我們來實現copyMakeBorder_8U函數:

      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 || CV_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));
      }

      這里需要解釋下,邊緣的復制順序是:先對每行的左右進行擴展,然后在此基礎上進行上下擴展,如圖所示。

      然后我們根據ArrayBuffer的性質,將數據轉成無符號32位整數來操作,這樣每個操作單位就對應了每個像素點了。什么意思?

      比如對于某個像素點:RGBA,由于某個通道是用無符號8為整數來存儲的,所以實際上一個像素點則對應了32位的存儲大小,由于ArrayBuffer的性質,可以將數據轉成任意類型來處理,這樣我們就可以通過轉成Uint32Array類型,將數據變成每個像素點的數據數組。

      那么copyMakeConstBorder_8U就比較容易實現了:

      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));
      }

       

      效果圖

      CV_BORDER_REPLICATE

      CV_BORDER_REFLECT

      CV_BORDER_WRAP

      CV_BORDER_CONSTANT

       

      更多的例子

      Javascript圖像處理之虛擬邊緣

       

      系列目錄

      Javascript圖像處理系列

       

      參考資料

      在OpenCV中圖像邊界擴展 copyMakeBorder 的實現 . viewcode . 2012-12-13 09:28

      主站蜘蛛池模板: 99RE8这里有精品热视频| 大香伊蕉在人线国产免费| 磴口县| 粉嫩一区二区三区精品视频| 在线国产极品尤物你懂的| 国产av无码专区亚洲aⅴ| 精品偷拍一区二区三区| 日本中文字幕不卡在线一区二区 | 亚洲人成小说网站色在线 | 无码熟妇人妻av影音先锋| 国内精品久久人妻互换| 蜜臀av午夜精品福利| 国产精品国产三级国产试看| 蜜桃av多人一区二区三区| 日韩中文字幕免费在线观看| 国产精品无码无片在线观看3d| 日日摸夜夜添狠狠添欧美| 亚洲男人第一无码av网站| 日韩不卡一区二区在线观看| 又爽又黄又无遮掩的免费视频| 无码伊人久久大杳蕉中文无码| 国产成人精品久久性色av| 日韩丝袜欧美人妻制服| 人人干人人噪人人摸| 我要看亚洲黄色太黄一级黄| 日本一区二区三区专线| 国产精品无码dvd在线观看| 国产精品不卡一区二区在线| 国产精品人妻中文字幕| 丰满岳妇乱一区二区三区| 欧美xxxx精品另类| 午夜三级成人在线观看| 无套内射极品少妇chinese| 亚洲啪啪精品一区二区的| 一区二区亚洲人妻精品| 久久天天躁狠狠躁夜夜av不卡| 中文字幕久久六月色综合| 国产午夜亚洲精品国产成人| 株洲县| 国产av亚洲精品ai换脸电影| 国产成人精品无人区一区|