2012-04-25 10 views
24

मुझे काले रंग के सिक्कों के अंदर सफेद छेद भरने में समस्या है ताकि मेरे पास भरे काले सिक्कों के साथ केवल 0-255 बाइनरी छवि हो .. मैंने इसे पूरा करने के लिए मध्य फ़िल्टर का उपयोग किया है लेकिन उस मामले में सिक्के के बीच संबंध पुल बढ़ता है और यह कटाव के कई बार के बाद उन्हें पहचान करने के लिए असंभव हो जाता है ... तो मैं opencv में विधि की तरह एक साधारण floodFill जरूरतबाइनरी ऑब्जेक्ट के अंदर छेद भरना

यहाँ छेद के साथ मेरी छवि है:

enter image description here

संपादित करें: फ़ंक्शन की तरह बाढ़ भरने को छेद भरना होगा X को संकेत दिए बिना बड़े घटकों में, वाई बीज के रूप में निर्देशांक ...

संपादित करें: मैंने cvDrawContours फ़ंक्शन का उपयोग करने की कोशिश की लेकिन मैं बड़े लोगों के अंदर समरूपता नहीं भरता।

 CvMemStorage mem = cvCreateMemStorage(0); 
     CvSeq contours = new CvSeq(); 
     CvSeq ptr = new CvSeq(); 
     int sizeofCvContour = Loader.sizeof(CvContour.class); 

     cvThreshold(gray, gray, 150, 255, CV_THRESH_BINARY_INV); 

     int numOfContours = cvFindContours(gray, mem, contours, sizeofCvContour, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
     System.out.println("The num of contours: "+numOfContours); //prints 87, ok 

     Random rand = new Random(); 
     for (ptr = contours; ptr != null; ptr = ptr.h_next()) { 
      Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat()); 
      CvScalar color = CV_RGB(randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue()); 
      cvDrawContours(gray, ptr, color, color, -1, CV_FILLED, 8); 
     } 
     CanvasFrame canvas6 = new CanvasFrame("drawContours"); 
     canvas6.showImage(gray); 

परिणाम::

यहाँ मेरी कोड है (आप प्रत्येक सिक्का अंदर ब्लैक होल देख सकते हैं)

enter image description here

उत्तर

36

यह करने के लिए दो तरीकों रहे हैं।

des = cv2.bitwise_not(gray) 
contour,hier = cv2.findContours(des,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE) 

for cnt in contour: 
    cv2.drawContours(des,[cnt],0,255,-1) 

gray = cv2.bitwise_not(des) 

परिणामस्वरूप छवि:

enter image description here

2) छवि उद्घाटन:

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) 
res = cv2.morphologyEx(gray,cv2.MORPH_OPEN,kernel) 

जिसके परिणामस्वरूप छवि इस प्रकार है:

enter image description here

आप देख सकते हैं, दोनों मामलों में कोई अंतर नहीं है।

नायब: ग्रे - ग्रेस्केल छवि, सभी कोड OpenCV-अजगर में हैं

+0

+1 सिर्फ इसलिए कि मैं सरल समाधान का आनंद लें। – karlphillip

+0

मेरे मामले cvDrawContours में मुझे लगता है कि काम नहीं करता, मैं पोस्ट को अद्यतन किया है .. –

+0

ठीक है, मैं एक पैरामीटर समस्या मैं का उपयोग करना चाहिए था: cvDrawContours (ग्रे, ptr, रंग, रंग, 0, CV_FILLED, 8); अधिकतम_लेवल पैरामीटर के रूप में 0 के साथ। एचएम अब सफलता से भर गया :) –

1

cvFindContours() समारोह का उपयोग करें। आप कनेक्टेड घटकों को खोजने के लिए इसका इस्तेमाल कर सकते हैं। सही पैरामीटर के साथ यह फ़ंक्शन प्रत्येक कनेक्टेड घटकों के रूप में एक सूची देता है।

एक छेद का प्रतिनिधित्व करने वाले समोच्च खोजें। फिर अग्रभूमि रंग से चयनित समोच्च को भरने के लिए cvDrawContours() का उपयोग करें जिससे छेद बंद हो जाए।

+0

मेरे मामले cvDrawContours में मुझे लगता है कि काम नहीं करता है, मैं पोस्ट को अद्यतन किया है ... –

5

एक साधारण पतला और ईरोड अंतराल को अच्छी तरह से बंद कर देगा, मुझे कल्पना है। मुझे लगता है कि शायद यही वह है जिसे आप ढूंढ रहे हैं।

एक और मजबूत समाधान पूरी छवि पर किनारे का पता लगाने के लिए होगा, और उसके बाद सर्कल के लिए एक आटा परिवर्तन होगा। एक त्वरित Google दिखाता है कि एक आटा परिवर्तन का उपयोग करके सर्किलों के आकार परिवर्तनीय पहचान के लिए विभिन्न भाषाओं में कोड नमूने उपलब्ध हैं, इसलिए उम्मीद है कि आपको कुछ आगे बढ़ने के लिए कुछ मिल जाएगा।

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

