2017-08-22 14 views
0

OpenCV Version 3.2.0cv :: Matを構築するさまざまな方法は何ですか?

私はBradskiを読んでいて、別のcv :: Matコンストラクタを作成しようとしています。 コンストラクタが動作しない理由を教えてもらえますか?

float data1[6] = {1,2,3,4,5,6}; 
float data2[6] = {10,20,30,40,50,60}; 
float data3[6] = {100,200,300,400,500,600}; 

cv::Mat mat1(3,4,CV_32FC1); //OK 
cv::Mat mat2(3,4,CV_32FC1,cv::Scalar(33.3)); //OK 
cv::Mat mat3(3,4,CV_32FC1,data1,sizeof(float)); //OK 
cv::Mat mat4(cv::Size(3,4),CV_32FC1); //OK 
cv::Mat mat5(cv::Size(3,4),CV_32FC1,cv::Scalar(66.6)); //OK 
cv::Mat mat6(cv::Size(3,4),CV_32FC1,data2,sizeof(float)); //OK 
int sz[] = {8, 8, 8}; 
cv::Mat bigCube1(3, sz, CV_32FC1); // OK 
cv::Mat bigCube2(3, sz, CV_32FC1, cv::Scalar::all(99)); // OK 
cv::Mat bigCube3(3, sz, CV_32FC1, data3, 4); // Not OK, How to initialise a 3D from data? 
std::cout << mat1 << std::endl << mat2 << std::endl << mat3 << std::endl << mat4 << std::endl << mat5 << std::endl << mat6 << std::endl; // OK                 
std::cout << bigCube1.at<float>(10,10,10) << std::endl << bigCube2.at<float>(10,10,10) << std::endl; // OK 

cv::Mat img_rgb = cv::imread("lena.jpg", CV_LOAD_IMAGE_COLOR); 
std::vector<cv::Range> ranges(3, cv::Range(2,3)); 

cv::Mat roiRange(img_rgb, cv::Range(100, 300), cv::Range(0, 512)); //OK 
cv::Mat roiRect(img_rgb, cv::Rect(0,100,512,200)); // OK 
cv::Mat roiRangeMultiple(bigCube1, ranges); // OK 

cv::namedWindow("range", CV_WINDOW_AUTOSIZE); 
imshow("range", roiRange); // OK 
cv::namedWindow("rect", CV_WINDOW_AUTOSIZE); 
imshow("rect", roiRect); // OK 
std::cout << roiRangeMultiple.at<float>(0,1,1); // Not OK. Expecting a float value as answer 
cv::waitKey(0); 

対応の答えは以下のとおりです。lena.jpgため

[4.6634629e-10, 0, 0, 0; 
0, 0, 0, 0; 
127.62516, 2.8025969e-45, 0, 0] 

[33.299999, 33.299999, 33.299999, 33.299999; 
33.299999, 33.299999, 33.299999, 33.299999; 
33.299999, 33.299999, 33.299999, 33.299999] 

[1, 2, 3, 4; 
2, 3, 4, 5; 
3, 4, 5, 6] 

[0, 0, 0; 
0, 0, 0; 
0, 0, 0; 
0, 0, 0] 

[66.599998, 66.599998, 66.599998; 
66.599998, 66.599998, 66.599998; 
66.599998, 66.599998, 66.599998; 
66.599998, 66.599998, 66.599998] 

[10, 20, 30; 
20, 30, 40; 
30, 40, 50; 
40, 50, 60] 
0 // bigCube1 
99 // bigCube2 

してから、対応する答えが範囲とのRectからトリミングされたバージョンです。私は範囲を使用する方法を知っていない。

+0

