質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

C++でのopencvでcv::momentsでのエラーについて

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 579

_orikage

score 7

目的、前提、実現したいこと、お願いしたいこと

  • 常にその色を追いかけるプログラムを書こうとしている途中です
  • プログラムの流れとして、カメラから取り込み→色を抽出、maskimageにする→収縮、拡大して判別しやすくする→輪郭抽出→重心検出という感じです
  • エラーを解決するためのアドバイスや解決案をお願いします

実行環境

  • visualstudio 2019
  • windows 10
  • opencvはvcpkgでダウンロードした

エラーコード

イメージ説明

エラーが発生した状況

赤が検出されないとき
それ以外のときは問題なく思い通りに動きました

ソースコード

コメントでエラーが発生したところの後ろにエラーコードを書いています

#include<iostream>
#include<vector>
#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/imgproc/types_c.h>



#define H_MAX 180
#define S_MAX 255
#define V_MAX 255
#define H_MIN 160
#define S_MIN 50
#define V_MIN 50



int main() {
    cv::VideoCapture cap(0);
    if (!cap.isOpened())
        return -1;
    cv::Mat image;



    while (true) {
        cap >> image;

        cv::Mat hsv_image, mask_image, output_image;
        cv::cvtColor(image, hsv_image, CV_BGR2HSV, 3);


        //赤抽出
        cv::Scalar ss_min = cv::Scalar(H_MIN, S_MIN, V_MIN);
        cv::Scalar ss_max = cv::Scalar(H_MAX, S_MAX, V_MAX);
        cv::inRange(hsv_image, ss_min, ss_max, mask_image);


        //収縮、拡大処理
        cv::Mat shushuku_mask_image,kakudai_mask_image;
        cv::Mat element = cv::Mat::ones(5, 5, CV_8UC1);
        cv::erode(mask_image, shushuku_mask_image, element, cv::Point(-1, -1), 1);
        cv::erode(shushuku_mask_image, shushuku_mask_image, element, cv::Point(-1, -1), 1);
        cv::erode(shushuku_mask_image, shushuku_mask_image, element, cv::Point(-1, -1), 1);
        cv::erode(shushuku_mask_image, shushuku_mask_image, element, cv::Point(-1, -1), 1);
        cv::dilate(mask_image, kakudai_mask_image, element, cv::Point(-1, -1), 1);
        cv::dilate(kakudai_mask_image, kakudai_mask_image, element, cv::Point(-1, -1), 1);
        cv::dilate(kakudai_mask_image, kakudai_mask_image, element, cv::Point(-1, -1), 1);
        cv::dilate(kakudai_mask_image, kakudai_mask_image, element, cv::Point(-1, -1), 1);


        //輪郭検出(vector<point>)
        std::vector < std::vector < cv::Point >> contours;
        cv::findContours(kakudai_mask_image, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
        double max_size = 0;
        int max_id = -1;
        for (int i = 0; i < contours.size(); i++) {
            if (contours[i].size() > max_size) {
                max_size = contours[i].size();
                max_id = i;
            }
        }
        cv::Moments mu;
        mu= cv::moments(contours[max_id]);//ここの列で例外発生( により ハンドルされない例外が 0x7956F2F6 (ucrtbased.dll) で発生しました(opencv_aka_chushutu_kireini.exe 内): 無効なパラメーターを致命的と見なす関数に無効なパラメーターが渡されました。 が発生しました)
        cv::Point2f mc = cv::Point2f(mu.m10 / mu.m00, mu.m01 / mu.m00);

        //中心に円を描画
        cv::Mat tyushin;
        tyushin = kakudai_mask_image.clone();
        cv::circle(tyushin, mc, 4, cv::Scalar(100), 2, 4);

        //gray_mask_image = hsv_image;


        //中心を出力
        std::cout <<"x="<< mc.x <<"y="<< mc.y << std::endl;


        cv::imshow("maskimage", mask_image);
        //cv::imshow("monokuro", gray_mask_image);
        cv::imshow("shushuku", shushuku_mask_image);
        cv::imshow("kakudai", kakudai_mask_image);
        cv::imshow("tyushin", tyushin);
        int key = cv::waitKey(1);
        if (key == 'q')
            break;
    }
    return 0;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

あまり真面目に追っていませんが、対象とする領域がないとき
cv::findContours(kakudai_mask_image, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); でcoutoursは空になり、
for (int i = 0; i < contours.size(); i++) {
でcontours.size()が0でこのループには入らず、そうするとmax_idは初期値で与えられた-1のまま問題の
mu= cv::moments(contours[max_id]);
に突入してDEBUGモードでは配列の範囲外を検出して例外、という流れのように思います。

対象とする領域がない時にプログラムがどのように応答するべきかを決めて、cv::findContours()の結果を受けて適切に分岐する(contorus[]にアクセスしないようにする)、というところでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/01/14 00:39

    cv::Moments mu;
    if (max_id != -1) {
    mu = cv::moments(contours[max_id]);
    }
    cv::Point2f mc = cv::Point2f(mu.m10 / mu.m00, mu.m01 / mu.m00);


    こう直したら動くようになりました!ありがとうございます!!

    キャンセル

  • 2020/01/14 07:45

    それはそれで、初期化されてないmuを参照しているのがかなりよろしくないと思います。ある日、突如として例外が出てしかし繰り返すと再現しない、なんてことになりかねないのでは。
    それとも、コンストラクタで初期化されていてm00が0にならない保証がある、とか?(OpenCVの仕様でどうなってます?)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る