머리말 이전 글에서 Edge Gradient 계산 기능에 대해 설명했습니다. 이번 글에서는 이미지 피라미드에 대해 알아보겠습니다.
이미지 피라미드? 이미지 피라미드는 컴퓨터 비전 애플리케이션에 널리 사용됩니다.
이미지 피라미드는 이미지 모음입니다. 컬렉션의 모든 이미지는 동일한 원본 이미지에서 유래하며 원본 이미지를 지속적으로 다운샘플링하여 얻습니다.
일반적인 이미지 피라미드에는 두 가지가 있습니다. :
•가우스 피라미드: 다운샘플링에 사용
•라플라시안 피라미드: 하위 레벨 이미지에서 샘플링되지 않은 상위 이미지를 재구성하는 데 사용됩니다. 피라미드
가우스 피라미드
피라미드와 유사하게 가우시안 피라미드는 기본 원본 이미지를 점차적으로 다운샘플링하여 점점 작아집니다.
그럼 다음 이미지 레이어를 얻는 방법은 무엇일까요? 먼저 가우스 커널로 컨볼루션합니다.
그런 다음 짝수 행과 열을 모두 삭제합니다.
다음 레벨 이미지가 이전 레벨의 약 1/4 수준임을 알 수 있습니다.
그럼 어떻게 위로 변신할 수 있을까요? 먼저 이미지 행과 열을 원래 크기의 두 배로 확장한 다음 추가된 행과 열을 0으로 채웁니다.
마지막으로 가우스 커널에 4만 곱하고 컨볼루션 후에 수행합니다.
가우스 피라미드 구현
var pyrDown = function(__src, __dst){
__src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */); == " CV_RGBA"){
var width = __src.col,
height = __src.row,
dWidth = ((너비 & 1) 너비) / 2,
dHeight = ((높이 & 1) 높이) / 2,
sData = __src.data,
dst = __dst || new Mat(dHeight, dWidth, CV_RGBA),
dstData = dst.data = copyMakeBorder(__src , 2, 2, 0, 0),
mData = withBorderMat.data,
mWidth = withBorderMat.col;
var newValue, nowX, offsetY, offsetI, dOffsetI, i, j; 🎜>var 커널 = [1, 4, 6, 4, 1,
, 16, 24, 16, 4,
, 24, 36, 24, 6,
, 16, 24, 16, 4,
, 4, 6, 4, 1
];
for(i = dHeight; i--;){
dOffsetI = i * dWidth
for(j = dWidth; ; j- -;){
for(c = 3; c--;){
newValue = 0
for(y = 5; y--;){
offsetY = ( y i * 2 ) * mWidth * 4;
for(x = 5; x--;){
nowX = (x j * 2) * 4 c; kernel[y * 5 x]);
}
}
dstData[(j dOffsetI) * 4 c] = newValue / 256
}
dstData[(j dOffsetI) * 4 3] = mData[offsetY 2 * mWidth * 4 (j * 2 2) * 4 3];
}
}
}else{
error(arguments.callee, UNSPPORT_DATA_TYPE/* {line } */ );
return dst;
}
dWidth = ((너비 & 1) 너비) / 2,
dHeight = ((높이) & 1) 높이) / 2
여기서 a & 1은 %2, 즉 2로 나눈 나머지와 같습니다.
구현 시 비효율적이므로 위 단계를 따르지 않았습니다. 대신 원래 행렬의 1/4인 행렬을 직접 만든 다음 컨볼루션 중에 삭제할 행과 열을 건너뛰었습니다.
아래도 마찬가지입니다. 컨볼루션을 생성한 후에는 일부 자리가 0이 되어야 하기 때문에 실제 컨볼루션 과정에서는 커널의 일부 요소가 무시됩니다.
코드 복사
코드는 다음과 같습니다.
var pyrUp = function(__src, __dst){
__src || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
if(__src.type && __src.type == "CV_RGBA"){
var width = __src.col,
height = __src.row,
dWidth = width * 2,
dHeight = 높이 * 2,
sData = __src.data,
dst = __dst || new Mat(dHeight, dWidth, CV_RGBA),
dstData = dst.data;
var withBorderMat = copyMakeBorder(__src, 2, 2, 0, 0),
mData = withBorderMat.data,
mWidth = withBorderMat.col;
var newValue, nowX, offsetY, offsetI, dOffsetI, i, j;
var 커널 = [1, 4, 6, 4, 1,
, 16, 24, 16, 4,
, 24, 36, 24, 6,
, 16, 24, 16 , 4,
, 4, 6, 4, 1
];
for(i = dHeight; i--;){
dOffsetI = i * dWidth;
for(j = dWidth; j--;){
for(c = 3; c--;){
newValue = 0;
for(y = 2 (i & 1); y--;){
offsetY = (y ((i 1) >> 1)) * mWidth * 4;
for(x = 2 (j & 1); x--;){
nowX = (x ((j 1) >> 1)) * 4 c;
newValue = (mData[offsetY nowX] * 커널[(y * 2 (i & 1 ^ 1)) * 5 (x * 2 (j & 1 ^ 1))]);
}
}
dstData[(j dOffsetI) * 4 c] = newValue / 64;
}
dstData[(j dOffsetI) * 4 3] = mData[offsetY 2 * mWidth * 4 (((j 1) >> 1) 2) * 4 3];
}
}
}else{
error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
}
dst를 반환합니다.
};
效果图