image - 解像度 - サイズを変えずに双一次補間で画像のサイズを変更する



画像 解像度 変更 フリー (1)

画像を拡大する方法がいくつかありますが、画像を縮小する方法はありません。 現在、最近傍法を使用しています。 MATLABでimresize関数を使用せずに双線形補間でこれを行うにはどうすればよいでしょうか。


あなたのコメントでは、バイリニア補間を使って画像のサイズを変更したいと述べました。 双線形補間アルゴリズムはサイズに依存しないことに注意してください。 画像を拡大したり縮小したりするのと同じアルゴリズムを使うことができます。 ピクセル位置をサンプリングするための正しい倍率は、指定した出力寸法によって異なります。 ただし、これによってコアアルゴリズムが変わることはありません

コードを始める前に、 Richard Alan PetersのIIデジタル画像処理スライド 、特にスライド#59を紹介します。 MATLABにやさしい双一次補間の実行方法についての優れた実例と疑似コードがあります。 自己完結型であるために、私は私たちがそれに従ってそれをコーディングできるように、ここに彼のスライドを含めるつもりです。

これを行う関数を書きましょう。 この関数は、2つの要素からなる配列だけでなく、カラーまたはグレースケールのいずれかの画像( imreadを通じてimread )をimreadます。サイズを変更する画像と出力サイズは、2つの要素からなります。あなたが望む最終的なリサイズ画像。 この配列の最初の要素は行になり、この配列の2番目の要素は列になります。 このアルゴリズムを実行して、次の疑似コードを使用して出力ピクセルカラー/グレースケール値を計算します。

function [out] = bilinearInterpolation(im, out_dims)

    %// Get some necessary variables first
    in_rows = size(im,1);
    in_cols = size(im,2);
    out_rows = out_dims(1);
    out_cols = out_dims(2);

    %// Let S_R = R / R'        
    S_R = in_rows / out_rows;
    %// Let S_C = C / C'
    S_C = in_cols / out_cols;

    %// Define grid of co-ordinates in our image
    %// Generate (x,y) pairs for each point in our image
    [cf, rf] = meshgrid(1 : out_cols, 1 : out_rows);

    %// Let r_f = r'*S_R for r = 1,...,R'
    %// Let c_f = c'*S_C for c = 1,...,C'
    rf = rf * S_R;
    cf = cf * S_C;

    %// Let r = floor(rf) and c = floor(cf)
    r = floor(rf);
    c = floor(cf);

    %// Any values out of range, cap
    r(r < 1) = 1;
    c(c < 1) = 1;
    r(r > in_rows - 1) = in_rows - 1;
    c(c > in_cols - 1) = in_cols - 1;

    %// Let delta_R = rf - r and delta_C = cf - c
    delta_R = rf - r;
    delta_C = cf - c;

    %// Final line of algorithm
    %// Get column major indices for each point we wish
    %// to access
    in1_ind = sub2ind([in_rows, in_cols], r, c);
    in2_ind = sub2ind([in_rows, in_cols], r+1,c);
    in3_ind = sub2ind([in_rows, in_cols], r, c+1);
    in4_ind = sub2ind([in_rows, in_cols], r+1, c+1);       

    %// Now interpolate
    %// Go through each channel for the case of colour
    %// Create output image that is the same class as input
    out = zeros(out_rows, out_cols, size(im, 3));
    out = cast(out, class(im));

    for idx = 1 : size(im, 3)
        chan = double(im(:,:,idx)); %// Get i'th channel
        %// Interpolate the channel
        tmp = chan(in1_ind).*(1 - delta_R).*(1 - delta_C) + ...
                       chan(in2_ind).*(delta_R).*(1 - delta_C) + ...
                       chan(in3_ind).*(1 - delta_R).*(delta_C) + ...
                       chan(in4_ind).*(delta_R).*(delta_C);
        out(:,:,idx) = cast(tmp, class(im));
    end

上記のコードを取り出し、それをコピーしてbilinearInterpolation.mというファイルに貼り付けて保存します。 このファイルを保存した作業ディレクトリを必ず変更してください。

sub2indsub2indを除いて、すべてがアルゴリズムに準拠しているようです。 meshgridは説明がとても簡単です。 あなたがしているのは、 (x,y)座標の2次元グリッドを指定することだけです。ここで、あなたの画像のそれぞれの位置は、 (x,y)または列と行の座標のペアを持ちます。 meshgridを使用forてグリッドを作成すると、続行する前に必要なアルゴリズムから正しいピクセル位置がすべて生成されるforループを回避できます。