1) कंटूर भरने:

पहले की विपरीत छवि, छवि में आकृति मिल जाए, ब्लैक के साथ इसे भरने और वापस पलट

3

आप Fillhole transformation, रूपात्मक छवि पुनर्निर्माण की एक आवेदन की तलाश में हो सकता है।

यह परिवर्तन आपके सिक्कों में छेद भर देगा, भले ही आसन्न सिक्कों के समूहों के बीच सभी छेद भरने की लागत पर। अन्य पोस्टर्स द्वारा सुझाए गए हफ़ स्पेस या ओपनिंग-आधारित समाधान शायद आपको बेहतर उच्च स्तरीय मान्यता परिणाम देंगे।

+2

लेकिन openlv के लिए matlab –

+0

@lbstr के लिए नहीं: पृष्ठ मुख्य रूप से सिद्धांत को समझाता है। मैं आपको अपने सिर से ओपनसीवी कोड नहीं दे सकता। – thiton

+0

लिंक मर चुका है। – Reunanen

1

मुझे लगता है कि वस्तुओं को छुआ या भीड़ में रखा गया है, तो समोच्चों और गणित के रूप में उद्घाटन का उपयोग करने में कुछ समस्याएं होंगी। इसके बजाए, निम्नलिखित सरल समाधान पाया और परीक्षण किया गया है। यह न केवल इस छवियों के लिए, बल्कि किसी अन्य छवियों के लिए भी बहुत अच्छा काम कर रहा है।

यहाँ कदम (अनुकूलित) में http://blogs.mathworks.com/steve/2008/08/05/filling-small-holes/

जाने I देखा है: इनपुट छवि

1. filled_I = floodfill(I). // fill every hole in the image. 
2. inverted_I = invert(I)`. 
3. holes_I = filled_I AND inverted_I. // finds all holes 
4. cc_list = connectedcomponent(holes_I) // list of all connected component in holes_I. 
5. holes_I = remove(cc_list,holes_I, smallholes_threshold_size) // remove all holes from holes_I having size > smallholes_threshold_size. 
6. out_I = I OR holes_I. // fill only the small holes. 

संक्षेप में, एल्गोरिथ्म सभी छेद खोजने के लिए है, तो बड़ा लोगों को निकालने के बारे में बस है छोटे मूल केवल मूल छवि पर।

0

मैं imfill फ़ंक्शन (मैटलैब में से एक के रूप में) को खोजने के लिए इंटरनेट के चारों ओर देख रहा हूं लेकिन ओपनसीवी के साथ सी में काम कर रहा हूं।

IplImage* imfill(IplImage* src) 
{ 
    CvScalar white = CV_RGB(255, 255, 255); 

    IplImage* dst = cvCreateImage(cvGetSize(src), 8, 3); 
    CvMemStorage* storage = cvCreateMemStorage(0); 
    CvSeq* contour = 0; 

    cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
    cvZero(dst); 

    for(; contour != 0; contour = contour->h_next) 
    { 
     cvDrawContours(dst, contour, white, white, 0, CV_FILLED); 
    } 

    IplImage* bin_imgFilled = cvCreateImage(cvGetSize(src), 8, 1); 
    cvInRangeS(dst, white, white, bin_imgFilled); 

    return bin_imgFilled; 
} 

इसके लिए: Original Binary Image

परिणाम है: Final Binary Image

चाल cvDrawContours समारोह के मापदंडों की स्थापना में है: कुछ reaserches के बाद, मैं अंत में एक समाधान के साथ आया था cvDrawContours (डीएसटी, समोच्च, सफेद, सफेद, 0, सीवी_एफल्डडी);

  • डीएसटी = गंतव्य छवि
  • समोच्च = पहले समोच्च
  • सफेद = रंग तैयार आकृति के लिए समोच्च
  • 0 = अधिकतम स्तर को भरने के लिए प्रयोग किया जाता करने के लिए सूचक। यदि 0, केवल समोच्च खींचा जाता है
  • सीवी_एफल्डडी = समोच्चों के साथ रेखाओं की मोटाई खींची जाती है।यदि यह नकारात्मक है (उदाहरण के लिए, = सीवी_एफआईएलडीडी), समोच्च अंदरूनी खींचे जाते हैं। openCV दस्तावेज में

अधिक जानकारी।

शायद एक तरह से एक द्विआधारी छवि के रूप में "DST" पाने के लिए सीधे है, लेकिन मैं कैसे द्विआधारी मूल्यों के साथ cvDrawContours समारोह का उपयोग करने के नहीं पा सके।

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