'mat3'と' mat6'はOKではないようです。 OpenCV 3.x以上で必要なステップサイズ(https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/mat.inl.hpp#L512)少なくとも行の長さ(つまり、重複は許されません)。 –

+0

@DanMašekそれは動作します。結果は答えです。 sizeof(float)ステップをソース配列内の1つの要素で置き換えます。それはsizeof(行)である必要はありません – infoclogged

+0

[そのアサート](https://github.com/opencv/opencv/blob/2.2/modules/core/include/opencv2/core/mat.hpp#L141)が持っています少なくともOpenCV 2.2以降であった。もちろん、CV_DbgAssertであるため、デバッグモードでのみ起動し、リリースモードでは動作します。しかし、デバッグモードでクラッシュして焼けるものは、私が働いているとは言いません。 –

答えて

0

複数の問題。

cv::Mat mat3(3,4,CV_32FC1,data1,sizeof(float)); 

これは、デバッグモードでクラッシュし、an assertionに失敗します。これはドキュメントに記載されていませんが、ステップサイズは少なくとも行の長さでなければなりません(つまり、重なりは許されません)。

このシナリオの正しいコードは、次のようなものです。前の場合のように

float data1[12] = { 1, 2, 3, 4, 2, 3, 4, 5, 3, 4, 5, 6 }; 
cv::Mat mat3(3, 4, CV_32FC1, data1, 4 * sizeof(float)); 

cv::Mat mat6(cv::Size(3,4),CV_32FC1,data2,sizeof(float)); 

同様の状況。これは別の形状の配列を生成することにも注意してください。以前は3行4列でしたが、これは4行3列です(docs of cv::Size参照)。

float data2[12] = { 10, 20, 30, 40, 20, 30, 40, 50, 30, 40, 50, 60 }; 
cv::Mat mat6(cv::Size(3, 4), CV_32FC1, data2, 3 * sizeof(float)); 

cv::Mat bigCube1(3, sz, CV_8UC1); 
std::cout << bigCube1 << std::endl; 

2つの以上の寸法を有するアレイのフォーマットはnot supportedあります。

あなたは、配列が正しく手動ですべての値を印刷することにより作成されたことをテストすることができます。

for (auto const& v : cv::Mat1b(bigCube2)) { 
    std::cout << uint(v) << " "; 
} 
std::cout << "\n"; 

cv::Mat bigCube3(3, sz, CV_32FC1, data3, 4); 

ここでの問題は、最後のパラメータです。 ndims-1多次元アレイの場合にはステップ(最後のステップは常に素子サイズに設定されている)の配列を - the docs

cv::Mat::Mat(int ndims, 
    const int * sizes, 
    int type, 
    void * data, 
    const size_t * steps = 0 
    ) 

からステップ。指定されない場合、行列は連続しているとみなされます。

  • あなたは十分なデータ
  • を渡さないと行が再び重なってしまう
  • 最後のパラメータ(唯一の単一の整数)として、ステップの配列を渡していません。これを行うには

一つの方法は、

float data3[8 * 8 * 8]; 
// Populate the data with sequence 0..511 
std::iota(std::begin(data3), std::end(data3), 0.0f); 

int sz[] = { 8, 8, 8 }; 
size_t steps[] = { 8 * 8 * sizeof(float), 8 * sizeof(float) }; 
cv::Mat bigCube3(3, sz, CV_32FC1, data3, steps); 

cv::Mat bigCube1(3, sz, CV_8UC1); 
// ... 
std::cout << roiRangeMultiple.at<float>(0,1,1); // Not OK. Expecting a float value as answer 

ようなデータ型がCV_8UC1なので、各要素はunsigned char型であるだろう。つまり、floatの値を抽出しないでください。あなたの期待は間違っています。 (今私はあなたの質問のコードを変更した参照してください)。

また、cv::Rangeでは、「開始は範囲の包括的な左境界であり、終わりは範囲の排他的右境界です」ということに注意してください。それぞれの軸でcv::Range(2,3)を抽出するので、結果のMatは1 x 1 x 1です。したがって、範囲外の要素にアクセスしています(再び、デバッグモードのアサーションをトリガーします)。あなたは正しい型を持って変更した後

std::cout << roiRangeMultiple.at<unsigned char>(0,0,0); 

。ただし、bigCube1を初期化しないことに注意してください。結果として0.0fが得られる可能性が最も高く、0と表示されます。これを自分で試すことができます。ただstd::cout << 0.0f;を実行してください。

+0

私はそれを通過します。私は_DEBUGでOpenCVを完全に再コンパイルする必要がありますか? – infoclogged

+0

あなたはOpenCVのデバッグビルドが必要です。 –

+0

私はこの場合CMAKE_BUILD_TYPEデバッグが必要ないと思います。コンパイル中に_DEBUGをソースファイルに渡すだけでうまくいくはずです。つまり、opencvをデバッグするのではなく、アサートをアクティブにするだけです。しかし、cmakeファイルで対応する_DEBUGオプションを見つけることはできません。どうしたのですか教えてください。 – infoclogged

関連する問題