【C#】HALCON de 画像処理(エッジ検出) 検出方向指定

スポンサーリンク

今回は、前回の記事で基礎を行いました。
基礎の内容では、垂直方向の検出は出来ましたが、水平方向の検出は出来ませんでした。
そこで、今回は『どこの引数を変更すれば、検出するエッジの方向を変更できるか?』を紹介したいと思います。
エッジの検出方向を指定できれば、前回検出できなかった水平方向も検出できるようになります。
下記は、前回の記事です。前回の記事で作成したサンプルを修正していきます。
【C#】HALCON de 画像処理(エッジ検出) 基礎 | 育児パパの人生備忘録 (t19488sns.com)

使用する関数

エッジ検出に必要な3つの関数です。

HOperatorSet.GenMeasureRectangle2
  (HTuple,HTuple,HTuple,HTuple,HTuple,HTuple,HTuple,HTuple,out HTuple)
    ⇒ エッジ検出に必要な長方形のエリアを抽出する
■HOperatorSet.MeasurePos
  (HObject,HTuple,HTuple,HTuple,HTuple,HTuple,out HTuple,
     out HTuple,out HTuple,out HTuple)
    ⇒ エッジ検出を実行する。
■HOperatorSet.CloseMeasure(HTuple)
    ⇒ エッジ検出を行ったオブジェクトを開放します。

今回、修正を加える関数は、HOperatorSet.GenMeasureRectangle2()になります。
復習がてら、この関数の引数の内容です。

HOperatorSet.GenMeasureRectangle2()
 引数1:長方形の中心座標Y (行/Row)
 引数2:長方形の中心座標X (列/Column)
 引数3:水平に対する長方形の縦軸の角度 (ラジアン)
 引数4:長方形の半分の幅
 引数5:長方形の半分の高さ
 引数6:処理する画像の幅
 引数7:処理する画像の高さ
 引数8:使用する補間手法(nearest_neighbor/bicubic/bilinear)
 引数9:[出力]測定するオブジェクトのハンドル

今回注目したいのは、引数3の内容です。
前回は[0.0]で実施したのですが、ここの内容を紹介します。

gen_measure_rectangle2 [HALCON Operator Reference / Version 13.0.4] (mvtec.com) より

要は、Phiの数値でエッジ検出する方向を決めています!
前回のサンプルだとこんなイメージです。

では、早速前回のサンプルを修正していきます。

サンプルを作っていく

画像は前回と同じものを使います。

操作画面

コンボボックスを追加し、検出方向を指定できるようにしました。

コンボボックスのアイテム(選択肢)として、下記4つを登録しました。

定義

定義は、下記を追加します。
コンボボックスのアイテム(SelectedIndex)に合わせて、列挙体を定義します。

enum eDirection
{
    LR, //左⇒右
    TB, //上⇒下
    RL, //右⇒左
    BT, //下⇒上
}

続いて、この列挙体に応じて数値を変更できるように、Dictionary型を定義します。
定義の段階で、初期値も登録します。

readonly Dictionary<eDirection, double> Phi = new Dictionary<eDirection, double> {
    { eDirection.LR, 0.0 },
    { eDirection.TB,-Math.PI/2 },
    { eDirection.RL, Math.PI },
    { eDirection.BT,Math.PI/2 }
};

処理

気になる処理ですが、[赤太字で修正場所/青の太字で追加場所]を紹介します。

