2015-08-20 14 views
41

Prima di tutto ho questa immagine e voglio fare un'applicazione in grado di rilevare immagini come questa e rimuovere il cerchio (filigrana) da esso.Rimuovere la filigrana da un'immagine usando opencv

image has a watermark

int main(){ 
    Mat im1,im2,im3,gray,gray2,result; 

    im2=imread(" (2).jpg"); 
    namedWindow("x",CV_WINDOW_FREERATIO); 
    imshow("x",im2); 

    //converting it to gray 
    cvtColor(im2,gray,CV_BGR2GRAY); 
    // creating a new image that will have the cropped ellipse 
    Mat ElipseImg(im2.rows,im2.cols,CV_8UC1,Scalar(0,0,0)); 

    //detecting the largest circle 
    GaussianBlur(gray,gray,Size(5,5),0); 
    vector<Vec3f> circles; 
    HoughCircles(gray,circles,CV_HOUGH_GRADIENT,1,gray.rows/8,100,100,100,0); 

    uchar x; 
    int measure=0;int id=0; 
    for(int i=0;i<circles.size();i++){ 
     if(cvRound(circles[i][2])>measure && cvRound(circles[i][2])<1000){ 
      measure=cvRound(circles[i][2]); 
      id=i; 
     } 
    } 


    Point center(cvRound(circles[id][0]),cvRound(circles[id][1])); 
    int radius=cvRound(circles[id][2]); 
    circle(im2,center,3,Scalar(0,255,0),-1,8,0); 
    circle(im2,center,radius,Scalar(0,255,0),2,8,0); 
    ellipse(ElipseImg,center,Size(radius,radius),0,0,360,Scalar(255,255,255),-1,8); 
    cout<<"center: "<<center<<" radius: "<<radius<<endl; 



    Mat res; 
    bitwise_and(gray,ElipseImg,result); 
    namedWindow("bitwise and",CV_WINDOW_FREERATIO); 
    imshow("bitwise and",result); 

    // trying to estimate the Intensity of the circle for the thresholding 
    x=result.at<uchar>(cvRound(circles[id][0]+30),cvRound(circles[id][1])); 
    cout<<(int)x; 

    //thresholding the output image 
    threshold(ElipseImg,ElipseImg,(int)x-10,250,CV_THRESH_BINARY); 
    namedWindow("threshold",CV_WINDOW_FREERATIO); 
    imshow("threshold",ElipseImg); 

    // making bitwise_or 
    bitwise_or(gray,ElipseImg,res); 
    namedWindow("bitwise or",CV_WINDOW_FREERATIO); 
    imshow("bitwise or",res); 

    waitKey(0); 
} 

Finora quello che ho fatto è:

  1. ho convertirlo in scala di grigi
  2. a rilevare la più grande cerchio utilizzando cerchi Hough e poi fare un cerchio con lo stesso raggio in una nuova immagine
  3. Questo nuovo cerchio con quello grigalizzato che utilizza (bitwise_and) mi restituisce un'immagine con solo quel cerchio
  4. soglia che nuova immagine
  5. bitwise_or il risultato della soglia

mio problema è che qualsiasi testo nero sulla linea bianca curva all'interno di questo cerchio non sembra. Ho provato a rimuovere il colore utilizzando i valori dei pixel anziché la soglia ma il problema è lo stesso, quindi qualsiasi soluzione o suggerimento?

Questi sono i risultati: enter image description here

risposta

34

io non sono sicuro se la seguente soluzione è accettabile nel tuo caso. Ma penso che funzioni leggermente meglio e non si preoccupa della forma della filigrana.

  • Rimuovere i tratti mediante filtraggio morfologico. Questo dovrebbe darti un'immagine di sfondo. background

  • Calcolare l'immagine differenza: differenza = sfondo - iniziale e la soglia è: binario = soglia (differenza)

binary1

  • Soglia l'immagine di sfondo ed estrarre il buio regione coperta dalla filigrana

dark

  • Dall'immagine iniziale, pixel estratto all'interno della regione filigrana e la soglia questi pixel, poi incollarli per l'immagine binaria in precedenza

binary2

Sopra è una descrizione di massima. Il codice qui sotto dovrebbe spiegarlo meglio.

Mat im = [load the color image here]; 

Mat gr, bg, bw, dark; 

cvtColor(im, gr, CV_BGR2GRAY); 

// approximate the background 
bg = gr.clone(); 
for (int r = 1; r < 5; r++) 
{ 
    Mat kernel2 = getStructuringElement(MORPH_ELLIPSE, Size(2*r+1, 2*r+1)); 
    morphologyEx(bg, bg, CV_MOP_CLOSE, kernel2); 
    morphologyEx(bg, bg, CV_MOP_OPEN, kernel2); 
} 

// difference = background - initial 
Mat dif = bg - gr; 
// threshold the difference image so we get dark letters 
threshold(dif, bw, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); 
// threshold the background image so we get dark region 
threshold(bg, dark, 0, 255, CV_THRESH_BINARY_INV | CV_THRESH_OTSU); 

// extract pixels in the dark region 
vector<unsigned char> darkpix(countNonZero(dark)); 
int index = 0; 
for (int r = 0; r < dark.rows; r++) 
{ 
    for (int c = 0; c < dark.cols; c++) 
    { 
     if (dark.at<unsigned char>(r, c)) 
     { 
      darkpix[index++] = gr.at<unsigned char>(r, c); 
     } 
    } 
} 
// threshold the dark region so we get the darker pixels inside it 
threshold(darkpix, darkpix, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 

// paste the extracted darker pixels 
index = 0; 
for (int r = 0; r < dark.rows; r++) 
{ 
    for (int c = 0; c < dark.cols; c++) 
    { 
     if (dark.at<unsigned char>(r, c)) 
     { 
      bw.at<unsigned char>(r, c) = darkpix[index++]; 
     } 
    } 
} 
+0

Impressionante, ha funzionato molto bene, ma ho un problema con le pagine più scure - filigrana scura - è sufficiente copiare l'intero filigrana all'immagine di peso corporeo quindi è come nulla di fatto, alla fine, come posso fare con qualcosa di simile ? –

+1

Controlla le immagini intermedie: ** differenza **, ** sfondo **, ** maschera filigrana ** e ** binario intermedio **. Qui usiamo il metodo Otsu, quindi le immagini sottoposte alla soglia dovrebbero essere più bimodali. È possibile verificare se le lettere all'interno della filigrana sono segmentate come previsto ritagliando una parte della filigrana che contiene testo e applicando la soglia di Otsu ad essa. Potrebbe anche essere una questione di CV_THRESH_BINARY vs CV_THRESH_BINARY_INV. – dhanushka

+0

@ dhanushka Per favore Qualcuno può aiutare con il codice Java per la parte ciclica del vettore. Non riesco a trovare qualcosa di equivalente in Java. Ho postato la domanda qui -> http://answers.opencv.org/question/130997/how-to-parse-a-binary-image-pixel-by-pixel-in-java-open-cv/ –

Problemi correlati