「TIPS:画像をファイルに保存するには?」 では、Bitmapクラス(System.Drawing名前空間)のコンストラクタでビットマップのサイズを指定することによりサイズの変更を行っているが、より高品質に、あるいはより低品質に(その代わり高速に)拡大/縮小する方法もある。これにはBitmapクラスのほかに、Graphicsクラス(System.Drawing名前空間)を使用する。
Graphicsクラスは、DrawLine(直線の描画)やDrawRectangle(四角形の描画)、DrawString(文字列の描画)などのメソッドを持つ描画のためのクラスだ。この中の1つであるGraphicsクラスのDrawImageメソッドにより、画像から作成したBitmapオブジェクトを描画することができる。このとき、パラメータとしてサイズを指定することにより画像の拡大/縮小が可能で、さらにGraphicsオブジェクトのInterpolationModeプロパティにより、拡大/縮小時の品質を設定することができる。
例えば、Graphicsオブジェクトが変数g、Bitmapオブジェクトが変数srcだとすると、品質「NearestNeighbor」で、縦横のサイズを2倍に拡大して描画するには次のようにする(NearestNeighborについてはすぐ次で説明する)。
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(src, 0, 0, src.Width * 2, src.Height * 2);
InterpolationModeプロパティには、同名のInterpolationMode列挙体(System.Drawing.Drawing2D名前空間)の値により補間方法を指定する(interpolationは「補間」の意)。この補間方法が拡大/縮小時の品質を左右するものだ。
補間方法について説明する前に、Graphicsオブジェクトについてもう少し説明しておこう。Graphicsオブジェクトには、描画の対象となる「描画面」が含まれる。通常これは、ウィンドウ(つまりはディスプレイ)やプリンタとなるが、描画面としてビットマップも指定することもできる。例えば次のコードでは、640×480のBitmapオブジェクトを作成し、これを描画面としている。
Bitmap dest = new Bitmap(640, 480);
Graphics g = Graphics.FromImage(dest);
このようなコードと、先のコードを組み合わせることによって、特定の補間方法で拡大/縮小したビットマップを得ることができる。
さて、InterpolationMode列挙体の値には、次の表のような補間方法が用意されている。
値 | 補間方法 |
---|---|
Default | 既定の補間モード |
Low | 低品質補間 |
High | 高品質補間 |
NearestNeighbor | 最近傍補間 |
Bilinear | 双一次補間 |
Bicubic | 双三次補間 |
HighQualityBilinear | 高品質双一次補間 |
HighQualityBicubic | 高品質双三次補間 |
このうちDefault、LowおよびHighについては、どのような補間方法が使用されるかはリファレンス・マニュアルにも記述されていないため不明だが、NearestNeighbor(ニアレスト・ネイバー)、Bilinear(バイリニア)、Bicubic(バイキュービック)は、画像処理における補間方法としては代表的なアルゴリズムだ。
次のサンプル・プログラムでは、この.NET TIPSコーナーのアイコン(JPEG画像)を、上の表に挙げたそれぞれの補間方法で縦横10倍に拡大し、InterpolationMode列挙体の名前をファイル名とするPNGファイルで保存する。
// resize.cs
using System;
using System.IO;
using System.Net;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
class ResizeBitmap {
public static void Main() {
string url = "http://www.atmarkit.co.jp/fdotnet/"
+ "dotnettips/index/dotnettips_s.jpg";
WebClient wc = new WebClient();
Stream stream = wc.OpenRead(url);
Bitmap src = new Bitmap(stream);
stream.Close();
int w = src.Width * 10;
int h = src.Height * 10;
Bitmap dest = new Bitmap(w, h);
Graphics g = Graphics.FromImage(dest);
foreach (InterpolationMode im
in Enum.GetValues(typeof(InterpolationMode))) {
if (im == InterpolationMode.Invalid)
continue;
g.InterpolationMode = im;
g.DrawImage(src, 0, 0, w, h);
dest.Save(im.ToString() + ".png", ImageFormat.Png);
}
}
}
// コンパイル方法:csc resize.cs
resize.csのダウンロード
Web上の画像からBitmapオブジェクトを作成する方法については「TIPS:画像を読み込むには?」 で、列挙体で定義されている定数の名前を列挙する方法については「TIPS:列挙体の名前を列挙するには?」 で、またビットマップのファイルへの保存については「TIPS:画像をファイルに保存するには?」 でそれぞれ解説しているので参照していただきたい。
上記のサンプル・プログラムを実行すると、カレント・ディレクトリに8つのPNGファイルが作成される。これらは次のような画像だ(ファイル・サイズの関係から、ここには画像の一部分だけを切り出して掲載している)。
■オリジナル画像
■左から「Default」「Low」「High」「NearestNeighbor」で拡大した画像
■左から「Bilinear」「Bicubic」「HighQualityBilinear」「HighQualityBicubic」で拡大した画像
サンプル・プログラムの実行結果
サンプル・プログラムを実行すると、カレント・ディレクトリに8つの補間方法により拡大を行った8つのPNGファイルが作成される(ファイル・サイズの関係から、ここには画像の一部分だけを切り出して掲載している)。
画像のリサイズ時には、縮小よりも拡大の方が処理は困難とされている。これは、拡大により画像を構成する画素数(ピクセル数)が増えるためだ。拡大後の画像では、元の画像には存在しなかった画素を作り出さなくてはならない。この画素を作り出すアルゴリズムが補間方法である。
NearestNeighborは、存在しない画素を最も近くにある画素で補間する方法だ。上の実行結果からも分かるとおり、これは元画像の各ピクセルを単純に拡大したものとなる。この方法で得られる画像品質は高くないが、当然処理速度は最速だ。一方、Bilinearでは周囲の4ピクセル、Bicubicではさらに周囲の点を含めた16ピクセルから、線形あるいは3次元関数を用いて補間を行う。実行結果から、Bilinearはぼけた感じになり、それに比べてBicubicではシャープな感じになることが分かる。
これら3つの中では、Bicubicが一般的によく用いられるが、これが最適な補間方法になるかどうかは、元の画像の色調によるところも大きい。大量の、あるいは巨大な画像を処理するような実用システムで補間方法を選択する場合には、最終画像の品質ばかりでなく、その処理速度も考慮しなければならない。
カテゴリ:クラス・ライブラリ 処理対象:ビットマップ
使用ライブラリ:Bitmapクラス(System.Drawing名前空間)
使用ライブラリ:Graphicsクラス(System.Drawing名前空間)
使用ライブラリ:InterpolationMode列挙体(System.Drawing.Drawing2D名前空間)
関連TIPS:画像を読み込むには?
関連TIPS:列挙体の名前を列挙するには?
関連TIPS:画像をファイルに保存するには?
■この記事と関連性の高い別の.NET TIPS
Copyright© Digital Advantage Corp. All Rights Reserved.