首頁 > web前端 > js教程 > Javascript影像處理—平滑處理實作原理_javascript技巧

Javascript影像處理—平滑處理實作原理_javascript技巧

WBOY
發布: 2016-05-16 17:45:07
原創
1601 人瀏覽過

前言

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

基本原理

這裡直接引用OpenCV 2.4 C 平滑處理和OpenCV 2.4 C 邊緣梯度計算的相關內容:

平滑也稱模糊, 是一項簡單且使用頻率很高的影像處理方法。

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

。 最常用的濾波器是線性

濾波器,線性濾波處理的輸出像素值(例如:g(i,j))是輸入像素值(例如:f(i)的加權平均值:

    g(i,j) = sum_{k,l} f(i k, j l) h(k,l)

h(k,l)稱為核

, 它只是一個加權係數。

這裡涉及一種叫做「卷積」的運算,那麼卷積是什麼呢?

卷積是在每個影像區塊與某個算子(核)之間進行的運算。

核? !

nbsp;
dsds

核就是一個固定大小的數值數組。此陣列有一個錨點

 ,一般位於陣列中央。

kernel example

 可是這怎麼運算啊?

假如你想得到影像的某個特定位置的捲積值,可用下列方法計算:

    將核的錨點放在該特定位置的像素上,同時,核內的其他值與該像素鄰域的各像素重合;將核內各值與相應像素值相乘,並將乘積相加;將所得結果放到與錨點對應的像素上;對影像所有像素重複上述過程。

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

    H(x,y) = sum_{i=0}^{M_{i} - 1} sum_{j=0}^{M_{j}-1} I(x i - a_{i}, y   j - a_{j})K(i,j)

在影像邊緣的捲積怎麼辦呢?

計算卷積前,需要透過複製來源影像的邊界來建立虛擬像素,這樣邊緣的地方也有足夠像素計算卷積了。這就是為什麼上一篇文章需要做虛擬邊緣函數。

 

平均值平滑

均值平滑其實就是內核元素全是1的捲積運算,然後再除以內核的大小,用數學表達式來表示就是:

  texttt{K} = frac{1}{texttt{ksize.width*ksize.height}} begin{bmatrix} 1 & 1 & 1 & cdots & 1 & 1 \ 1 & 1 & 1 & cdots & 1 & 1 \ hdotsfor{6} \ 1 & 1 & 1 & cdots & 1 & 1 \ end{bmatrix}

下面我們來實現平均值平滑函數blur:

複製程式碼 程式碼如下:


程式碼如下:


if(__src.type && __src.type == "CV_RGBA"){
var height = __src.row, wid. col,
dst = __dst || new Mat(height, width, CV_RGBA),
dstData = dst.data;
var size1 = __size1 || 3,
size2 = __size2 || size🎜>size2 = __size2 ||size1,
size = size1 * size2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size大小必須是奇數"); return __src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__sstart , 0, 0, __borderType),
mData = withBorderMat.data,
mWidth = withBorderMat.col;

var newValue, nowX, offsetY, offsetI;
var newValue, nowX, offsetY, offsetI;
i, j3, j , 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[(joff 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分別是核的橫向和縱向大小,且必須是正奇數。

高斯平滑

最有用的濾波器 (儘管不是最快的)。 高斯濾波是將輸入數組的每一個像素點與高斯內核

卷積將卷積和作為輸出像素值。

http://www.cnblogs.com/http://www.cnblogs.com/_images/Smoothing_Tutorial_theory_gaussian_0.jpg

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

所以高斯濾波器其加權數是中間大,四周小的。

其二維高斯函數為:

    G_{0}(x, y) = A e^{ dfrac{ -(x - mu_{x})^{2} }{ 2sigma^{2}_{x} }   dfrac{ -(y - mu_{y})^{2} }{ 2sigma^{2}_{y} } } 

其中 

mu 為平均值 (峰值對應位置),

sigma 代表標準差 (變量

x 和 變量

y 各有一個平均值,也各有一個標準差)。

這裡參考OpenCV的實現,不過應該還有優化空間,因為還沒用到分離濾波器。

首先我們先做一個getGaussianKernel來傳回高斯濾波器的一維數組。

複製程式碼 程式碼如下:

function getGaussianKernel(__nianKernel(__s) SMALL_GAUSSIAN_SIZE = 7,
smallGaussianTab = [[1],
[0.25, 0.5, 0.25],
[0.0625, 0.25, 0.375,
[0.0625, 0.25, 0.375, 0.25, 0. , 0.21875, 0.28125, 0.21875, 0.109375, 0.03125]
];

var fixedKernel = __n & 2 == 1 && __n
var sigmaX = __sigma > 0 ? __sigma : ((__n - 1) * 0.5 - 1) * 0.3 0.8,
scale2X = -0.5 / (sigmaX * sigmaX);

var i, x, t, kernel = [];

for(i = 0; 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;
};


然後經過兩個這個一維數組,便可以計算出一個完整的高斯內核,再利用blur裡面用到的循環方法,就可以算出高斯平滑後的矩陣了。


複製程式碼 程式碼如下:

函數GaussianBlur(__src, __size1, __size2, __sigma1, __sigma2, __borderType, __dst){
if(__src.type && __src.type == "CV_RGBA") ==== .row,
寬度= __src.col,
dst = __dst || new Mat(高度, 寬度, CV_RGBA),
dstData = dst.data;
var sigma1 = __sigma1 || 0,
sigma2 = __sigma2 || __西格瑪1;
var size1 = __size1 || Math.round(sigma1 * 6 1) | Math.round(sigma1 * 6 1) | 1、
尺寸2 = __尺寸2 || Math.round(sigma2 * 6 1) | 數學.round(sigma2 * 6 1) | 1、
尺寸=尺寸1*尺寸2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size必須是奇數。");
返回__src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__src, startY, startX, 0, 0, __borderType),
mData = withBorderM. >mWidth = withBorderMat.col;

var kernel1 = getGaussianKernel(size1, sigma1),
kernel2,
kernel = new Array(size1 * size2); === size2 && sigma1 === sigma2)
kernel2 = kernel1;
else
kernel2 = getGaussianKernel(size2, sigma2);


for(i = kernel2.length; i--;){
for(j = kernel1.length; j--;){
kernel[i * size1 j] = kernel2 [ i] * 內核1[j];
}
}

var newValue, nowX, offsetY, offsetI;

for(i = 高度; i--;) {
offsetI = i * 寬度;
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 c] = newValue;
dstData[(j offsetI) * 4 c] = newValue;
}
dstData[(j offsetI) * 4 3] = mData[offsetY startY * mWidth * 4 (j startX) * 4 3];
}
}

}else{
console.error("不支援的類型");
}
返回目的地;
}


