2015-08-20 3 views
41

Tout d'abord, j'ai cette image et je souhaite créer une application capable de détecter des images comme celle-ci et d'en retirer le cercle (filigrane).Suppression du filigrane d'une image à l'aide d'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); 
} 

Jusqu'à présent, ce que je fait est:

  1. Je convertir en niveaux de gris
  2. Je détecte le plus grand cercle en utilisant des cercles de jarrets, puis faire un cercle avec un même rayon de une nouvelle image
  3. Ce nouveau cercle avec le grayscaled utilisant (bitwise_and) me donne une image avec seulement ce cercle
  4. seuil nouvelle image
  5. bitwise_or le résultat du seuil

Mon problème est que tout texte noir sur la ligne blanche incurvée à l'intérieur de ce cercle n'a pas comparu. J'ai essayé d'enlever la couleur en utilisant les valeurs de pixel au lieu du seuil, mais le problème est le même, donc des solutions ou des suggestions?

Voici les résultats: enter image description here

Répondre

34

Je ne sais pas si la solution suivante est acceptable dans votre cas. Mais je pense qu'il fonctionne un peu mieux, et ne se soucie pas de la forme du filigrane.

  • Supprimer les traits en utilisant un filtrage morphologique. Cela devrait vous donner une image de fond. background

  • Calculer l'image de différence: différence = background - initial, et le seuil, il: binaire = seuil (différence)

binary1

  • Seuil du fond d'image et extraire l'obscurité région couverte par le filigrane

dark

  • De l'image initiale, les pixels d'extrait dans la région de filigrane et le seuil de ces pixels, puis les coller à l'image binaire plus tôt

binary2

Au-dessus est une description sommaire. Le code ci-dessous devrait l'expliquer mieux.

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

Impressionnant, il fonctionne très bien, mais j'ai problème avec des pages plus sombres - filigrane plus sombre - il suffit de copier l'ensemble filigrane à l'image bw il est comme rien fait à la fin, comment puis-je faire face à quelque chose comme ça ? –

+1

Vérifiez les images intermédiaires: la ** différence **, ** arrière-plan **, le ** masque de filigrane ** et le ** binaire intermédiaire **. Ici, nous utilisons la méthode Otsu, donc les images soumises au seuillage doivent être bimodales. Vous pouvez vérifier si les lettres à l'intérieur du filigrane sont segmentées comme prévu en recadrant une partie du filigrane qui contient du texte et en appliquant un seuillage Otsu. Il pourrait aussi s'agir de CV_THRESH_BINARY vs CV_THRESH_BINARY_INV. – dhanushka

+0

@dhanushka S'il vous plaît Quelqu'un peut-il aider avec le code Java pour le vecteur Looping Part.Je ne peux pas trouver quelque chose d'équivalent en Java. J'ai posté Question ici -> http://answers.opencv.org/question/130997/how-to-parse-a-binary-image-pixel-by-pixel-in-java-open-cv/ –