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

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

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

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

C++

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

Q&A

解決済

1回答

991閲覧

うまく位置推定ができない

amay

総合スコア2

OpenCV

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

C++

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

0グッド

0クリップ

投稿2021/11/11 05:31

編集2021/11/11 07:45

位置測定が実測と全く合わないです。
事前に別のコードからカメラキャリブレーションを行った前提のこーどです。

#define _CRT_SECURE_NO_WARNINGS #include <opencv2/opencv.hpp> #include <iostream> #include <string> #include <sstream> #include <iomanip> #include <opencv2/imgcodecs.hpp> #include <vector> #include <opencv2/imgproc/imgproc.hpp> #.include <random> #include <strstream> //抽出する画像の輝度値の範囲を指定 #define B_MAX 100 #define B_MIN 0 #define G_MAX 100 #define G_MIN 0 #define R_MAX 255 #define R_MIN 100 using namespace cv; using namespace std; /* class StereoMatcher : public Algorithm { public: //返された奥行マップは CV_16UC1 型であり, 要素は実際には //DISP_SHIFT=4 少数ビットの固定小数点である enum { DISP_SHIFT = 4, DISP_SCALE = (1 << DISP_SHIFT) }; //主要なメソッド, 2つのグレースケールの8ビットの平行化された画像を取り, //16ビットの固定小数点数の視差画像を出力する virtual void compute( InputArray left, InputArray right, OutputArray disparity ) = 0; //最小の視差, 通常は0(点は無限遠にある) virtual int getMinDisparity() const = 0; virtual void setMinDisparity(int minDisparity) = 0; //最小値(含む)と最大値(含まない)との間の視差の幅 virtual int getNumDisparities() const = 0; virtual void setNumDisparities(int numDisparities) = 0; //アルゴリズムで使用されるブロックのサイズ virtual int getBlockSize() const = 0; virtual void setBlockSize(int blockSize) = 0; //スペックルとみなされ, そのようにマークされる最大サイズ virtual int getSpeckleWindowSize() const = 0; virtual void setSpeckleWindowSize(int speckleWindowSize) = 0; //近傍ピクセル間の許容される差 //フラッドフィルベースのスペックルフィルタリングアルゴリズムで使用 virtual int getSpeckleRange() const = 0; virtual void setSpeckleRange(int speckleRange) = 0; }; class StereoBM : public cv::StereoMatcher { enum { PREFILTER_NORMALIZED_RESPONSE = 0, PREFILTER_XSOBEL = 1 }; //PREFILTER_NORMALIZED_RESPONSE か PREFILTER_XSOBEL のいずれかを選択 virtual int getPreFilterType() const = 0; virtual void setPreFilterType(int preFilterType) = 0; //PREFILTER_NORMALIZED_RESPONSE モードで使用されるブロックのサイズ virtual int getPreFilterSize() const = 0; virtual void setPreFilterSize(int preFilterSize) = 0; //事前フィルタリング後に適用される飽和しきい値 virtual int getPreFilterCap() const = 0; virtual void setPreFilterCap(int preFilterCap) = 0; //テクスチャのしきい値, テクスチャ特性を有するブロック(微分係数の絶対値の合計)が //このしきい値よりも小さいブロックは, 明確な視差のない領域としてマークされる virtual int getTextureThreshold() const = 0; virtual void setTextureThreshold(int textureThreshold) = 0; //視差範囲にわたってコスト関数に明らかな勝者がない場合, //ピクセルには明確な視差がない. //一意性のしきい値は, どれが「明白な勝者」かを定義し, //最高点と次点の間のマージンを % で定義する virtual int getUniquenessRatio() const = 0; virtual void setUniquenessRatio(int uniquenessRatio) = 0; //コンストラクタ関数, デフォルトの値をもつが, 最初のパラメータは技術的な理由から //実際にはここか, 後で setNumDisparities() を使用して指定するべき static Ptr<StereoBM> create( int numDisparities = 0, int blockSize = 21 ); }; */ int main(void) { Mat left, right; VideoCapture cap1(0); VideoCapture cap2(1); if (!cap1.isOpened()) { cerr << "ERROR! Unable to open camera\n"; return -1; } if (!cap2.isOpened()) { cerr << "ERROR! Unable to open camera\n"; return -1; } //キャリブレーションで求めたパラメーター Mat cam_matrix1, cam_matrix2; Mat dist_matrix1, dist_matrix2; Mat R_calib, T_calib; Mat R1(3, 3, CV_64F); Mat R2(3, 3, CV_64F); Mat P1(3, 4, CV_64F); Mat P2(3, 4, CV_64F); Mat Q; Mat F; Size size = left.size(); Mat left_good, right_good; //並行化後の画像 Mat joint; //左右を結合した画像 //パラメータの読み込み FileStorage fs("C:\Users\yamamura\source\repos\ip\ip\img\camera.xml", FileStorage::READ); if (!fs.isOpened()) { cout << "File can not be opened." << endl; return -1; } cout << "しきい値を入力してください" << endl; int tsd_v; cin >> tsd_v; while (true) { cap1.read(left); cap2.read(right); const int key = waitKey(1); //表示して確認 namedWindow("左"); imshow("左", left); namedWindow("右"); imshow("右", right); //結果保存用Matを定義 Mat maskl, maskr, outl, outr; //inRangeを用いてフィルタリング Scalar s_min = Scalar(B_MIN, G_MIN, R_MIN); Scalar s_max = Scalar(B_MAX, G_MAX, R_MAX); inRange(left, s_min, s_max, maskl); inRange(right, s_min, s_max, maskr); //マスク画像を表示 namedWindow("maskl"); namedWindow("maskr"); imshow("maskl", maskl); imshow("maskr", maskr); //マスクを基に入力画像をフィルタリング left.copyTo(outl, maskl); right.copyTo(outr, maskr); //結果の表示と保存 namedWindow("outl"); namedWindow("outr"); imshow("outl", outl); imshow("outr", outr); Mat binaryl, binaryr; //二値化 threshold(maskl, binaryl, tsd_v, 255, THRESH_BINARY); threshold(maskr, binaryr, tsd_v, 255, THRESH_BINARY); waitKey(1); //画像を平滑化(メディアンフィルタ) int size = 5; UMat dstl, dstr; medianBlur(binaryl, dstl, size); medianBlur(binaryr, dstr, size); imshow("dstl", dstl); imshow("dstr", dstr); /*ビット反転 bitwise_not(dstl, dstl); bitwise_not(dstr, dstr); */ /* //ラベリング Mat labl, labr, statsl, statsr, centerl, centerr; int nlabell = connectedComponentsWithStats(dstl, labl, statsl, centerl); int nlabelr = connectedComponentsWithStats(dstr, labr, statsr, centerr); //ラベリング結果の描画色を決定 vector <Vec3b> colorsl(nlabell); vector <Vec3b> colorsr(nlabelr); colorsl[0] = Vec3b(0, 0, 0); colorsr[0] = Vec3b(0, 0, 0); for (int i = 1; i < nlabell; ++i) { colorsl[i] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255)); } for (int i = 1; i < nlabelr; ++i) { colorsr[i] = Vec3b((rand() & 255), (rand() & 255), (rand() & 255)); } //ラベリング結果の描画 Mat Dstl(dstl.size(), CV_8UC3); Mat Dstr(dstr.size(), CV_8UC3); for (int i = 0; i < Dstl.rows; ++i) { int* lb = labl.ptr<int>(i); Vec3b* pix = Dstl.ptr<Vec3b>(i); for (int j = 0; j < Dstl.cols; ++j) { pix[j] = colorsl[lb[j]]; } } for (int i = 0; i < Dstr.rows; ++i) { int* lb = labr.ptr<int>(i); Vec3b* pix = Dstr.ptr<Vec3b>(i); for (int j = 0; j < Dstr.cols; ++j) { pix[j] = colorsr[lb[j]]; } } //ROIの設定 for (int i = 1; i < nlabell; ++i) { int* param = statsl.ptr<int>(i); int x = param[ConnectedComponentsTypes::CC_STAT_LEFT]; int y = param[ConnectedComponentsTypes::CC_STAT_TOP]; int height = param[ConnectedComponentsTypes::CC_STAT_HEIGHT]; int width = param[ConnectedComponentsTypes::CC_STAT_WIDTH]; rectangle(Dstl, Rect(x, y, width, height), Scalar(0, 255, 0), 2); } for (int i = 1; i < nlabelr; ++i) { int* param = statsr.ptr<int>(i); int x = param[ConnectedComponentsTypes::CC_STAT_LEFT]; int y = param[ConnectedComponentsTypes::CC_STAT_TOP]; int height = param[ConnectedComponentsTypes::CC_STAT_HEIGHT]; int width = param[ConnectedComponentsTypes::CC_STAT_WIDTH]; rectangle(Dstr, Rect(x, y, width, height), Scalar(0, 255, 0), 2); } //重心の出力 for (int i = 1; i < nlabell; ++i) { double* param = centerl.ptr<double>(i); int x1 = static_cast<int>(param[0]); int y1 = static_cast<int>(param[1]); circle(Dstl, Point(x1, y1), 3, Scalar(0, 0, 255), -1); cout << "centerl" << i << "=" << param[4] << endl; } for (int i = 1; i < nlabelr; ++i) { double* param = centerr.ptr<double>(i); int x2 = static_cast<int>(param[0]); int y2 = static_cast<int>(param[1]); circle(Dstr, Point(x2, y2), 3, Scalar(0, 0, 255), -1); cout << "centerr" << i << "=" << param[4] << endl; } //面積値の出力 for (int i = 1; i < nlabell; ++i) { int* param = statsl.ptr<int>(i); int x = param[0]; int y = param[1]; stringstream num; num << i; putText(dstl, num.str(), Point(x + 5, y + 20), FONT_HERSHEY_COMPLEX, 0.7, Scalar(0, 255, 255), 2); } for (int i = 1; i < nlabelr; ++i) { int* param = statsr.ptr<int>(i); int x = param[0]; int y = param[1]; stringstream num; num << i; putText(dstr, num.str(), Point(x + 5, y + 20), FONT_HERSHEY_COMPLEX, 0.7, Scalar(0, 255, 255), 2); } imshow("Dstl", Dstl); imshow("Dstr", Dstr); waitKey(1); */ //重心探索 Moments mom1 = moments(dstl, 1); Point2f pt1 = Point2f(mom1.m10 / mom1.m00, mom1.m01 / mom1.m00); circle(dstl, pt1, 10, Scalar(100), 3, 4); Moments mom2 = moments(dstr, 1); Point2f pt2 = Point2f(mom2.m10 / mom2.m00, mom2.m01 / mom2.m00); circle(dstr, pt2, 10, Scalar(100), 3, 4); imshow("DstL", dstl); imshow("DstR", dstr); waitKey(1); float T = 15; //カメラ間距離 float F = 163.6; //焦点距離 //float Z = 50; //物体距離 //ピクセル誤差 float D = pt1.x - pt2.x; //焦点距離 //float f = Z*D/T; //推定距離 float z = F * T / D; //標準出力 //cout << f << endl; cout << z << endl; waitKey(1); /* for (int i = 0; i < nlabell; i++) { compare(labl, i, dstl, CMP_EQ); imshow("LabelingL", dstl); waitKey(1); } for (int i = 0; i < nlabell; i++) { compare(labr, i, dstr, CMP_EQ); imshow("LabelingR", dstr); waitKey(1); } */ if (key == 'q') { /* imwrite("maskl.jpg", maskl); imwrite("maskr.jpg", maskr); imwrite("outl.jpg", outl); imwrite("outr.jpg", outr); //二値化画像の保存 imwrite("binaryl.jpg", binaryl); imwrite("binaryr.jpg", binaryr); //ラベリング画像の保存 imwrite("labl.jpg", dstl); imwrite("labr.jpg", dstr); */ break; } } return 0; }

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

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

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

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

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

