2016-01-20 16 views
5

Immagine Ingresso:Creazione rettangolo all'interno di un blob utilizzando OpenCV

Uscita Image:

ho diverse chiazze colorate in un'immagine e sto cercando di creare rettangoli (o quadrati - che sembra essere molto più facile) all'interno del più grande blob di ogni colore. Ho trovato the answer to how to create a rectangle that bounds a single largest blob, ma non sono sicuro su come trovare un quadrato che si adatta semplicemente all'interno di un blob. Non deve essere il più grande, deve solo essere più grande di una certa area altrimenti non lo includerò. Ho visto anche dei lavori sui poligoni, ma nulla per le forme amorfe.

+0

Se si fornisce un'immagine non compressa, vi posto nella mia risposta anche i risultati sulla vostra immagine. – Miki

risposta

0

È possibile utilizzare this code per individuare il quadrato o il rettangolo più grande inscritto all'interno di una forma arbitraria. Sebbene sia MATLAB anziché C++/OpenCV, puoi facilmente cambiare il suo codice sorgente in base alle tue esigenze.

Per individuare il rettangolo più grande inscritto all'interno di poligoni convessi, controllare here (con codice).

1

Per un singolo blob, il problema può essere formulato come: find the largest rectangle containing only zeros in a matrix.

Per trovare il rettangolo orientato agli assi più grande all'interno di un BLOB, è possibile fare riferimento alla funzione findMinRect in my other answer. Il codice è un porting in C++ dell'originale in Python dal here.


Quindi il secondo problema è trovare tutti i BLOB con lo stesso colore. Questo è un po 'complicato perché l'immagine è jpeg e la compressione crea molti colori artificiali vicino ai bordi. Così ho creato un'immagine png (mostrata sotto), solo per mostrare che l'algoritmo funziona. Sta a te fornire un'immagine senza artefatti da compressione.

Quindi è sufficiente creare una maschera per ciascun colore, trovare i componenti collegati per ciascun blob in questa maschera e calcolare il rettangolo minimo per ciascun blob.

immagine iniziale:

enter image description here

Qui mi mostrano i rettangoli trovati per ogni blob, divisi per colore. È quindi possibile prendere solo i rettangoli necessari, il rettangolo massimo per ciascun colore o il rettangolo per il blob più grande per ciascun colore.

Risultato:

enter image description here

Ecco il codice:

#include <opencv2/opencv.hpp> 
#include <algorithm> 
#include <set> 
using namespace std; 
using namespace cv; 

// https://stackoverflow.com/a/30418912/5008845 
Rect findMinRect(const Mat1b& src) 
{ 
    Mat1f W(src.rows, src.cols, float(0)); 
    Mat1f H(src.rows, src.cols, float(0)); 

    Rect maxRect(0, 0, 0, 0); 
    float maxArea = 0.f; 

    for (int r = 0; r < src.rows; ++r) 
    { 
     for (int c = 0; c < src.cols; ++c) 
     { 
      if (src(r, c) == 0) 
      { 
       H(r, c) = 1.f + ((r>0) ? H(r - 1, c) : 0); 
       W(r, c) = 1.f + ((c>0) ? W(r, c - 1) : 0); 
      } 

      float minw = W(r, c); 
      for (int h = 0; h < H(r, c); ++h) 
      { 
       minw = min(minw, W(r - h, c)); 
       float area = (h + 1) * minw; 
       if (area > maxArea) 
       { 
        maxArea = area; 
        maxRect = Rect(Point(c - minw + 1, r - h), Point(c + 1, r + 1)); 
       } 
      } 
     } 
    } 

    return maxRect; 
} 


struct lessVec3b 
{ 
    bool operator()(const Vec3b& lhs, const Vec3b& rhs) { 
     return (lhs[0] != rhs[0]) ? (lhs[0] < rhs[0]) : ((lhs[1] != rhs[1]) ? (lhs[1] < rhs[1]) : (lhs[2] < rhs[2])); 
    } 
}; 

int main() 
{ 
    // Load image 
    Mat3b img = imread("path_to_image"); 

    // Find unique colors 
    set<Vec3b, lessVec3b> s(img.begin(), img.end()); 

    // Divide planes of original image 
    vector<Mat1b> planes; 
    split(img, planes); 
    for (auto color : s) 
    { 
     // Create a mask with only pixels of the given color 
     Mat1b mask(img.rows, img.cols, uchar(255)); 
     for (int i = 0; i < 3; ++i) 
     { 
      mask &= (planes[i] == color[i]); 
     } 

     // Find blobs 
     vector<vector<Point>> contours; 
     findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); 

     for (int i = 0; i < contours.size(); ++i) 
     { 
      // Create a mask for each single blob 
      Mat1b maskSingleContour(img.rows, img.cols, uchar(0)); 
      drawContours(maskSingleContour, contours, i, Scalar(255), CV_FILLED); 

      // Find minimum rect for each blob 
      Rect box = findMinRect(~maskSingleContour); 

      // Draw rect 
      Scalar rectColor(color[1], color[2], color[0]); 
      rectangle(img, box, rectColor, 2); 
     } 
    } 

    imshow("Result", img); 
    waitKey(); 

    return 0; 
} 
Problemi correlati