2014-05-09 17 views
6

Gibt es eine einfache Möglichkeit, alle Werte in einem cv :: Mat auf einen bestimmten Wert zu setzen, wenn sie eine Bedingung erfüllen. Zum Beispiel, ich habe CV_32FC1, und ich möchte alle Werte eingestellt, die 0 bis 20 MATLAB sind würde ich einfach das getan haben:OpenCV cv :: Mat gesetzt, wenn

M(M == 0) = 20; 

Antwort

11

können Sie

cv::Mat mask = M == 0; 
M.setTo(0.5, mask); 

jedoch verwenden, enthält es mit zusätzlicher Speicher zum Erstellen von Masken, ist aber eine Lösung mit opencv-API und kann daher auf alle Matrixtypen angewendet werden. Wenn Sie Leistungsprobleme berücksichtigen, können Sie immer direkt auf Mat :: data verweisen, um diese Lösung für den konkreten Matrixtyp zu optimieren.

+0

Das ist so mächtig! Es kann für die Schwellenwertbildung usw. verwendet werden, indem nur der zweite Teil des Ausdrucks komplexer gemacht wird. Es scheint unmöglich zu sein, dies in der Dokumentation oder den Anleitungen zu finden. Wir sollten diesen Beitrag bewerben, damit die Leute ihn nutzen können! Leider scheint es nicht mit zusammengesetzten Ausdruck zu funktionieren - das heißt: 'cv :: Mat newMask = Maske <= 2;' aber das ist nicht 'cv :: Mat newMask = Maske> 2 && Maske <5; ' –

+0

@DavidDoria nur was mir in den Sinn kommt, ist die Verwendung von zwei zusätzlichen temporären Masken, zB cv :: Mat maskGreaterThan2 = M> 2; cv :: Mat maskLessThan5 = M <5; cv :: Mat Maske = MassGreaterThan2 & MaskeLessThan5. Leider ist dies im Vergleich zum Produktivitätsgewinn, den wir hier erreichen, wirklich speicher- und zeitaufwendig. – marol

2

Dank @marols Kommentaren habe ich mich für die folgende Implementierung entschieden. Ich verwende C++ 11 Lambda-Funktionen, um zu bestimmen, welche Werte geändert werden müssen. Um seine Macht zu demonstrieren, ist mein Zustand DEFAULT_VAL zu setzen, wenn der Wert aus dem Bereich [MIN_VAL, MAX_VAL]:

#include <functional> 

#define MatType float 
#define MatCmpFunc std::function<bool(const MatType&)> 
. 
. 
. 
// function which accepts lambda function to condition values which need to 
// be changed 
void MatSetIf(cv::Mat& inputmat, const MatType& newval, MatCmpFunc func) { 
    float* pmat = (float*)inputmat.data; 
    // iterate and set only values which fulfill the criteria 
    for (int idx = 0; idx < inputmat.total(); ++idx) { 
    if (func(pmat[idx])) { 
     pmat[idx] = newval; 
    } 
    } 
} 
. 
. 
. 
void main() { 
    cv::Mat mymat(100,100,CV_32FC1); 
    const float MIN_VAL = 10; 
    const float MAX_VAL = 1000; 
    const float DEFAULT_VAL = -1; 
    . 
    . 
    . 
    // declare lambda function which returns true when mat value out of range 
    MatCmpFunc func = [&](const DepthMatType& val) -> bool { 
    return (val < MIN_VAL || val > MAX_VAL) ? true : false; 
    }; 
    // use lambda func above to set all out of range values to 50 
    Mat32FSetIf(mymat, DEFAULT_VAL, func); 
    . 
    . 
    . 
} 
+2

Dies ist teilweise was ich als direkten Mat :: Datenzugriff bezeichnen. Die Verwendung von at() im Debug-Modus ist definitiv langsamer als setTo(). Wenn Sie sich also für eine solche Lösung entscheiden und einen bestimmten Matrixtyp haben, würde ich keine generelle Template-Funktion empfehlen, anstatt eine konkrete Funktion, die direkt funktioniert Mat :: data (wie opencv docs sagt, "wenn es um die Optimierung geht, nichts kann C-Array-Operator [] schlagen") – marol

+0

Danke @marol ... beide Kommentare waren wirklich hilfreich :) – ahmadh

3

Dies ist ein klassischer Fall für look-up table. Es ist schnell, einfach und kann mehrere Werte gleichzeitig neu zuordnen.