2012-09-19 23 views
7

मैं opencv ईएम एल्गोरिथ्म का उपयोग करने के रंग extraction.I opencv दस्तावेज में उदाहरण के आधार पर निम्न कोड का उपयोग कर रहा करने के लिए कोशिश कर रहा हूँ के आधार पर:OpenCV: रंग निष्कर्षण गाऊसी मिश्रण मॉडल

cv::Mat capturedFrame (height, width, CV_8UC3); 
int i, j; 
int nsamples = 1000; 
cv::Mat samples (nsamples, 2, CV_32FC1); 
cv::Mat labels; 
cv::Mat img = cv::Mat::zeros (height, height, CV_8UC3); 
img = capturedFrame; 
cv::Mat sample (1, 2, CV_32FC1); 
CvEM em_model; 
CvEMParams params; 
samples = samples.reshape (2, 0); 

    for (i = 0; i < N; i++) 
    {   
     //from the training samples 
     cv::Mat samples_part = samples.rowRange (i*nsamples/N, (i+1)*nsamples/N); 

     cv::Scalar mean (((i%N)+1)*img.rows/(N1+1),((i/N1)+1)*img.rows/(N1+1)); 
     cv::Scalar sigma (30,30); 
     cv::randn(samples_part,mean,sigma);      

    }  

    samples = samples.reshape (1, 0); 

    //initialize model parameters 
    params.covs   = NULL; 
    params.means  = NULL; 
    params.weights  = NULL; 
    params.probs  = NULL; 
    params.nclusters = N; 
    params.cov_mat_type = CvEM::COV_MAT_SPHERICAL; 
    params.start_step = CvEM::START_AUTO_STEP; 
    params.term_crit.max_iter = 300; 
    params.term_crit.epsilon = 0.1; 
    params.term_crit.type = CV_TERMCRIT_ITER|CV_TERMCRIT_EPS;  
    //cluster the data 
    em_model.train (samples, Mat(), params, &labels);  

    cv::Mat probs; 
    probs = em_model.getProbs(); 

    cv::Mat weights; 
    weights = em_model.getWeights(); 

cv::Mat modelIndex = cv::Mat::zeros (img.rows, img.cols, CV_8UC3); 

for (i = 0; i < img.rows; i ++) 
{ 
    for (j = 0; j < img.cols; j ++) 
    { 
     sample.at<float>(0) = (float)j; 
    sample.at<float>(1) = (float)i;  

    int response = cvRound (em_model.predict (sample)); 
    modelIndex.data [ modelIndex.cols*i + j] = response; 

    } 
} 

मेरे यहां सवाल यह है:

सबसे पहले, मैं प्रत्येक मॉडल को यहां पूरी तरह से पांच निकालना चाहता हूं, फिर उन अलग पिक्सेल मानों को पांच अलग-अलग मैट्रिक्स में संग्रहीत करना चाहता हूं। इस मामले में, मेरे पास अलग-अलग पांच अलग-अलग रंग हो सकते थे। यहां मैंने केवल अपनी अनुक्रमणिका प्राप्त की है, क्या उनके संबंधित रंगों को यहां प्राप्त करने का कोई तरीका है? इसे आसान बनाने के लिए, मैं इन पांच जीएमएम के आधार पर प्रमुख रंग खोजने से शुरू कर सकता हूं।

दूसरा, यहां मेरा नमूना डेटापॉइंट "100" है, और इसमें लगभग 3 सेकंड लगते हैं। लेकिन मैं इन सभी चीजों को 30 मिलीसेकंड से अधिक नहीं करना चाहता हूं। मुझे ओपनसीवी पृष्ठभूमि निष्कर्षण पता है, जो जीएमएम का उपयोग कर रहा है, 20ms से नीचे वास्तव में तेज़ प्रदर्शन करता है, इसका मतलब है कि मेरे लिए सभी 600x800 = 480000 पिक्सेल के लिए 30 एमएस के भीतर ऐसा करने का एक तरीका होना चाहिए। मैंने पाया predict फ़ंक्शन सबसे अधिक समय लेने वाला है।

+0

