実例で学ぶMenou-TE ~その5 ネジ編~

第5回目の実例紹介になります。

今回は「ワークの傾きを算出したい」というリクエストを頂きましたので、
機能を追加してみました。

以下のように無造作に並んだネジの向きを検出していきたいと思います。
(第2回で釘って書いちゃいましたがネジでしたね…)

まずはネジの頭部と先端を区別せず、傾き(0~180°)で検出していきます。

領域検出と形状抽出で縦に並んだネジを検出

  1. ネジ検出用の領域検出を追加
    image

  2. ネジ検出のアノテーション及び学習
    ここでは結果だけ表示します。

  3. 縦向きネジ検出用の形状抽出を追加
    image

  4. 縦向きネジ検出の形状抽出の設定
    入力輪郭をスコアマップに切り替えます。


    ノイズがあるので面積をみてネジのみを検出します。
    最小面積を1000とします。

    直線の傾きを見て縦に並んでいるネジのみ検出します。
    傾きは左が0°下が90°右が180°
    直線の向きは考慮しないので上は90°です。
    傾きを75~105°とします。

    これで縦に並んでいるネジのみ検出することが出来ました。

次は縦に並んでるネジのうち頭部が上、先端が下にあるもののみ検出します。

領域検出と形状抽出とスクリプト検査で頭部が上向きで先端が下向きのネジを検出

  1. ネジ頭部検出用の領域検出を追加
    image

  2. ネジ頭部検出のアノテーション及び学習
    ここでは結果だけ表示します。

  3. スクリプト検査の設定
    ランタイム評価画面を開きます。
    image
    スクリプト検査設定タブを開いてスクリプト検査を記述し、
    スクリプト検査にチェックを入れます。

スクリプトでは直線の端の点のどちらがネジ頭部なのかを判定し角度を算出しています。

以下が今回使用したコードです。

// 最小角度
const int minAngle = 75;
// 最大角度
const int maxAngle = 105;
// 頭部判定用のマージン
const int margin = 50;

// 検査をしない場合はnull 条件に一致する場合はtrue 条件に一致しない場合はfalse
bool? result = null;

// ネジ頭部のブロブ
var screwHeadBlobs = GetBlobs("ネジ頭部検出");
var screwContours = GetContourOutputs("縦向きネジ検出");

// 結果が存在する時

if (screwHeadBlobs?.Any() == true && screwContours?.Any() == true)
{
    foreach (var screwContour in screwContours)
    {
        // 無効な輪郭は見ない
        if (!screwContour.IsEnabled)
        {
            continue;
        }
        var point0 = screwContour.LineSlope.Point0;
        var point1 = screwContour.LineSlope.Point1;
        var isPoint0Head = false;
        var isPoint1Head = false;
        foreach (var screwHeadBlob in screwHeadBlobs)
        {
            var left = screwHeadBlob.Rect.Left - margin;
            var right = screwHeadBlob.Rect.Right + margin;
            var top = screwHeadBlob.Rect.Top - margin;
            var bottom = screwHeadBlob.Rect.Bottom + margin;
            // ネジ頭部内に座標0があるか
            if (point0.X > left && point0.X < right && point0.Y > top && point0.Y < bottom)
            {
                isPoint0Head = true;
                break;
            }
            // ネジ頭部内に座標1があるか
            if (point1.X > left && point1.X < right && point1.Y > top && point1.Y < bottom)
            {
                isPoint1Head = true;
                break;
            }
        }

        // 座標0が頭部の場合
        if (isPoint0Head)
        {
            // 頭部から先端
            var pointPair = CreatePointPair(point0, point1);
            // 角度判定
            if (pointPair.Angle > minAngle && pointPair.Angle < maxAngle)
            {
                AddPointPair("頭が上で先端が下", pointPair);
                AddBlob("頭が上で先端が下", screwContour.Blob);
                result = true;
            }
        }
        // 座標1が頭部の場合
        else if (isPoint1Head)
        {
            // 頭部から先端
            var pointPair = CreatePointPair(point1, point0);
            // 角度判定
            if (pointPair.Angle > minAngle && pointPair.Angle < maxAngle)
            {
                AddPointPair("頭が上で先端が下", pointPair);
                AddBlob("頭が上で先端が下", screwContour.Blob);
                result = true;
            }
        }
    }
    // nullの時はfalseにして検出失敗とする
    result = result != null;
}

// resultは必ず最後の行に記述してください
result

スクリプト検査の結果です。

頭部が上向きで先端が下向きのネジのみ抽出することが出来ました。

動画版もあります。

ネジの例は以上となります。

実装したばかりでまだリリースされていないので、
使ってみたいという方は次回リリースを楽しみにしていてください。

「いいね!」 1