y_waiwai

2021/11/11 05:55

このままではコードが読みづらいので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
SaitoAtsushi

2021/11/11 06:17

うまくできないというのは具体的にどういう意味ですか? どのような期待をしているところにどのような結果になってしまったのか書きましょう。
jbpb0

2021/11/11 06:20

c++のコードの一番最初の行のすぐ上に ```c++ だけの行を追加してください また、c++のコードの一番最後の行のすぐ下に ``` だけの行を追加してください または、 https://teratail.storage.googleapis.com/uploads/contributed_images/e378967f71829feb9e6187e5be60349f.gif を見て、そのようにしてみてください 現状、コードがとても読み辛いです 質問にコードを載せる際に上記をやってくれたら、他人がコードを読みやすくなり、コードの実行による現象確認もやりやすくなるので、回答されやすくなります
episteme

2021/11/11 07:37

質問になっていない。コードを貼り付けただけ。
fana

2021/11/12 01:28

何故か注釈で StereoMatcher や StereoBM といった型の話が書かれているようですが, この質問においてそれらが無関係であれば,そういった物を無意味に提示コードに含めるべきではありません.
guest

回答1

0

ベストアンサー

提示されたコードを見るに,

//キャリブレーションで求めたパラメーター

という箇所に書かれているMat群は後段で全く用いられていないようですし,

