2013-01-08 15 views
6

Sto cercando di segmentare i biglietti da visita e suddividerli in base al colore di sfondo per trattarli come diverse regioni di interesse.Segmentazione dell'immagine per colore di sfondo - OpenCV Android

Per esempio una scheda di questo tipo: Sample business card

dovrebbero poter essere quello di essere diviso in due immagini in quanto vi sono 2 colori di sfondo. Ci sono suggerimenti su come affrontarlo? Ho provato a fare qualche analisi di profilo che non ha avuto esito positivo.

Altre carte esempio: enter image description here

Questa carta dovrebbero dare 3 segmentazioni, in quanto vi sono tre parti, anche se è solo 2 colori (anche se 2 colori saranno a posto).

enter image description here

La scheda di cui sopra dovrebbe fare un solo la segmentazione in quanto è solo un colore di sfondo.

Non sto ancora provando a pensare a sfondi sfumati.

risposta

8

Dipende da come appaiono le altre carte, ma se le immagini sono tutte di ottima qualità, non dovrebbe essere troppo difficile.

Nell'esempio che hai postato, puoi semplicemente raccogliere i colori dei pixel del bordo (la colonna più a sinistra, la colonna più a destra, la prima riga, l'ultima riga) e trattare ciò che trovi come possibili colori di sfondo. Forse controlla se ci sono abbastanza pixel con più o meno lo stesso colore. Hai bisogno di un qualche tipo di misurazione della distanza. Una soluzione facile è utilizzare la distanza euclidea nello spazio colore RGB.

Una soluzione più generica sarebbe quella di trovare i cluster negli istogrammi colore dell'intera immagine e trattare ogni colore (sempre con tolleranza) che ha più del x% della quantità complessiva di pixel come colore di sfondo. Ma ciò che definisci come sfondo dipende da cosa vuoi ottenere e come appaiono le tue immagini.

Se hai bisogno di ulteriori suggerimenti, puoi pubblicare più immagini e taggare quali parti delle immagini vuoi che vengano rilevate come colore di sfondo e cosa no.

-

Edit: I suoi due nuove immagini mostrano anche lo stesso modello. I colori di sfondo occupano gran parte dell'immagine, non c'è rumore e non ci sono sfumature di colore. Quindi, un approccio semplice potrebbe essere simile al seguente:

Se si dispone di esempi che non funzionano con questo approccio, basta inviare.

+0

Ho aggiunto alcune schede di esempio. Puoi anche riferire la tua risposta più a OpenCV se possibile? – SalGad

+0

Ho modificato la mia risposta in base alle nuove informazioni. –

+0

Grazie a @Dobi, ci proverò e ti faccio sapere :) – SalGad

0

Come approccio per trovare anche sfondi con sfumature di colore in essi, si potrebbe usare astuto. Il seguente codice (sì, non Android, lo so, ma il risultato dovrebbe essere lo stesso se lo porti) funziona bene con le tre immagini di esempio che hai postato finora. Se hai altre immagini, che non funzionano con questo, per favore fatemelo sapere.

#include <opencv2/opencv.hpp> 

using namespace cv; 
using namespace std; 

Mat src; 
Mat src_gray; 
int canny_thresh = 100; 
int max_canny_thresh = 255; 
int size_per_mill = 120; 
int max_size_per_mill = 1000; 
RNG rng(12345); 

bool cmp_contour_area_less(const vector<Point>& lhs, const vector<Point>& rhs) 
{ 
    return contourArea(lhs) < contourArea(rhs); 
} 

void Segment() 
{ 
    Mat canny_output; 
    vector<vector<Point> > contours; 
    vector<Vec4i> hierarchy; 

    Canny(src_gray, canny_output, canny_thresh, canny_thresh*2, 3); 

    // Draw rectangle around canny image to also get regions touching the edges. 
    rectangle(canny_output, Point(1, 1), Point(src.cols-2, src.rows-2), Scalar(255)); 
    namedWindow("Canny", CV_WINDOW_AUTOSIZE); 
    imshow("Canny", canny_output); 

    // Find the contours. 
    findContours(canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0)); 

    // Remove largest Contour, because it represents always the whole image. 
    sort(contours.begin(), contours.end(), cmp_contour_area_less); 
    contours.resize(contours.size()-1); 
    reverse(contours.begin(), contours.end()); 

    // Maximum contour size. 
    int image_pixels(src.cols * src.rows); 
    cout << "image_pixels: " << image_pixels << "\n"; 

    // Filter the contours, leaving just large enough ones. 
    vector<vector<Point> > background_contours; 
    for(size_t i(0); i < contours.size(); ++i) 
    { 
     double area(contourArea(contours[i])); 
     double min_size((size_per_mill/1000.0) * image_pixels); 
     if (area >= min_size) 
     { 
      cout << "Background contour " << i << ") area: " << area << "\n"; 
      background_contours.push_back(contours[i]); 
     } 
    } 

    // Draw large contours. 
    Mat drawing = Mat::zeros(canny_output.size(), CV_8UC3); 
    for(size_t i(0); i < background_contours.size(); ++i) 
    { 
     Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255)); 
     drawContours(drawing, background_contours, i, color, 1, 8, hierarchy, 0, Point()); 
    } 

    namedWindow("Contours", CV_WINDOW_AUTOSIZE); 
    imshow("Contours", drawing); 
} 

void size_callback(int, void*) 
{ 
    Segment(); 
} 

void thresh_callback(int, void*) 
{ 
    Segment(); 
} 

int main(int argc, char* argv[]) 
{ 
    if (argc != 2) 
    { 
     cout << "Please provide an image file.\n"; 
     return -1; 
    } 

    src = imread(argv[1]); 

    cvtColor(src, src_gray, CV_BGR2GRAY); 
    blur(src_gray, src_gray, Size(3,3)); 

    namedWindow("Source", CV_WINDOW_AUTOSIZE); 
    imshow("Source", src); 

    if (!src.data) 
    { 
     cout << "Unable to load " << argv[1] << ".\n"; 
     return -2; 
    } 

    createTrackbar("Canny thresh:", "Source", &canny_thresh, max_canny_thresh, thresh_callback); 
    createTrackbar("Size thresh:", "Source", &size_per_mill, max_size_per_mill, thresh_callback); 

    Segment(); 
    waitKey(0); 
}