2014-01-29 5 views
16

Ich benutze OpenCV und möchte Rechtecke zusammenfassen, die signifikante Überlappungen haben. Ich habe versucht, groupRectangles dafür zu verwenden, die ein Gruppenschwellenwertargument nimmt. Bei einem Schwellenwert von 0 wird überhaupt keine Gruppierung durchgeführt, und bei einer Schwelle von 1 werden nur Rechtecke zurückgegeben, die das Ergebnis von mindestens zwei Rechtecken sind. Um zum Beispiel die Rechtecke auf der linken Seite im Bild unten angegebenen Sie mit den zwei Rechtecke auf der rechten Seite am Ende:OpenCV groupRectangles - gruppierte und nicht gruppierte Rechtecke

enter image description here

Was Ich mag würde mit 3 Rechtecke, um am Ende ist. Die 2 rechts im Bild oben, plus das Rechteck oben rechts im Bild links, das sich nicht mit anderen Rechtecken überschneidet. Was ist der beste Weg, dies zu erreichen?

+0

ich habe auch ein ähnliches Problem ... haben Sie bereits einige Lösung bekam dafür? – skm

Antwort

16

Die Lösung, mit der ich ging, war, alle ursprünglichen Rechtecke vor dem Aufruf groupRectangles zu duplizieren. Auf diese Weise jedes Eingang Rechteck ist garantiert mit mindestens einem anderen Rechteck gruppiert werden, und wird in der Ausgabe angezeigt:

int size = rects.size(); 
for(int i = 0; i < size; i++) 
{ 
    rects.push_back(Rect(rects[i])); 
} 
groupRectangles(rects, 1, 0.2); 
+0

Irgendwie funktioniert das nicht für mich. Die duplizierten Rechtecke werden in meinem Fall immer noch entfernt. Irgendeine Idee, was ich hier falsch mache? – Jaykob

+0

Update: Ich habe mein Problem gelöst. Ich hatte irgendwie ein großes Rechteck um alle anderen Rechtecke in meinen Eingabedaten. Das hat natürlich alles vermasselt. Entschuldigung d – Jaykob

0

Durch die Überprüfung aus groupRectangles() in opencv-3.3.0-Quellcode:

if(groupThreshold <= 0 || rectList.empty()) 
    { 
     // ...... 
     return; 
    } 

Ich sah, dass, wenn groupThreshold auf kleiner als oder gleich 0 gesetzt ist, die Funktion nur zurückkehren würde, ohne irgendeine Gruppierung zu tun.

Auf der anderen Seite entfernt das folgende code alle Rechtecke, die nicht mehr als groupThreshold Ähnlichkeiten haben.

// filter out rectangles which don't have enough similar rectangles 
    if(n1 <= groupThreshold) 
     continue; 

Das erklärt, warum mit groupThreshold = 1 nur mit mindestens 2 Überlappungen sind in der Ausgangsrechtecke.

Eine mögliche Lösung könnte darin bestehen, den oben gezeigten Quellcode zu ändern (n1 <= groupThreshold durch n1 < groupThreshold zu ersetzen) und OpenCV neu zu kompilieren.

0

Ein wenig spät auf die Party, aber "Duplizierung" Lösung hat nicht richtig für mich gearbeitet. Ich hatte auch ein anderes Problem, wo verschmolzene Rechtecke sich überlappen würden und zusammengeführt werden müssten.

Also kam ich mit einer Overkill-Lösung (möglicherweise C++ 14 Compiler erforderlich). Hier Verwendungsbeispiel:

std::vector<cv::Rect> rectangles, test1, test2, test3; 

rectangles.push_back(cv::Rect(cv::Point(5, 5), cv::Point(15, 15))); 
rectangles.push_back(cv::Rect(cv::Point(14, 14), cv::Point(26, 26))); 
rectangles.push_back(cv::Rect(cv::Point(24, 24), cv::Point(36, 36))); 

rectangles.push_back(cv::Rect(cv::Point(37, 20), cv::Point(40, 40))); 
rectangles.push_back(cv::Rect(cv::Point(20, 37), cv::Point(40, 40))); 