//パラメータの読み込み

という箇所では何も読み込んでいる様子がありません.

そして,距離推定には,謎の値:

float T = 15; //カメラ間距離
float F = 163.6; //焦点距離

が用いられているように見えます.

位置測定が実測と全く合わない

とのことですが,そもそも現状行っている処理というのは,「正当な理屈の上で,合うハズ」な形になっているのでしょうか?


仮に

  • 前記の TF が,実際にキャリブレーション作業を行って得られたパラメータ値に相当する値なのであって
  • カメラ画像は,理想的なピンホールカメラモデルだと近似して問題ないものであり
  • rectification を行わずとも最初からそれが行われた相当の映像が得られる

という(非現実的とも思える)環境下における話なのだとしても,最終的な結果の良し悪しは

float D = pt1.x - pt2.x;

に用いられている pt1, pt2 を得る過程がどの程度ロバストなのか? に依存することになるでしょう.
これらの座標は何らかの画像処理の結果みたいなので,当然,相応に揺らぐでしょう → それがそのまま奥行推定結果に響くわけです.
そこらへんの評価をすべきです.
(実施環境次第では,視差1[pixel]の違いが奥行推定値としては 数十[cm]とか数[m]とかの違いとなり得るわけですし)


ということで,とりあえず,以下のようなことを(上から順に)確認すべきに思います.

  1. そもそもまともな理屈の上に成り立った処理になっているのか? ということを確認する.

