2014-05-09 26 views
6

Bir koşulu yerine getirdiyse, cv :: Mat içindeki tüm değerleri belirli bir değere ayarlamak için basit bir yol var mı? Örneğin, ben CV_32FC1 var ve ben sadece bu yapardı MATLAB'de 20'ye 0 olan tüm değerleri ayarlamak istiyorum:OpenCV cv :: Mat set

M(M == 0) = 20; 

cevap

11

Sen Ancak

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

kullanabilirsiniz, o kullanıyor içerir Maske oluşturmak için ek bellek, ancak opencv API kullanarak bir çözümdür, bu nedenle tüm matris türlerine uygulanabilir. Performans sorunlarını göz önünde bulundurursanız, bu matris tipi için bu çözümü optimize etmek için her zaman Mat :: verisine doğrudan başvurabilirsiniz.

+0

Bu çok güçlü! İfadenin ikinci kısmını daha karmaşık hale getirerek eşikleme, vb. Için kullanılabilir. Bunu dokümantasyonda veya öğreticilerde bulmak imkansız görünüyor. Bu yayını tanıtmalıyız, böylece insanlar bunu kullanmayı biliyor! Ne yazık ki, bileşik ifadeyle çalışmak gibi görünmüyor - yani bu işler: 'cv :: Mat newMask = maske <= 2;' ancak bu, cv :: Mat newMask = mask> 2 && mask <5; ' –

+0

@DavidDoria sadece şimdi aklıma gelen iki ek geçici maske kullanmaktır, yani cv :: Mat maskGreaterThan2 = M> 2; cv :: Mat maskLessThan5 = M <5; cv :: Mat maskesi = kitleGreaterThan2 ve maskLessThan5. Ne yazık ki bu, burada elde ettiğimiz verimlilik artışına kıyasla gerçekten hafıza ve zaman pahalıdır. – marol

2

@marol'ün yorumları sayesinde, aşağıdaki uygulamaya yerleştim. Hangi değerlerin değiştirilmesi gerektiğini şart koşmak için C++ 11 lambda fonksiyonlarını kullanıyorum. gücünü göstermek için, benim durumum [MAX_VAL, MIN_VAL] değer aralığı dışına çıktığında DEFAULT_VAL için ayarlamaktır:

#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

Bu kısmen doğrudan Mat :: veri erişimi olarak adlandırıyorum. Hata ayıklama modunda at() 'da kullanmak setTo()' dan kesinlikle daha yavaştır, bu nedenle bu tür bir çözümü kullanmaya karar verirseniz ve belirli bir matris türüne sahipseniz, doğrudan doğruya çalışan somut işlev yerine genel bir şablon işlevi oluşturmanızı önermem. Mat :: data (opencv docs'ın dediği gibi, "optimizasyon şartlarına geldiğinde hiçbir şey C dizisi operatörünü yenemez []") – marol

+0

Teşekkürler @marol ... her iki yorum da gerçekten yardımcı oldu :) – ahmadh

3

Bu look-up table için klasik bir durumdur. Hızlı, basit ve aynı anda birden fazla değeri tekrarlayabilir.