private void BtnEdge_Click(object sender, EventArgs e)
{
    if (DispOrgImg == null) return;        //画像読込されてないなら処理しない

    //Zoom方式で表示
    HTuple hwnd = hWindowControl1.HalconWindow;
    HOperatorSet.ClearWindow(hwnd);
    DispZoom(hwnd, DispOrgImg);

    //検出エリアの中心座標
    double halfW = (double)(nudW.Value / 2);
    double halfH = (double)(nudH.Value / 2);
    double centerX = (double)nudX.Value + halfW;
    double centerY = (double)nudY.Value + halfH;

    //検出方向に応じて変更する引数の変数
    eDirection select = (eDirection)cmbDirection.SelectedIndex;
    double phi = Phi[select];
    if (select == eDirection.TB || select == eDirection.BT)
    {
        (halfW, halfH) = (halfH, halfW);
    }

    //検出エリアの表示
    HOperatorSet.SetDraw(hwnd, "margin");
    HOperatorSet.SetColor(hwnd, "yellow");
    HOperatorSet.SetLineWidth(hwnd, 1);
    HOperatorSet.DispRectangle2(hwnd, centerY, centerX, phi, halfW, halfH);

    //画像サイズ取得
    HOperatorSet.GetImageSize(DispOrgImg, out HTuple w, out HTuple h);

    //測定オブジェクトのハンドルを取得
    HOperatorSet.GenMeasureRectangle2(
       centerY, centerX, phi, halfW, halfH, w, h, "nearest_neighbor",
       out HTuple handle);

    //エッジ検出実行
    HOperatorSet.MeasurePos(
       DispOrgImg, handle, 1.0, 30, "all", "all",
       out HTuple row, out HTuple col, out HTuple ampl, out HTuple dist);

    //エッジ検出終了
    HOperatorSet.CloseMeasure(handle);

    //結果表示
    dgvResult.Rows.Clear();
    int cnt = row.Length;
    if (cnt <= 0) return;

    dgvResult.Rows.Add(cnt);
    for(int indx = 0;indx < cnt;indx++)
    {
        dgvResult.Rows[indx].Cells[0].Value = col[indx].D.ToString("F2");
        dgvResult.Rows[indx].Cells[1].Value = row[indx].D.ToString("F2");
        dgvResult.Rows[indx].Cells[2].Value = ampl[indx].D.ToString("F2");

        //クロス線を描画
        HOperatorSet.SetColor(hwnd, "red");
        HOperatorSet.SetLineWidth(hwnd, 3);
        HOperatorSet.DispCross(hwnd, row[indx], col[indx], 10, 0.0);

        if (indx + 1 < cnt)
        {
            dgvResult.Rows[indx].Cells[3].Value = dist[indx].D.ToString("F2");
        }
    }

    //描画の設定を戻す
    HOperatorSet.SetColor(hwnd, "white");
    HOperatorSet.SetLineWidth(hwnd, 1);
}

ココで注意したいのが、HOperatorSet.DispRectangle2()とHOperatorSet.GenMeasureRectangle2()では、回転後の幅と高さを指定しないといけない事です。
その為、追加したコードを見ていただければわかりますが、水平方向の検出の時(90°と270°の時)は、幅と高さを反転させています。
今は便利ですね。変数の入れ替えは、タプルを利用する事が出来るようになっています。
※VisualStudioのバージョンやC#のバージョンによっては出来ません。
(halfW, halfH) = (halfH, halfW)

実行結果

コンボボックスを変更する事で、水平方向や垂直方向を検出する事が出来ました。
また、[左⇒右]と[右⇒左]を比較すると、検出結果の順番が逆になっている事が分かります。

補足

フォームロード処理

ここでは、追加したコンボボックスの初期値を指定します。
そうする事で、選択された状態でソフトを起動させることが出来ます。

private void FrmEdge_Load(object sender, EventArgs e)
{
    cmbDirection.SelectedIndex = 0;
}

コントロールの活性制御

コントロール(コンボボックス)を追加したので、それの分を追加します。

private void ControlEnable(bool sw)
{
    btnReadImg.Enabled = sw;
    btnEdgeInspectArea.Enabled = sw;
    grpParam.Enabled = sw;
    btnEdge.Enabled = sw;
    dgvResult.Enabled = sw;
    cmbDirection.Enabled = sw;
}

コメント

タイトルとURLをコピーしました