sub2indがどのようにsub2indするかは、それが2D行列の行と列の位置を取り込むということです(まあ...それは本当にあなたが望むどんな次元の次元でも構いません)、そしてそれは単一の線形インデックスを出力します。 MATLABが行列をどのようにインデックス付けするかを知らない場合は、2つの方法で行列の要素にアクセスできます。 行と列を使用して必要なものを取得することも、 列主索引を使用することもできます。 このマトリックスの例を見てみましょう。

A = 

1  2  3  4  5
6  7  8  9  10
11 12 13 14 15

9という数字にアクセスしたい場合は、ほとんどの人がデフォルトにする傾向があるA(2,4)を実行できます。 単一の番号を使用して番号9にアクセスするもう1つの方法があります。これはA(11)です。 MATLABは、その行列のメモリを優先形式でレイアウトします。 つまり、この行列を使って、そのすべてのを単一の配列にスタックすると、次のようになります。

A = 

1
6
11
2
7
12
3
8
13
4
9
14
5
10
15

今、あなたが要素番号9にアクセスしたい場合は、この配列の11番目の要素にアクセスする必要があります。 補間ビットに戻ると、 forループを実行せずに補間を実行するfor画像内の要素にアクセスしてベクトル化したい場合、 sub2indは非常に重要です。 そのため、擬似コードの最後の行を見ると、 rcr+1 、およびc+1要素にアクセスする必要があります。 これらのすべてが2D配列であることに注意してください。ここで、これらすべての配列の各一致位置の各要素は、最終出力ピクセルを生成するためにサンプリングする必要がある4つのピクセルを示しています。 sub2indの出力 、出力イメージと同じサイズの2次元配列になります。 ここで重要なのは、 rcr+1 、およびc+1の2D配列の各要素が、アクセスしたいイメージの列メジャーインデックスを与え、これをイメージへの入力としてスローすることによって得られることです。インデックス作成の場合は、必要なピクセル位置を正確に取得します。

アルゴリズムを実装するときに追加したい、いくつかの重要な微妙な点があります。

  1. 画像の外側を補間するときに画像にアクセスするためのインデックスは、範囲外にならないように1または行数または列数に設定されていることを確認する必要があります。 実際には、画像の右または下に伸びる場合は、補間によって右または下の1つ上のピクセルにアクセスしている必要があるため、これを最大値の1つに設定する必要があります。 これはあなたがまだ限界内にいることを確認するでしょう。

  2. また、出力画像が入力画像と同じクラスにキャストされていることを確認する必要があります。

  3. 各ループを独自に補間するforループを実行しました。 あなたはbsxfunを使ってこれを賢く行うことができbsxfun 、しかし私は単純化のためにforループを使うことに決めました、そしてそれであなたはアルゴリズムと一緒に従うことができるように。

これを示す例として、MATLABのシステムパスの一部であるonion.pngイメージを使用しましょう。 この画像の元のサイズは135 x 198です。 この画像を大きくして、元の画像の2倍のサイズの270 x 396て補間しましょう。

im = imread('onion.png');
out = bilinearInterpolation(im, [270 396]);
figure;
imshow(im);
figure;
imshow(out);

上記のコードは、各寸法を2倍に増やすことによって画像を補間し、元の画像と拡大された画像を含む別の図を表示します。 これは私が両方のために得るものです:

同様に、画像を半分に縮小しましょう。

im = imread('onion.png');
out = bilinearInterpolation(im, [68 99]);
figure;
imshow(im);
figure;
imshow(out);

135の半分は行の67.5ですが、私は68に切り上げました。これは私が得るものです:

私が実際に気づいたことの一つは、バイリニアによるアップサンプリングはバイキュービックのような他のスキームやLanczosと比較してもまともな性能を持っているということです。 ただし、細部を削除しているので画像を縮小しているときは、最近傍で十分です。 私はバイリニアまたはバイキュービックがやりすぎると思います。 私はあなたのアプリケーションが何であるかについてはわかりませんが、異なる補間アルゴリズムを試してみて、結果からあなたが好きなものを見てください。 バイキュービックは別の話です、そして私はそれを練習としてあなたに任せます。 あなたが興味を持っているならば、私があなたが言及したそれらのスライドはバイキュービック補間に関する材料を持っていますか。

がんばろう!





interpolation