2012-04-25 13 views
7

मैं जावासीवी (ओपनसीवी रैपर) का उपयोग करके एक सिक्का पहचान कर रहा हूं लेकिन सिक्के कनेक्ट होने पर मुझे थोड़ी सी समस्या है। अगर मैं इन सिक्कों को अलग करने के लिए उन्हें खराब करने की कोशिश करता हूं तो वे अपना सर्कल फॉर्म खो देते हैं और यदि मैं प्रत्येक सिक्का के अंदर पिक्सेल गिनने की कोशिश करता हूं तो समस्याएं हो सकती हैं ताकि कुछ सिक्कों को एक बड़ा के रूप में गिना जा सके। मैं जो करना चाहता हूं वह सबसे पहले उन्हें दोबारा बदलने और उन्हें एक सर्कल (उस सिक्का के त्रिज्या के बराबर) बनाने के लिए बनाना है और फिर उनके अंदर पिक्सेल गिनना है।शोर फ़ॉर्म में शोर का सिक्का

यहाँ मेरी thresholded छवि है: enter image description here

कोई सुझाव: enter image description here

और यहाँ छवि घिस रहा है? या सिक्कों के बीच पुलों को तोड़ने का कोई बेहतर तरीका है?

उत्तर

11

यह एक समस्या मैं फिर से के समान दिखता है केंद्रीय प्लेटों पर बढ़ते जीवाणु उपनिवेशों को अलग करना था। मैंने थ्रेसहोल्ड छवि पर एक दूरी परिवर्तन किया (आपके मामले में आपको इसे उलटा करने की आवश्यकता होगी)। फिर दूरी मानचित्र के शिखर पाए गए (एक फैला हुआ दूरी मानचित्र और दूरी मानचित्र और शून्य मानों के बीच अंतर की गणना करके)। फिर, मैंने प्रत्येक चोटी को एक सर्कल (सिक्का) का केंद्र और दूरी मानचित्र में चोटी का मूल्य सर्कल के त्रिज्या के रूप में माना।

यहाँ इस पाइप लाइन के बाद अपनी छवि का परिणाम है: distance transform works

मैं OpenCV के लिए नया हूँ, और C++ तो मेरे कोड शायद बहुत गंदा है, लेकिन मैंने किया था कि:

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

    cv::Mat objects, distance,peaks,results; 
    std::vector<std::vector<cv::Point> > contours; 

    objects=cv::imread("CUfWj.jpg"); 
    objects.copyTo(results); 
    cv::cvtColor(objects, objects, CV_BGR2GRAY); 
    //THIS IS THE LINE TO BLUR THE IMAGE CF COMMENTS OF THIS POST 
    cv::blur(objects,objects,cv::Size(3,3)); 
    cv::threshold(objects,objects,125,255,cv::THRESH_BINARY_INV); 


    /*Applies a distance transform to "objects". 
    * The result is saved in "distance" */ 
    cv::distanceTransform(objects,distance,CV_DIST_L2,CV_DIST_MASK_5); 

    /* In order to find the local maxima, "distance" 
    * is subtracted from the result of the dilatation of 
    * "distance". All the peaks keep the save value */ 
    cv::dilate(distance,peaks,cv::Mat(),cv::Point(-1,-1),3); 
    cv::dilate(objects,objects,cv::Mat(),cv::Point(-1,-1),3); 

    /* Now all the peaks should be exactely 0*/ 
    peaks=peaks-distance; 

    /* And the non-peaks 255*/ 
    cv::threshold(peaks,peaks,0,255,cv::THRESH_BINARY); 
    peaks.convertTo(peaks,CV_8U); 

    /* Only the zero values of "peaks" that are non-zero 
    * in "objects" are the real peaks*/ 
    cv::bitwise_xor(peaks,objects,peaks); 

    /* The peaks that are distant from less than 
    * 2 pixels are merged by dilatation */ 
    cv::dilate(peaks,peaks,cv::Mat(),cv::Point(-1,-1),1); 

    /* In order to map the peaks, findContours() is used. 
    * The results are stored in "contours" */ 
    cv::findContours(peaks, contours, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
    /* The next steps are applied only if, at least, 
    * one contour exists */ 
    cv::imwrite("CUfWj2.jpg",peaks); 
    if(contours.size()>0){ 

     /* Defines vectors to store the moments of the peaks, the center 
     * and the theoritical circles of the object of interest*/ 
     std::vector <cv::Moments> moms(contours.size()); 
     std::vector <cv::Point> centers(contours.size()); 
     std::vector<cv::Vec3f> circles(contours.size()); 
     float rad,x,y; 
     /* Caculates the moments of each peak and then the center of the peak 
     * which are approximatively the center of each objects of interest*/ 

     for(unsigned int i=0;i<contours.size();i++) { 
      moms[i]= cv::moments(contours[i]); 
      centers[i]= cv::Point(moms[i].m10/moms[i].m00,moms[i].m01/moms[i].m00); 
      x= (float) (centers[i].x); 
      y= (float) (centers[i].y); 
      if(x>0 && y>0){ 
       rad= (float) (distance.at<float>((int)y,(int)x)+1); 
       circles[i][0]= x; 
       circles[i][3]= y; 
       circles[i][2]= rad; 
       cv::circle(results,centers[i],rad+1,cv::Scalar(255, 0,0), 2, 4, 0); 
      } 
     } 
     cv::imwrite("CUfWj2.jpg",results); 
    } 

    return 1; 
} 
+1

आपको सबसे अच्छा परिणाम मिला है .. मैं आज रात जावासीवी पर कोशिश करूंगा! –

+0

