2017-08-22 2 views
0

OpenCV Version 3.2.0Was sind die verschiedenen Möglichkeiten, cv :: Mat zu konstruieren?

Ich lese Bradski und versuche, verschiedene cv :: Mat Konstruktoren - Einzelkanal. Kann mir bitte jemand sagen, warum die Konstruktoren nicht funktionieren?

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); 

Die entsprechenden Antworten sind:

[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 

Und dann die entsprechenden Antworten für lena.jpg die beschnittene Version von Reichweite und Rect ist. Ich weiß nicht, wie man die Bereiche benutzt.

+0

'mat3' und' mat6' scheinen nicht in Ordnung zu sein. Zumindest OpenCV 3.x [benötigt] (https://github.com/opencv/opencv/blob/master/modules/core/include/opencv2/core/mat.inl.hpp#L512) die Schrittgröße um sein mindestens die Länge einer Zeile (dh keine Überlappung ist erlaubt). –

+0

@ DanMašek Es funktioniert. Das Ergebnis ist in der Antwort. sizeof (float) schreitet um ein Element im Quell-Array fort. Es muss nicht die Größe von (Zeile) sein – infoclogged

+0

[That bestätigen] (https://github.com/opencv/opencv/blob/2.2/modules/core/include/opencv2/core/mat.hpp#L141) hat war dort mindestens seit OpenCV 2.2. Da es ein 'CV_DbgAssert' ist, wird es natürlich nur im Debug-Modus ausgelöst, und im Release-Modus wird es" funktionieren ". Aber etwas, das im Debug-Modus abstürzt und brennt, würde ich nicht als funktionierend bezeichnen. –

Antwort

0

Mehrere Probleme.

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

Dies wird im Debug-Modus abstürzen, an assertion scheitern. Auch wenn dies nicht in der Dokumentation enthalten ist, muss die Schrittgröße mindestens die Länge einer Zeile haben (d. H. Keine Überlappung ist zulässig).

Der richtige Code für dieses Szenario wäre etwas wie.

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)); 

ähnliche Situation wie in der vorhergehenden Fall. Beachten Sie auch, dass dies zu einem anders geformten Array führt - vorher waren 3 Zeilen, 4 Spalten, dieses hat 4 Zeilen und 3 Spalten (siehe 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; 

Formatierung von Arrays mit mehr als 2 Dimensionen not supported.

können Sie testen, ob das Array richtig durch manuelles Drucken aller Werte erstellt wurde:

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

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

Das hier Problem der letzte Parameter ist. Von the docs

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

Schritte - Array von ndims-1 Schritte bei einem mehrdimensionalen Array (der letzte Schritt ist mit dem Elementgröße immer gesetzt). Wenn nicht spezifiziert, wird angenommen, dass die Matrix kontinuierlich ist.

  • Sie sind nicht eine Reihe von Schritten als letzter Parameter übergeben (nur eine einzige ganze Zahl)
  • Sie nicht genügend Daten
  • und die Reihen überlappen würden wieder passieren.

Eine Möglichkeit, dies zu tun wäre, so etwas wie

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 

Der Datentyp CV_8UC1 ist, so dass jedes Element eine unsigned char. Das bedeutet, dass Sie keine float Werte daraus extrahieren sollten. Deine Erwartung ist falsch. (Jetzt sehe ich, dass Sie den Code in Ihrer Frage geändert haben).

Beachten Sie auch, dass mit cv::Range "Start ist eine inklusive linke Grenze des Bereichs und Ende ist eine ausschließliche rechte Grenze des Bereichs". Da Sie cv::Range(2,3) in jeder Achse extrahieren, ist die resultierende Mat 1 x 1 x 1. Daher greifen Sie auf Elemente außerhalb des Bereichs zu (wiederum würde dies eine Debug-Modus-Assertion auslösen).

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

Nach der Änderung haben Sie den richtigen Typ. Beachten Sie jedoch, dass Sie niemals bigCube1 initialisieren. Sie erhalten höchstwahrscheinlich eine 0.0f, die als 0 gedruckt wird. Sie können dies selbst ausprobieren, führen Sie einfach std::cout << 0.0f; aus und sehen Sie.

+0

Ich werde durchgehen. Sieht so aus, als müsste ich OpenCV komplett mit _DEBUG neu kompilieren, oder? – infoclogged

+0

Ya, Sie benötigen einen Debug-Build von OpenCV. –

+0

Ich denke, ich brauche in diesem Fall keine CMAKE_BUILD_TYPE Debug. Es sollte einfach funktionieren, das _DEBUG während des Kompilierens an die Quelldateien zu übergeben. Ich meine, ich möchte Opencv nicht debuggen, sondern nur die Assert aktivieren. Allerdings finde ich keine entsprechende _DEBUG Option in der cmake Datei. Kannst du mir bitte sagen wie hast du es gemacht? – infoclogged

Verwandte Themen