最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Javascript圖像處理—虛擬邊緣介紹及使用方法

 更新時(shí)間:2012年12月27日 14:30:45   作者:  
虛擬邊緣就是按照一定映射關(guān)系,給圖像添加邊緣那么虛擬邊緣有什么用呢?接下來(lái)詳細(xì)介紹,需要了解的朋友可以參考下
前言
上一篇文章,我們來(lái)給矩陣添加一些常用方法,這篇文章將講解圖像的虛擬邊緣。

虛擬邊緣
虛擬邊緣就是按照一定映射關(guān)系,給圖像添加邊緣。
那么虛擬邊緣有什么用呢?比如可以很容易做一個(gè)倒影的效果:
 
當(dāng)然這只是附帶效果了,虛擬邊緣主要用在圖像卷積運(yùn)算(例如平滑操作)時(shí)候,由于卷積運(yùn)算的特點(diǎn),需要將圖片擴(kuò)大才能對(duì)邊角進(jìn)行卷積運(yùn)算,這時(shí)候就需要對(duì)圖片進(jìn)行預(yù)處理,添加虛擬邊緣。
說(shuō)白了,就是在一些圖片處理前進(jìn)行預(yù)處理。

邊緣類型
這里參考OpenCV相關(guān)文檔的邊緣描述:
復(fù)制代碼 代碼如下:

/*
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'
*/

舉個(gè)例子BODER_REFLECT就是對(duì)于某一行或某一列像素點(diǎn):
  abcdefgh
其左的虛擬邊緣對(duì)應(yīng)為fedcba,右邊對(duì)應(yīng)為hgfedcb,也就是反射映射。上圖就是通過(guò)對(duì)圖片底部進(jìn)行添加BORDER_REFLECT類型的虛擬邊緣得到的。
而B(niǎo)ORDER_CONSTANT則是所有邊緣都是固定值i。
實(shí)現(xiàn)
因?yàn)锽ORDER_CONSTANT比較特殊,所以和其他類型分開(kāi)處理。
復(fù)制代碼 代碼如下:

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

這個(gè)函數(shù)接受一個(gè)輸入矩陣src,每個(gè)方向要添加的像素大小top,left,bottom,right,邊緣的類型borderType,還有一個(gè)數(shù)組value,即如果是常數(shù)邊緣時(shí)候添加的常數(shù)值。
然后我們引入一個(gè)邊緣的映射關(guān)系函數(shù)borderInterpolate。
復(fù)制代碼 代碼如下:

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) * __len;
if(__p >= __len)
__p %= __len;
break;
case CV_BORDER_CONSTANT:
__p = -1;
default:
error(arguments.callee, UNSPPORT_BORDER_TYPE/* {line} */);
}
}
return __p;
};

這個(gè)函數(shù)的意義是對(duì)于原長(zhǎng)度為len的某一行或者某一列的虛擬像素點(diǎn)p(p一般是負(fù)數(shù)或者大于或等于該行原長(zhǎng)度的數(shù),負(fù)數(shù)則表示該行左邊的像素點(diǎn),大于或等于原長(zhǎng)度則表示是右邊的像素點(diǎn)),映射成這一行的哪一個(gè)像素點(diǎn)。我們拿CV_BORDER_REPLICATE分析一下,其表達(dá)式是:
  __p = __p < 0 ? 0 : __len - 1;
也就是說(shuō)p為負(fù)數(shù)時(shí)(也就是左邊)的時(shí)候映射為0,否則映射成len - 1。
然后我們來(lái)實(shí)現(xiàn)copyMakeBorder_8U函數(shù):
復(fù)制代碼 代碼如下:

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

這里需要解釋下,邊緣的復(fù)制順序是:先對(duì)每行的左右進(jìn)行擴(kuò)展,然后在此基礎(chǔ)上進(jìn)行上下擴(kuò)展,如圖所示。

然后我們根據(jù)ArrayBuffer的性質(zhì),將數(shù)據(jù)轉(zhuǎn)成無(wú)符號(hào)32位整數(shù)來(lái)操作,這樣每個(gè)操作單位就對(duì)應(yīng)了每個(gè)像素點(diǎn)了。什么意思?
比如對(duì)于某個(gè)像素點(diǎn):RGBA,由于某個(gè)通道是用無(wú)符號(hào)8為整數(shù)來(lái)存儲(chǔ)的,所以實(shí)際上一個(gè)像素點(diǎn)則對(duì)應(yīng)了32位的存儲(chǔ)大小,由于ArrayBuffer的性質(zhì),可以將數(shù)據(jù)轉(zhuǎn)成任意類型來(lái)處理,這樣我們就可以通過(guò)轉(zhuǎn)成Uint32Array類型,將數(shù)據(jù)變成每個(gè)像素點(diǎn)的數(shù)據(jù)數(shù)組。
那么copyMakeConstBorder_8U就比較容易實(shí)現(xiàn)了:
復(fù)制代碼 代碼如下:

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

