SKProgramLab

Let's Enjoy Programming! ~画像処理/IoT/機械学習など~

C#/VB.NETで画像処理⑨<画像のラベリング処理>

こんにちは、SKです。
f:id:SKProgramLab:20200310203357p:plain:w100

C#/VB.NETで画像処理シリーズの第9弾。
カメラ画像のラベリング処理を実装します。

ラベリングとは、二値化画像の白領域の連結領域を抽出する処理のことです。前回の輪郭抽出処理と似ていますが、ラベリングは各領域の面積が簡単に取り出せたり、使い勝手が良い関数です。

OpenCVSharpの作者さんも好きだと公言しているのがこのラベリング。下記の記事は本当に参考になります。

★OpenCVSharpのラベリングについて

schima.hatenablog.com

OpenCVSharpとは?

skprogramlab.hatenablog.com

(前回)画像の輪郭抽出

skprogramlab.hatenablog.com

動画手順

youtu.be

①ラベリングボタンを配置する

フォーム上にボタンを配置します。
このボタンの押下イベントで、ラベリングフラグのTrue/Falseを切り替えます。フラグがTrueの時に、Process関数内で画像の二値化→ラベリング処理を行い、各ラベリング領域に矩形を描画してPictureBoxに表示します。 表示テキストは"Labeling"。 f:id:SKProgramLab:20200407220902p:plain

ラベリングフラグのbool変数isLabelingを追加します。
f:id:SKProgramLab:20200407220951p:plain

②画像を二値化する

まずは前回同様、画像を二値化し、Mat変数grayに格納します。 f:id:SKProgramLab:20200407221125p:plain
Usingで定義することを忘れずに。

(参考)Usingについて

C# Tips −usingを使え、使えったら使え(^^)−

③ラベリング処理

ラベリングには、OpenCVSharpのConnectedComponentsEx関数を使用します。これは、OpenCVのConnectedComponents関数をより使いやすくShimat先生が改良した独自の関数です。

ConnectedComponentsEx関数

OpenCvSharpをつかう その24 (OpenCV 3.0のラベリング) - schima.hatenablog.com
引数には二値化画像を渡すのみ。そして戻り値のラベリングデータBlobsをForループで回し1つずつアクセスできます。超簡単!

Cv2.Rectangle関数で各領域の矩形を描画します。

private void Process(Mat img)
{
    if (isLabeling)
    {
        using (Mat gray = new Mat(img.Size(), MatType.CV_8UC1))
        {
            Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
            Cv2.Threshold(gray, gray, 0, 255, ThresholdTypes.Otsu);
            ConnectedComponents cc = Cv2.ConnectedComponentsEx(gray);
            foreach (var blob in cc.Blobs.Skip(1))
            {
                img.Rectangle(blob.Rect, Scalar.Lime, 2);
            }
        }
    }
}

f:id:SKProgramLab:20200407223625p:plain

実行します。
起動時 f:id:SKProgramLab:20200406220559p:plain
Contours押下時
f:id:SKProgramLab:20200407223716p:plain

最後に、コード全文を載せておきます。
C#

using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Task.Run(() =>
            {
                using (VideoCapture v = new VideoCapture(0))
                using (Mat img = new Mat())
                {
                    while (true)
                    {
                        v.Read(img);
                        Process(img);
                        pictureBox1.Image = BitmapConverter.ToBitmap(img);
                    }
                }
            });
        }

        private bool isLabeling = false;

        private void Process(Mat img)
        {
            if (isLabeling)
            {
                using (Mat gray = new Mat(img.Size(), MatType.CV_8UC1))
                {
                    Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
                    Cv2.Threshold(gray, gray, 0, 255, ThresholdTypes.Otsu);
                    ConnectedComponents cc = Cv2.ConnectedComponentsEx(gray);
                    foreach (var blob in cc.Blobs.Skip(1))
                    {
                        img.Rectangle(blob.Rect, Scalar.Lime, 2);
                    }
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            isLabeling = !isLabeling;
        }
    }
}


VB.NET

Imports OpenCvSharp
Imports OpenCvSharp.Extensions

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Task.Run(Sub()
                     Using v As New VideoCapture(0)
                         Using img As New Mat
                             Do
                                 v.Read(img)
                                 Process(img)
                                 PictureBox1.Image = img.ToBitmap
                             Loop
                         End Using
                     End Using
                 End Sub)
    End Sub

    Private isLabeling As Boolean = False

    Private Sub Process(ByVal img As Mat)
        If isLabeling Then
            Using gray As New Mat(img.Size, MatType.CV_8UC1)
                Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY)
                Cv2.Threshold(gray, gray, 0, 255, ThresholdTypes.Otsu)
                Dim cc As ConnectedComponents = Cv2.ConnectedComponentsEx(gray)
                For Each blob As ConnectedComponents.Blob In cc.Blobs.Skip(1)
                    img.Rectangle(blob.Rect, Scalar.Lime, 2)
                Next
            End Using
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        isLabeling = Not isLabeling
    End Sub

End Class