+1 दिलचस्प दृष्टिकोण। – karlphillip

+1

** हालांकि **, [मुझे आपके कोड से मिली छवि] (http://imageshack.us/photo/my-images/526/58131003.jpg/) आपके द्वारा दिखाए गए एक से थोड़ा अलग है। – karlphillip

2

ओपनसीवी में एक कार्य है जिसे HoughCircles() कहा जाता है जिसे विभिन्न मंडलियों को अलग किए बिना आपके मामले पर लागू किया जा सकता है। क्या आप इसे जावासीवी से कॉल कर सकते हैं? यदि ऐसा है, तो आप अपनी अलग-अलग समस्या को छोड़कर, जो चाहते हैं वह करेंगे (सर्किल का पता लगाने और गिनती)।

मुख्य बिंदु सर्कल को पहले अलग किए बिना सटीक रूप से पहचानना है। अन्य एल्गोरिदम (जैसे टेम्पलेट मिलान का उपयोग सामान्यीकृत हफ़ ट्रांसफॉर्म के बजाय किया जा सकता है, लेकिन आपको सिक्के के विभिन्न आकारों को ध्यान में रखना होगा।

+0

सबसे पहले मैंने गॉसियन धुंधला और फिर cvHoughCircles लगाया लेकिन कुछ छवियों में यह सही त्रिज्या और सर्कल के लिए केंद्र नहीं मिल सकता है।और कुछ छवियों में भी यह गलत सर्किलों को पाता है - विशेष रूप से जब सिक्कों को समूहीकृत किया जाता है और उनमें से बहुत सारे होते हैं .. –

+0

गॉसियन के बजाय औसत माध्य का उपयोग करना बेहतर है, क्योंकि धुंध प्रभाव को सीमित कर देगा (इसलिए यह आपके एल्गोरिदम की सटीकता में सुधार करेगा)। मुख्य समस्या यह है कि इन जटिल आकारों को मोर्फोलॉजी से अलग करना बहुत मुश्किल है (आपको सारांशित करने के लिए बहुत कुछ करना होगा)। यदि हफ़ सर्किल काम नहीं करते हैं, तो आप सीधे मंडलियों का पता लगाने के लिए, विभिन्न स्केलों की मंडलियों के साथ टेम्पलेट मिलान करने का प्रयास कर सकते हैं। – sansuiso

5

आपको cvHoughCircles() के लिए पैरा का एक अच्छा सेट खराब करने की आवश्यकता नहीं है :

enter image description here

कोड उत्पन्न करने के लिए इस छवि मेरे दूसरे पोस्ट से आया इस्तेमाल किया: इन मानकों के साथ Detecting Circles,:

CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->height/12, 80, 26); 
+0

ठीक है कि ठंडा है लेकिन कुछ मामलों में हौ सर्किल विधि में 5 सेंट और 10 सेंट उसी त्रिज्या के साथ खींचा जा सकता है जो मैं नहीं चाहता हूं, मुझे बस प्रत्येक सिक्का के लिए त्रिज्या मिलना चाहिए और यह पता लगाएं कि उस छवि पर कितना पैसा है त्रिज्या .. –

+0

समस्या यह है कि जब आप क्षरण निष्पादित करते हैं, तो आप इस जानकारी को खो देते हैं, जैसा कि आपने पहले ही देखा है। यदि आप हौ सर्किल का उपयोग करके अपने पहचान को बेहतर बनाने के तरीके की जांच करने में समय बिताने के इच्छुक नहीं हैं, तो मुझे यह सुझाव देना होगा कि आप [SURF] (http://achuwilson.wordpress.com/2011/08/ का उपयोग करके एक पूरी तरह से अलग दृष्टिकोण लेते हैं। 05/ऑब्जेक्ट-डिटेक्शन-यूज-सर्फ-इन-ओपनसीवी-भाग -1 /) या [हायर] (http://achuwilson.wordpress.com/2011/02/13/object-detection-using-opencv-using- हार्ट्रेनिंग /) [प्रशिक्षण] (http://note.sonots.com/SciSoftware/haartraining.html) सिक्कों का पता लगाने के लिए। – karlphillip

+0

यदि आपको केवल एक-दूसरे के पास सिक्कों से निपटना है, तो यह मुश्किल है कि हफ़ सर्किल संभाल सकता है। लेकिन अगर आपको एक-दूसरे के ऊपर ओवरलैप करने वाले सिक्कों से निपटना है, तो आपको केवल उन अन्य दृष्टिकोणों पर विचार करना चाहिए जिन्हें मैंने अभी सुझाव दिया था। – karlphillip

1

क्षरण-आधारित ऑब्जेक्ट मान्यता के लिए सामान्य दृष्टिकोण एरोडेड छवि में निरंतर क्षेत्रों को लेबल करना है और फिर मूल छवि में क्षेत्रों से मेल खाने तक उन्हें फिर से विकसित करना है। हालांकि, आपके मामले में कठिन सर्कल एक बेहतर विचार है।

0

शामिल सिक्कों का पता लगाने के बाद, मैं "निश्चित रूप से सिक्का" और "निश्चित रूप से सिक्का नहीं" के रूप में वर्गीकृत करने के लिए मॉर्फोलॉजिकल ऑपरेशंस लागू करने की सलाह देता हूं, दूरी परिवर्तन लागू करता हूं, फिर सीमा निर्धारित करने के लिए वाटरशेड चलाता हूं। यह परिदृश्य वास्तव में ओपनसीवी में वाटरशेड एल्गोरिदम के लिए प्रदर्शन उदाहरण है - शायद यह इस प्रश्न के जवाब में बनाया गया था।

संबंधित मुद्दे