中位數平滑

中位數輔助將每個像素的像素以鄰域(以目前像素為中心的適配器區域)像素的

中位數

取代 。

依然使用blur裡面所佔用的循環,只要得到核中的所有值,再透過排序便可以得到中位數,然後依靠該值替代。


複製程式碼 程式碼如下:
functionmedianBlur(__s__srcsize Type__ {
if(__src.type && __src .type == "CV_RGBA"){
var height = __src.row,
寬度= __src.col,
dst = __dst || new Mat(高度, 寬度, CV_RGBA),
dstData = dst.data;
var size1 = __size1 || 3、
尺寸2 = __尺寸2 ||尺寸1,
尺寸=尺寸1*尺寸2;
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("size必須是奇數");
回傳__src;
}
var startX = Math.floor(size1 / 2),
startY = Math.floor(size2 / 2);
var withBorderMat = copyMakeBorder(__src,orderstartY, startX, __bType ),
mData = withBorderMat.data,
mWidth = withBorderMat.col;

var newValue = [], nowX, offsetY, offsetI;
var i, j, c, y,, j, j, c, y, j x;

for(i = 高度; i--;){
offsetI = i * 寬度;
for(j = width; j--;){
for(c = 3; c--;){
for(y = size2; y--;){
offsetY = (y i) * m寬度* 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("型別不支援");
}
回傳目的地;
};


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板