話の筋道がまともでないならば,まともな結果は得られないであろう.
2. pt1 と pt2 をあなたが手動できっちりと与えたならば,奥行推定結果は相応にまともな値となるのか? を確認する.
「考え得る限り完璧なマッチング対応」を与えても奥行推定がダメなのであれば,とにかく何かが間違っている.
各種パラメータが間違っているのかもしれないし,ステレオ計算の処理の実装にバグがあるのかもしれない.
3. pt1 や pt2 の座標の揺らぎがどの程度奥行推定値を変動させるのか? を評価する.
画像処理の精度を極限まで高めた想定での pt1, pt2 座標の誤差を何pixelと見積もるのか?
その誤差量による奥行の変動量が許容できないレベルなのであれば,そもそも全体の処理フローが無理筋だということになる.

投稿2021/11/12 02:05

fana

総合スコア11656

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

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

fana

2021/11/12 02:17

とりあえず,前の質問: https://teratail.com/questions/367347 では,必要そうな言葉を様々列挙したけども,今回のコードにはそれらの要素がほぼほぼ含まれていない様子にも見える. もちろん,ステレオ計算に関して, 「そんなにきっちりとやらずとも{なんとなく/ほどほどな}推定処理で良いのだ」という話もあり得るとは思うけども,そういう話なのだとすれば, 前提部分を{なんとなく/ほどほど}にしたことによって,その推定結果がどの程度{なんとなく/ほどほど}な値になるのだろうか? ということを見積もる必要があるよ. 現状の結果がその範疇なのかもしれないのだし.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問