C#での画像処理 – 基本編

C#での画像処理、2回目は基本編と銘打ってよくある画像処理を用意します。

1回目のデータ構造を使った画像処理の例を出していませんでした。画像処理の基本としてよくある線形フィルタ等を用意してみました。

namespace NormalizeCorrelation
{
    using System;
    using System.Collections.Generic;

    internal static class MonochromeExtension
    {

        internal static MonochromeImage Invert(this MonochromeImage srcImage)
        {
            int dstWidth = srcImage.Width;
            int dstHeight = srcImage.Height;
            MonochromeImage dstImage = new MonochromeImage(dstWidth, dstHeight);
            for (int y = 0; y < dstHeight; y++)
            {
                for (int x = 0; x < dstWidth; x++)
                {
                    dstImage[x, y] = (byte)(~srcImage[x,y]);
                }
            }
            return dstImage;
        }

        internal static MonochromeImage LowPassFilter(this MonochromeImage srcImage)
        {
            int dstWidth = srcImage.Width;
            int dstHeight = srcImage.Height;
            MonochromeImage dstImage = new MonochromeImage(dstWidth, dstHeight);
            for (int y = 0; y < dstHeight; y++)
            {
                for (int x = 0; x < dstWidth; x++)
                {
                    int sum = srcImage[x - 1, y - 1] + srcImage[x, y - 1] + srcImage[x + 1, y - 1] +
                              srcImage[x - 1, y] + srcImage[x, y] + srcImage[x + 1, y] +
                              srcImage[x - 1, y + 1] + srcImage[x, y + 1] + srcImage[x + 1, y + 1];
                    dstImage[x, y] = (byte)( sum / 9);
                }
            }
            return dstImage;
        }

        internal static MonochromeImage ScalingHalf(this MonochromeImage srcImage)
        {
            int dstWidth = srcImage.Width / 2;
            int dstHeight = srcImage.Height/2;
            MonochromeImage dstImage = new MonochromeImage(dstWidth, dstHeight);
            for (int y = 0; y < dstHeight; y++)
            {
                for (int x = 0; x < dstWidth; x++)
                {
                    int sum = srcImage[2 * x, 2 * y] + srcImage[2 * x + 1, 2 * y] +
                              srcImage[2 * x, 2 * y + 1] + srcImage[2 * x + 1, 2 * y + 1];
                    dstImage[x, y] = (byte)(sum / 4);
                }
            }
            return dstImage;
        }

        internal static MonochromeImage LaplacianFilter(this MonochromeImage srcImage )
        {
            int dstWidth = srcImage.Width;
            int dstHeight = srcImage.Height;
            MonochromeImage dstImage = new MonochromeImage(dstWidth, dstHeight);
            for (int y = 0; y < dstHeight; y++)
            {
                for (int x = 0; x < dstWidth; x++)
                {
                    int rowVal = srcImage[x - 1, y - 1] + srcImage[x, y - 1] + srcImage[x + 1, y - 1] +
                                 srcImage[x - 1, y] - 8 * srcImage[x, y] + srcImage[x + 1, y] +
                                 srcImage[x - 1, y + 1] + srcImage[x, y + 1] + srcImage[x + 1, y + 1];
                    int absVal = Math.Abs(rowVal);
                    dstImage[x, y] = (byte)((byte.MaxValue < absVal) ? byte.MaxValue : absVal);
                }
            }
            return dstImage;
        }

        internal static MonochromeImage MedianFilter(this MonochromeImage srcImage)
        {
            int dstWidth = srcImage.Width;
            int dstHeight = srcImage.Height;
            MonochromeImage dstImage = new MonochromeImage(dstWidth, dstHeight);
            for (int y = 0; y < dstHeight; y++)
            {
                for (int x = 0; x < dstWidth; x++)
                {
                    var items = new List<byte>(){
                        srcImage[x - 1, y - 1],
                        srcImage[x, y - 1],
                        srcImage[x + 1, y - 1],
                        srcImage[x - 1, y],
                        srcImage[x, y],
                        srcImage[x + 1, y],
                        srcImage[x - 1, y + 1],
                        srcImage[x, y + 1],
                        srcImage[x + 1, y + 1]
                    };
                    items.Sort();
                    dstImage[x, y] = items[4];
                }
            }
            return dstImage;
        }
    }
}

上の通り、データ型に対する拡張メソッドとして定義すると次々と画像処理をさせたいときに以下のようなコードがかけます。

        private void UpdateDisplayImage(Bitmap img)
        {
            Bitmap capureImage = (Bitmap)img.Clone();
            MonochromeImage image = new MonochromeImage(capureImage);
            // ローパスフィルタかけて、1/2にダウンサンプリング、
            // その後ラプラシアンフィルタでエッジ抽出。
            var resultImage = image.LowPassFilter().ScalingHalf().LaplacianFilter();

            capturedPictureBox.Image = resultImage.GetAsBitmap();
        }

拡張メソッドばんざい。これは以前にUSBカメラをC#で使うのコードの一部です。組み合わせて動かすとこんな感じ。

imageprocessbycsharp

リアルタイムに更新される画像で画像処理を確認できるのはわかりやすくてGOOD。次回はもう少し自分でもやってみたくなる(?)内容に進む予定です;

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中