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

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

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

3377閲覧

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

_orikage

総合スコア7

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/01/13 12:35

編集2020/01/13 12:38

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

  • 常にその色を追いかけるプログラムを書こうとしている途中です
  • プログラムの流れとして、カメラから取り込み→色を抽出、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; }

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

あまり真面目に追っていませんが、対象とする領域がないとき
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/13 13:28

thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_orikage

2020/01/13 15: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); こう直したら動くようになりました!ありがとうございます!!
thkana

2020/01/13 22:45

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問