首頁  >  文章  >  web前端  >  Javascript影像處理—虛擬邊緣介紹及使用方法_javascript技巧

Javascript影像處理—虛擬邊緣介紹及使用方法_javascript技巧

WBOY
WBOY原創
2016-05-16 17:45:171397瀏覽
前言
上一篇文章,我們來為矩陣添加一些常用方法,這篇文章將講解圖像的虛擬邊緣。

虛擬邊緣
虛擬邊緣就是依照一定映射關係,為影像添加邊緣。
那麼虛擬邊緣有什麼用呢?例如可以很容易做一個倒影的效果:
 
當然這只是附帶效果了,虛擬邊緣主要用在圖像卷積運算(例如平滑操作)時候,由於卷積運算的特點,需要將圖片擴大才能對邊角進行卷積運算,這時候就需要對圖片進行預處理,並加入虛擬邊緣。
說穿了,就是在一些圖片處理前先進行預處理。

邊緣類型
這裡參考OpenCV相關文檔的邊緣描述:
複製代碼 程式碼如下:

/*
Various border types, image boundaries are denoted with '|'
* BORDER_REPLICATE: aaDER|abcdefb| abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: 71/abn;

舉例BODER_REFLECT是對於某一行或某一列像素點:
  abcdefgh
其左的虛擬邊緣對應為fedcba,右邊對應為hgfedcb,也就是反射映射。上圖就是透過圖片底部進行新增BORDER_REFLECT類型的虛擬邊緣所得到的。
而BORDER_CONSTANT則是所有邊緣都是固定值i。
實作
因為BORDER_CONSTANT比較特殊,所以跟其他型別分開處理。



複製程式碼 程式碼如下: function copyMakeBorder(__srcbot, top __ , __borderType, __value){
if(__src.type != "CV_RGBA"){
console.error("不支援類型!");
}
if(__borderType ===_BORDER_CONSTANT ){
return copyMakeConstBorder_8U(__src, __top, __left, __bottom, __right, __value);
}else{
return copyMake__B,8U(__s__s__);
};


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



複製程式碼
程式碼如下: function borderInterpolate(__p__p. >if(__p = __len){ switch(__borderType){
case CV_BORDER_REPLICATE:
__p = __p ; ; >case CV_BORDER_REFLECT:
case CV_BORDER_REFLECT_101:
var delta = __borderType == CV_BORDER_REFLECT_101;
if(__len == 1)
> 9; )
__p = -__p - 1 delta;
else
__p = __len - 1 - (__p - __len) - delta;
}while(__p = __len)
break;
case CV_BORDER_WRAP:
if(__p __p -= ((__p - __len 1) / __len) * __len;
if(__p >= __len)
__p %= __len;
break;
case CV_BORDER_CONSTANT:
__p = -1;
default:
error(arguments.callee, UNSPPORT_BORDER_TYPE/* { {/); 🎜>}
}
return __p;
};


這個函數的意義是對於原長度為len的某一行或某一列的虛擬像素點p(p一般是負數或大於或等於該行原長度的數,負數則表示該行左邊的像素點,大於或等於原長度則表示是右邊的像素點),映射成這一行的哪一個像素點。我們拿CV_BORDER_REPLICATE分析一下,其表達式是:
  __p = __p 也就是說p為負數時(也就是左邊)的時候映射為0,否則映射成len - 1。
然後我們來實作copyMakeBorder_8U函數:



複製程式碼


程式碼如下:

函數 copyMakeBorder_8U(__src, __top, __left, __bottom, __right, __borderType){
var i, j;
var 寬度 = __src.col,
高度 = __src.row;
var top = __top,
left = __left || __top,
右= __右||左,
底部 = __bottom || 頂部,
dstWidth = 左右寬度,
dstHeight = 頂部底部高度,
borderType = borderType || CV_BORDER_REFLECT;
var buffer = new ArrayBuffer(dstHeight * dstWidth * 4),
tab = new Uint32Array(left right);
for(i = 0; i tab[i] = borderInterpolate(i - left, width, __borderType);
}
for(i = 0; i tab[i left] = borderInterpolate(width i, width, __borderType);
}
var tempArray,資料;
for(i = 0; i tempArray = new Uint32Array(buffer, (i top) * dstWidth * 4, dstWidth);
data = new Uint32Array(__src.buffer, i * width * 4, width);
for(j = 0; j tempArray[j] = data[tab[j]];
for(j = 0; j tempArray[j left 寬度] = data[tab[j left]];
tempArray.set(資料, 左);
}
var allArray = new Uint32Array(buffer);
for(i = 0; i j = borderInterpolate(i - 頂部, 高度, __borderType);
tempArray = new Uint32Array(buffer, i * dstWidth * 4, dstWidth);
tempArray.set(allArray.subarray((j top) * dstWidth, (j top 1) * dstWidth));
}
for(i = 0; i j = borderInterpolate(i height, height, __borderType);
tempArray = new Uint32Array(buffer, (i 頂部高度) * 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 寬度 = __src.col,
高度 = __src.row;
var top = __top,
left = __left || __top,
右= __右||左,
底部 = __bottom || 頂部,
dstWidth = 左右寬度,
dstHeight = 頂部底部高度,
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 for( j = 0; j constArray[i * 4 j] = value[j];
}
}
constArray = new Uint32Array(constBuf);
var tempArray;
for(i = 0; 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 tempArray = new Uint32Array(buffer, i * dstWidth * 4, dstWidth);
tempArray.set(constArray);
}
for(i = 0; i tempArray = new Uint32Array(buffer, (i 頂部高度) * 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

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn