平滑处理实现原理(2)

其中 

 为均值 (峰值对应位置),

\sigma

 代表标准差 (变量  和 变量  各有一个均值,也各有一个标准差)。

这里参考OpenCV的实现,不过应该还有优化空间,因为还没用到分离滤波器。

首先我们做一个getGaussianKernel来返回高斯滤波器的一维数组。

复制代码 代码如下:


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 ? smallGaussianTab[__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;
};


然后通过两个这个一维数组,便可以计算出一个完整的高斯内核,再利用blur里面用到的循环方法,就可以算出高斯平滑后的矩阵了。

复制代码 代码如下:


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必须是奇数。");
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;
}

中值平滑

中值滤波将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的

中值代替 。

依然使用blur里面用到的循环,只要得到核中的所有值,再通过sort排序便可以得到中值,然后锚点由该值替代。

复制代码 代码如下:


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必须是奇数");
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;
};

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdddxg.html