端くれプログラマの備忘録 C#,画像処理 [C#] 画像を矩形で切り取る (Bitmap.Clone)

[C#] 画像を矩形で切り取る (Bitmap.Clone)

以前にも同じ処理について書いたけど、MSDNを眺めていたら別の方法を見つけたので試してみる。

Bitmap.Clone メソッド (Rectangle, PixelFormat) (System.Drawing)
http://msdn.microsoft.com/ja-jp/library/ms141944(v=vs.110).aspx

Rectangle rect = new Rectangle(50, 80, 200, 150);
Bitmap dest = image.Clone(rect, image.PixelFormat);

コードはたった2行。ちなみに以前に書いたGraphicsオブジェクトを使う処理だと

Bitmap dest = new Bitmap(200, 150, image.PixelFormat);
Graphics g = Graphics.FromImage(dest);
Rectangle srcRect = new Rectangle(50, 80, 200, 150);
Rectangle desRect = new Rectangle(0, 0, 200, 150);
g.DrawImage(image, desRect, srcRect, GraphicsUnit.Pixel);
g.Dispose();

コードは6行になる。単純計算でコーディング量は3倍。まあ、2行でも6行でも大した量じゃないけど。

処理速度の比較 – Bitmap.Cloneメソッド vs Graphicsオブジェクト

パフォーマンスが同じならコーディング量は少ないほうがいい。処理速度を検証しよう。

特定ディレクトリ中の70個のJPEGファイルをスキャンして、1つずつ読み込んで固定サイズに切り取り、別フォルダに保存し直すだけのプログラムを書いた。それぞれの方法で10回ずつ処理して所要時間を計測してみる。

using System.IO;
using System.Drawing.Imaging;
using System.Diagnostics;

for (int i = 0; i < 10; i++) // loop for 10 times
{
    string[] files = Directory.GetFiles(@"C:\Temp\Photo");
    Stopwatch sw = new Stopwatch();
    sw.Start();
    foreach (string file in files)
    {
        string file2 = Path.Combine(@"C:\Temp\Photo2", Path.GetFileName(file));

        Bitmap imgSrc = new Bitmap(file);

        Bitmap imgDst = image1(imgSrc);
        //Bitmap imgDst = image2(imgSrc);
        imgDst.Save(file2, ImageFormat.Jpeg);
        imgDst.Dispose();
        imgSrc.Dispose();
    }
    sw.Stop();
    Debug.WriteLine("{0}: Elapsed time = {1} ms", i+1, sw.ElapsedMilliseconds);
}

// crop using Graphics object
Bitmap image1(Bitmap image)
{
    Bitmap dest = new Bitmap(200, 150, image.PixelFormat);
    Graphics g = Graphics.FromImage(dest);
    Rectangle srcRect = new Rectangle(50, 80, 200, 150);
    Rectangle desRect = new Rectangle(0, 0, 200, 150);
    g.DrawImage(image, desRect, srcRect, GraphicsUnit.Pixel);
    g.Dispose();
    return dest;
}

// crop using Bitmap.Clone method
Bitmap image2(Bitmap image)
{
    Rectangle rect = new Rectangle(50, 80, 200, 150);
    return image.Clone(rect, image.PixelFormat);
}

テスト結果 (処理時間)

// Graphicsオブジェクトを使った画像切り取り
1: Elapsed time = 1646 ms
2: Elapsed time = 1621 ms
3: Elapsed time = 1617 ms
4: Elapsed time = 1574 ms
5: Elapsed time = 1657 ms
6: Elapsed time = 1557 ms
7: Elapsed time = 1723 ms
8: Elapsed time = 1567 ms
9: Elapsed time = 1655 ms
10: Elapsed time = 1561 ms
// Bitmap.Cloneメソッドによる画像切り取り
1: Elapsed time = 3216 ms
2: Elapsed time = 2981 ms
3: Elapsed time = 3074 ms
4: Elapsed time = 3300 ms
5: Elapsed time = 3096 ms
6: Elapsed time = 2939 ms
7: Elapsed time = 3097 ms
8: Elapsed time = 3222 ms
9: Elapsed time = 2949 ms
10: Elapsed time = 2987 ms

結果はBitmap.Cloneを使った切り取り処理のほうが倍近く遅かった。

Bitmap.Cloneメソッドは簡単だけど処理は遅いという結論。