相關(guān)文章

  • JS的拖拽屬性draggable詳解

    JS的拖拽屬性draggable詳解

    這篇文章主要介紹了JS的拖拽屬性draggable詳解,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • js 時(shí)間格式與時(shí)間戳的相互轉(zhuǎn)換示例代碼

    js 時(shí)間格式與時(shí)間戳的相互轉(zhuǎn)換示例代碼

    很多的新手朋友們對(duì)js中的時(shí)間格式與時(shí)間戳的轉(zhuǎn)換比較陌生,下面就為大家詳細(xì)介紹下具體的轉(zhuǎn)換步驟,感興趣的朋友可以參考下
    2013-12-12
  • js為什么不能正確處理小數(shù)運(yùn)算?

    js為什么不能正確處理小數(shù)運(yùn)算?

    這篇文章主要介紹了js不能正確處理小數(shù)運(yùn)算的原因,為大家解除js為什么不能正確處理小數(shù)運(yùn)算的疑慮,感興趣的小伙伴們可以參考一下
    2015-12-12
  • 微信小程序開(kāi)發(fā)之獲取用戶信息的兩種方法

    微信小程序開(kāi)發(fā)之獲取用戶信息的兩種方法

    小程序可以通過(guò)微信官方提供的登錄方法方便地獲取微信提供的用戶身份標(biāo)識(shí),進(jìn)而開(kāi)發(fā)者可以進(jìn)行下一步操作,下面這篇文章主要給大家介紹了關(guān)于微信小程序開(kāi)發(fā)之獲取用戶信息的兩種方法,需要的朋友可以參考下
    2022-03-03
  • 使用tree?shaking?移除無(wú)用代碼

    使用tree?shaking?移除無(wú)用代碼

    這篇文章主要為大家介紹了使用tree?shaking?移除無(wú)用代碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 兩個(gè)數(shù)組去重的JS代碼

    兩個(gè)數(shù)組去重的JS代碼

    這篇文章主要介紹了兩個(gè)數(shù)組去重的JS代碼,有需要的朋友可以參考一下
    2013-12-12
  • js計(jì)算兩個(gè)時(shí)間之間天數(shù)差的實(shí)例代碼

    js計(jì)算兩個(gè)時(shí)間之間天數(shù)差的實(shí)例代碼

    這篇文章主要介紹了js計(jì)算兩個(gè)時(shí)間之間天數(shù)差的實(shí)例代碼,有需要的朋友可以參考一下
    2013-11-11
  • es6中some和every方法使用簡(jiǎn)單示例

    es6中some和every方法使用簡(jiǎn)單示例

    JavaScript在ES6版本后提供了一些更加便捷的方法供開(kāi)發(fā)者使用,實(shí)現(xiàn)原理其實(shí)是在對(duì)應(yīng)的構(gòu)造函數(shù)原型提供方法,下面這篇文章主要給大家介紹了關(guān)于es6中some和every方法使用的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • JavaScript設(shè)計(jì)模式之代理模式詳解

    JavaScript設(shè)計(jì)模式之代理模式詳解

    這篇文章主要為大家詳細(xì)介紹了JavaScript設(shè)計(jì)模式之代理模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • js實(shí)現(xiàn)無(wú)縫輪播圖

    js實(shí)現(xiàn)無(wú)縫輪播圖

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)無(wú)縫輪播圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03

最新評(píng)論

平顺县| 泰州市| 岑溪市| 水富县| 铜梁县| 进贤县| 高雄县| 镇巴县| 泽普县| 威宁| 嘉兴市| 高邮市| 都兰县| 山西省| 云安县| 上虞市| 江都市| 惠水县| 贵溪市| 霍林郭勒市| 庆元县| 呈贡县| 佛冈县| 西乡县| 徐水县| 汉沽区| 澄江县| 綦江县| 白山市| 绥江县| 榆树市| 海林市| 贞丰县| 射阳县| 册亨县| 大港区| 上杭县| 若尔盖县| 新兴县| 遂溪县| 墨竹工卡县|