■8近傍ロジック
・(x, y) の8近傍(上下左右+斜め4方向)
8カ所のうち、隣接する箇所があれば、クラスタリングする。なければ、違うクラスタを探す。
(x-1,y-1) (x, y-1) (x+1,y-1)
(x-1, y ) (x, y ) (x+1, y )
(x-1,y+1) (x, y+1) (x+1,y+1)
■ ソースコード
public static int[,] Kinbo8(int[,] binary, out int numLabels)
{
int height = binary.GetLength(0); // 行数
int width = binary.GetLength(1); // 列数
int[,] label = new int[height, width]; // ラベル配列
int labelId = 1;
// 8近傍のdx, dy
int[] dx = { -1, 0, 1, -1, 1, -1, 0, 1 }; // 左上、上、右上、左、右、左下、下、右下
int[] dy = { -1, -1, -1, 0, 0, 1, 1, 1 }; // 左上、上、右上、左、右、左下、下、右下
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// クラスタが空じゃなく、ラベルが 0のとき
if (binary[y, x] != 0 && label[y, x] == 0)
{
// 新しいラベル付与
Queue<(int, int)> queue = new Queue<(int, int)>();
queue.Enqueue((y, x));
label[y, x] = labelId; // ラベル付与
// クラスタ探索 *** BFS(幅優先探索)*** でつながっている全ピクセルを調べて、ラベリング。
// つながってるピクセルは全部同じlabelIdにする。
while(queue.Count > 0)
{
var (cy, cx) = queue.Dequeue(); // 現在のピクセル位置
// 8近傍をチェック
for (int d = 0; d < 8; d++)
{
int ny = cy + dy[d]; // 新しいy座標
int nx = cx + dx[d]; // 新しいx座標
// 画面外チェック
if (ny > 0 && ny < height && nx >= 0 && nx < width) // 画面内
{
// クラスタが空じゃなく、ラベルが 0のとき
if (binary[ny, nx] != 0 && label[ny, nx] == 0)
{
label[ny, nx] = labelId; // ラベル付与
queue.Enqueue((ny, nx)); // キューに追加
}
}
}
}
// 次のラベルIDへ
labelId++;
}
}
}
numLabels = labelId - 1; // ラベル数を設定
return label;
}