क्या यह प्रश्न अभी भी सक्रिय है? या इसे हल किया गया था [http://stackoverflow.com/questions/12909343/opencv-how-to-categorize-gmm-calculated-probs/12909985#12909985)? सम्मान – remi

+0

@remi: यह प्रश्न पुराना था, लेकिन मैंने एक और सवाल पूछा कि आपने उत्तर दिया है, मैंने इसे रंग निष्कर्षण और गणना की गति के साथ अपडेट किया है। क्या तुम मेरी मदद कर सकते हो? धन्यवाद। –

+1

मैं वास्तव में इस सवाल को समझ नहीं पा रहा हूं। रंग निकालने से मुझे कोई समझ नहीं आती है। क्या आप प्रमुख रंगों की गणना करने की कोशिश कर रहे हैं? या रंगों को मापें? आपका कोड मुझे बहुत मदद नहीं करता है। 'Params.cov_mat_type = COV_MAT_DIAGONAL' का उपयोग करके गति समस्या के बारे में अधिकतर मामलों के लिए पर्याप्त है और आपकी प्रक्रिया को तेज करेगा – remi

उत्तर

11

प्रथम प्रश्न:

आदेश रंग निष्कर्षण आप पहली बार अपने इनपुट पिक्सल के साथ ईएम प्रशिक्षित करने की आवश्यकता करने के लिए। इसके बाद आप बस सभी इनपुट पिक्सल पर लूप करें और उनमें से प्रत्येक को वर्गीकृत करने के लिए पूर्वानुमान() का उपयोग करें। मैंने एक छोटा सा उदाहरण संलग्न किया है जो रंगों के आधार पर अग्रभूमि/पृष्ठभूमि अलगाव के लिए ईएम का उपयोग करता है। यह आपको दिखाता है कि प्रत्येक गाऊशियन के प्रमुख रंग (माध्य) को कैसे निकालें और मूल पिक्सेल रंग का उपयोग कैसे करें।

#include <opencv2/opencv.hpp> 

int main(int argc, char** argv) { 

    cv::Mat source = cv::imread("test.jpg"); 

    //ouput images 
    cv::Mat meanImg(source.rows, source.cols, CV_32FC3); 
    cv::Mat fgImg(source.rows, source.cols, CV_8UC3); 
    cv::Mat bgImg(source.rows, source.cols, CV_8UC3); 

    //convert the input image to float 
    cv::Mat floatSource; 
    source.convertTo(floatSource, CV_32F); 

    //now convert the float image to column vector 
    cv::Mat samples(source.rows * source.cols, 3, CV_32FC1); 
    int idx = 0; 
    for (int y = 0; y < source.rows; y++) { 
     cv::Vec3f* row = floatSource.ptr<cv::Vec3f > (y); 
     for (int x = 0; x < source.cols; x++) { 
      samples.at<cv::Vec3f > (idx++, 0) = row[x]; 
     } 
    } 

    //we need just 2 clusters 
    cv::EMParams params(2); 
    cv::ExpectationMaximization em(samples, cv::Mat(), params); 

    //the two dominating colors 
    cv::Mat means = em.getMeans(); 
    //the weights of the two dominant colors 
    cv::Mat weights = em.getWeights(); 

    //we define the foreground as the dominant color with the largest weight 
    const int fgId = weights.at<float>(0) > weights.at<float>(1) ? 0 : 1; 

    //now classify each of the source pixels 
    idx = 0; 
    for (int y = 0; y < source.rows; y++) { 
     for (int x = 0; x < source.cols; x++) { 

      //classify 
      const int result = cvRound(em.predict(samples.row(idx++), NULL)); 
      //get the according mean (dominant color) 
      const double* ps = means.ptr<double>(result, 0); 

      //set the according mean value to the mean image 
      float* pd = meanImg.ptr<float>(y, x); 
      //float images need to be in [0..1] range 
      pd[0] = ps[0]/255.0; 
      pd[1] = ps[1]/255.0; 
      pd[2] = ps[2]/255.0; 

      //set either foreground or background 
      if (result == fgId) { 
       fgImg.at<cv::Point3_<uchar> >(y, x, 0) = source.at<cv::Point3_<uchar> >(y, x, 0); 
      } else { 
       bgImg.at<cv::Point3_<uchar> >(y, x, 0) = source.at<cv::Point3_<uchar> >(y, x, 0); 
      } 
     } 
    } 

    cv::imshow("Means", meanImg); 
    cv::imshow("Foreground", fgImg); 
    cv::imshow("Background", bgImg); 
    cv::waitKey(0); 

    return 0; 
} 

मैंने निम्नलिखित छवि के साथ कोड का परीक्षण किया है और यह काफी अच्छा प्रदर्शन करता है।

enter image description here

दूसरा प्रश्न:

मैंने देखा है समूहों की अधिकतम संख्या प्रदर्शन पर बहुत बड़ा प्रभाव पड़ता है। तो इसे खाली छोड़ने या इसे अपने उदाहरण में नमूने की संख्या में सेट करने के बजाय इसे बहुत रूढ़िवादी मूल्य पर सेट करना बेहतर है। इसके अलावा प्रलेखन कम-बाध्य पैरामीटर वाले मॉडल को बार-बार अनुकूलित करने के लिए एक पुनरावृत्ति प्रक्रिया का उल्लेख करता है। शायद यह आपको कुछ गति देता है। अधिक पढ़ने के लिए कृपया ट्रेन() here के लिए प्रदान किए गए नमूना कोड के अंदर दस्तावेज़ों पर एक नज़र डालें।

+0

मैंने आपके कोड की कोशिश की, और इसकी गणना गति को छोड़कर, यह काफी ठीक काम करता है। वैसे भी, मैं इसे संभालने की कोशिश करूंगा। अपने जवाब के लिए आपको बहुत बहुत धन्यवाद। –

+0

ठीक है, क्या मैं सोच रहा हूं कि आप कुछ छवि स्ट्रीम में रीयल-टाइम में एल्गोरिदम लागू करना चाहते हैं? यदि हां, तो आपको हर फ्रेम में ईएम को प्रशिक्षित करने की आवश्यकता नहीं है, लेकिन इसे पहली छवि के साथ प्रशिक्षित करने की आवश्यकता है और फिर केवल लगातार फ्रेम में भविष्यवाणी करें या यदि आपको प्रत्येक छवि में ट्रेन करने की आवश्यकता है तो पिछली ट्रेन और COV_MAT_DIAGONAL के मानों से शुरू करें (कृपया ट्रेन विधि के लिए ओपनसीवी दस्तावेज में दिए गए उदाहरण के अंदर कोड डॉक का संदर्भ लें) –

+0

यह समय लेने वाला हिस्सा नहीं है, लेकिन यह "भविष्यवाणी" हिस्सा है। मैं वीडियो फ्रेम सौंप रहा हूं, और एक 600x800 आकार के फ्रेम की भविष्यवाणी के लिए इसमें लगभग 3 सेकंड लगते हैं! क्या आपके पास गति के लिए कोई अन्य विचार है? –