C#とソーベルフィルタを用いて、画像から輪郭(エッジ)を抽出する方法について紹介します。
## ソーベルフィルタで輪郭検出(C#)
ソーベルフィルタは空間1次微分を計算し、輪郭を検出するフィルタです。
上、右、下、左、右上、右下、左下、左上の8方向、上下左右の4方向同時、8方向同時など様々な輪郭を検出できます。
| – | ソーベルフィルタの原理についてはこちら |
|---|---|
| 参考 | ソーベルフィルタによる輪郭抽出の原理 |
今回はこれをC#で実装してみました。
## ソースコード
プログラムのソースコードは下記の通りです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
namespace SobelFilter
{
class Program
{
static void Main(string[] args)
{
// 画像の読み込み(グレースケールに変換)
byte[,] img = LoadImageGray("src.jpg");
// フィルタ用のマスク
const int kernelSize = 3;
double[,] kernel = new double[kernelSize, kernelSize]{
{-1.0,-2,-2},
{0.0,0.0,0.0},
{1.0,2.0,1.0}};
// フィルタ処理
byte[,] img2 = Filter(img, kernel);
// 画像保存
SaveImage(img2, "dst.jpg");
}
// 画像をグレースケール変換して読み込み
static byte[,] LoadImageGray(string filename)
{
Bitmap img = new Bitmap(filename);
int w = img.Width;
int h = img.Height;
byte[,] dst = new byte[w, h];
// bitmapクラスの画像ピクセル値を配列に挿入
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
// グレイスケールに変換
dst[j, i] = (byte)((img.GetPixel(j, i).R + img.GetPixel(j, i).B + img.GetPixel(j, i).G) / 3);
}
}
return dst;
}
static void SaveImage(byte[,] src, string filename)
{
// 画像データの幅と高さを取得
int w = src.GetLength(0);
int h = src.GetLength(1);
Bitmap img = new Bitmap(w, h);
// ピクセル値のセット
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
img.SetPixel(j, i, Color.FromArgb(src[j, i], src[j, i], src[j, i]));
}
}
// 画像の保存
img.Save(filename);
}
static byte[,] Filter(byte[,] src, double[,] kernel)
{
// 縦横サイズを配列から読み取り
int w = src.GetLength(0);
int h = src.GetLength(1);
// マスクサイズの取得
int kernelSize = kernel.GetLength(0);
// 出力画像用の配列
byte[,] dst = new byte[w, h];
// 画像処理
for (int i = 0; i < h; i++)
{
for (int j = 0; j < w; j++)
{
double sum = 0;
for (int k = -kernelSize / 2; k <= kernelSize / 2; k++)
{
for (int n = -kernelSize / 2; n <= kernelSize / 2; n++)
{
if (j + n >= 0 && j + n < w && i + k >= 0 && i + k < h)
{
sum += src[j + n, i + k] * kernel[n + kernelSize / 2, k + kernelSize / 2];
}
}
}
dst[j, i] = DoubleToByte(sum);
}
}
return dst;
}
// double型をbyte型に変換
static byte DoubleToByte(double num)
{
if (num > 255.0) return 255;
else if (num < 0) return 0;
else return (byte)num;
}
}
}
## 実行結果
プログラムの実行結果は下記の通りです。
■入力画像(左)、出力画像(右)


出力画像を見ると、輪郭の部分が白くなっている、つまり画素値が大きいことがわかります。
| - | 関連ページ |
|---|---|
| 1 | ■C#で画像処理入門 |
| 2 | ■C#入門】基礎文法とサンプル集 |


コメント