test1 = rectangles; 
test2 = rectangles; 
test3 = rectangles; 

//Output format: {Rect(x, y, width, height), ...} 

//Merge once 
mergeRectangles(test1); 
//Output rectangles: test1 = {Rect(5, 5, 31, 31), Rect(20, 20, 20, 20)} 

//Merge until there are no rectangles to merge 
mergeRectangles(test2, true); 
//Output rectangles: test2 = {Rect(5, 5, 35, 35)} 

//Override default merge (intersection) function to merge all rectangles 
mergeRectangles(test3, false, [](const cv::Rect& r1, const cv::Rect& r2) { 
    return true; 
}); 
//Output rectangles: test3 = {Rect(5, 5, 35, 35)} 

Funktion:

void mergeRectangles(std::vector<cv::Rect>& rectangles, bool recursiveMerge = false, std::function<bool(const cv::Rect& r1, const cv::Rect& r2)> mergeFn = nullptr) { 
    static auto defaultFn = [](const cv::Rect& r1, const cv::Rect& r2) { 
     return (r1.x < (r2.x + r2.width) && (r1.x + r1.width) > r2.x && r1.y < (r2.y + r2.height) && (r1.y + r1.height) > r2.y); 
    }; 

    static auto innerMerger = [](std::vector<cv::Rect>& rectangles, std::function<bool(const cv::Rect& r1, const cv::Rect& r2)>& mergeFn) { 
     std::vector<std::vector<std::vector<cv::Rect>::const_iterator>> groups; 
     std::vector<cv::Rect> mergedRectangles; 
     bool merged = false; 

     static auto findIterator = [&](std::vector<cv::Rect>::const_iterator& iteratorToFind) { 
      for (auto groupIterator = groups.begin(); groupIterator != groups.end(); ++groupIterator) { 
       auto foundIterator = std::find(groupIterator->begin(), groupIterator->end(), iteratorToFind); 
       if (foundIterator != groupIterator->end()) { 
        return groupIterator; 
       } 
      } 
      return groups.end(); 
     }; 

     for (auto rect1_iterator = rectangles.begin(); rect1_iterator != rectangles.end(); ++rect1_iterator) { 
      auto groupIterator = findIterator(rect1_iterator); 

      if (groupIterator == groups.end()) { 
       groups.push_back({rect1_iterator}); 
       groupIterator = groups.end() - 1; 
      } 

      for (auto rect2_iterator = rect1_iterator + 1; rect2_iterator != rectangles.end(); ++rect2_iterator) { 
       if (mergeFn(*rect1_iterator, *rect2_iterator)) { 
        groupIterator->push_back(rect2_iterator); 
        merged = true; 
       } 
      } 
     } 

     for (auto groupIterator = groups.begin(); groupIterator != groups.end(); ++groupIterator) { 
      auto groupElement = groupIterator->begin(); 

      int x1 = (*groupElement)->x; 
      int x2 = (*groupElement)->x + (*groupElement)->width; 
      int y1 = (*groupElement)->y; 
      int y2 = (*groupElement)->y + (*groupElement)->height; 

      while (++groupElement != groupIterator->end()) { 
       if (x1 > (*groupElement)->x) 
        x1 = (*groupElement)->x; 
       if (x2 < (*groupElement)->x + (*groupElement)->width) 
        x2 = (*groupElement)->x + (*groupElement)->width; 
       if (y1 >(*groupElement)->y) 
        y1 = (*groupElement)->y; 
       if (y2 < (*groupElement)->y + (*groupElement)->height) 
        y2 = (*groupElement)->y + (*groupElement)->height; 
      } 

      mergedRectangles.push_back(cv::Rect(cv::Point(x1, y1), cv::Point(x2, y2))); 
     } 

     rectangles = mergedRectangles; 
     return merged; 
    }; 

    if (!mergeFn) 
     mergeFn = defaultFn; 

    while (innerMerger(rectangles, mergeFn) && recursiveMerge); 
}