はじめに 前回の記事では、エッジ勾配計算関数について説明しました。今回は画像ピラミッドについて学びます。
画像ピラミッド? 画像ピラミッドは、コンピューター ビジョン アプリケーションで広く使用されています。
画像ピラミッドは画像のコレクションです。コレクション内のすべての画像は同じ元の画像に由来し、元の画像を継続的にダウンサンプリングすることによって取得されます。
2 つの一般的な画像ピラミッドがあります :
•ガウス ピラミッド: ダウンサンプリングに使用されます
•ラプラシアン ピラミッド: 下のレベルの画像から上部の非サンプリング画像を再構築するために使用されます。ピラミッド
ガウス ピラミッド
ピラミッドと同様に、ガウス ピラミッドは基礎となる元の画像を徐々にダウンサンプリングし、ますます小さくなります。
では、画像の次のレイヤーを取得するにはどうすればよいでしょうか? まず、ガウス カーネルで畳み込みます。
次に、偶数番号の行と列をすべて削除します。
次のレベルの画像は前のレベルの約 1/4 であることがわかります。
では、どうすれば上向きに変化できるのでしょうか? まず画像の行と列を元のサイズの 2 倍に拡大し、追加した行と列を 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 = ((width & 1) width) / 2,
dHeight = ((height & 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 kernel = [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 *
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;
newValue = (mData[offsetY nowX] * 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 } */ );
戻り値
};
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 kernel = [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] * kernel[(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 を返します。
};
效果图