다음은 OpenCV 2.4 C 스무딩 처리 및 OpenCV 2.4 C 가장자리 그라디언트 계산 관련 내용에 대한 직접 참조입니다.
평균 평활화는 실제로 커널 요소가 모두 1이고 수학적 표현은 다음과 같습니다.
평균 스무딩 기능을 구현해 보겠습니다.
함수 흐림(__src, __size1, __size2, __borderType, __dst){
if(size1 % 2 !== 1 || size2 % 2 !== 1){
console.error("크기는 홀수여야 합니다." );
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; , j, c , y, x;
for(i = 높이; i--;){
offsetI = i * 너비;
for(j = 너비; j--;) {
for(c = 3; c--;){
newValue = 0;
for(y = size2; y--;){
offsetY = (y i) * mWidth * 4 ;
for(x = size1; offsetI) * 4 c] = newValue / size;
}
dstData[(j offsetI) * 4 3] = mData[offsetY startY * mWidth * 4 (j startX ) * 4 3];
}
}
}else{
console.error("지원되지 않는 유형입니다. ");
}
dst 반환;
}
여기서 size1과 size2는 각각 코어의 가로 및 세로 크기이며 양의 홀수여야 합니다.
가우스 스무딩
가장 유용한 필터입니다(가장 빠르지는 않지만). 가우시안 필터링은 입력 배열의 각 픽셀을 가우시안 커널
으로 컨볼루션하고 컨볼루션 합을 출력 픽셀 값으로 처리하는 것입니다.
1차원 가우스 함수를 살펴보면 가운데가 크고 양쪽이 작은 함수임을 알 수 있습니다.
그래서 가우시안 필터의 가중치 숫자는 중앙이 크고 주변이 작습니다.
2차원 가우스 함수는 다음과 같습니다.
여기서
은 평균(최고값에 해당하는 위치),
은 표준편차(변수)를 나타냅니다.
및 변수
각각 평균이 있고 표준편차가 있습니다.
여기서는 OpenCV 구현을 언급하고 있는데, 아직 분리 필터를 사용하지 않았기 때문에 최적화의 여지가 있을 것입니다.
먼저 getGaussianKernel을 만들어 가우시안 필터의 1차원 배열을 반환합니다.
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 .10937 5,0.21875, 0.28125, 0.21875, 0.109375, 0.03125]
];
varfixedKernel = __n & 2 == 1 && __n <= SMALL_GAUSSIAN_SIZE && __sigma <= 0 ? 탭[__n > & gt; 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 = 고정커널 ? 고정커널[i] : Math.exp(scale2X * x * x)
커널[i] = t; = t;
}
sum = 1 / sum;
for(i = __n; i--;){
커널[i] *= sum; >}
return kernel;
};
그런 다음 두 개의 1차원 배열을 통해 완전한 가우시안 커널을 계산한 다음 블러에서 사용되는 루프 방법을 사용합니다. , 가우스 평활화된 행렬을 계산할 수 있습니다.
코드 복사 코드는 다음과 같습니다.
함수 GaussianBlur(__src, __size1, __size2, __sigma1, __sigma2, __borderType, __dst){
if(__src.type && __src.type == "CV_RGBA"){
var height = __src .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) | 1,
size2 = __size2 || Math.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 = 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] * 커널1[j];
}
}
var newValue, nowX, offsetY, offsetI;
for(i = 높이; i--;){
offsetI = i * 너비;
for(j = 너비; 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] * 커널[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("不支持的类型");
}
dst를 반환합니다.
}
中值平滑
中值滤波将图image的每个 Image素用邻域 (以当前 Image素为心的正方form区域) Image素的
中值代替 。
블러리 인터페이스를 사용하여 블러리면을 사용하여 到적循环, 只要得到核中的所有值,再过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(높이, 너비, 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必须是奇数");
__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 = 높이; i--;){
offsetI = i * 너비;
for(j = 너비; 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("类型不支持");
}
dst를 반환합니다.
};