2013-07-07 24 views
10

Questo potrebbe essere stato risposto ma ho disperatamente bisogno di una risposta per questo. Voglio trovare il quadrato o il rettangolo più grande in un'immagine usando OpenCV in Android. Tutte le soluzioni che ho trovato sono C++ e ho provato a convertirlo ma non funziona e non so dove mi sbaglio.Android OpenCV Trova il più grande quadrato o rettangolo

private Mat findLargestRectangle(Mat original_image) { 
    Mat imgSource = original_image; 

    Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY); 
    Imgproc.Canny(imgSource, imgSource, 100, 100); 

    //I don't know what to do in here 

    return imgSource; 
} 

Quello che sto cercando di realizzare qui è quello di creare una nuova immagine che si basa sulla più grande piazza trovato il (immagine Mat valore di ritorno) dell'immagine originale in.

Questo è quello che voglio che accada:

1 http://img14.imageshack.us/img14/7855/s7zr.jpg

E 'anche bene che ho appena ottenere i quattro punti la piazza più grande e penso che posso prendere da lì. Ma sarebbe meglio se potessi semplicemente restituire l'immagine ritagliata.

+1

Se si dispone di sorgente sul C++ e il lavoro, forse si mostra sorgente completo (intendo mostrare ciò che non ci sono invece il vostro '// I non so cosa fare qui!). Possiamo provare a convertire tutti i codici insieme. – McBodik

+2

se hai trovato la soluzione, potresti postarla? – TharakaNirmana

risposta

11

Dopo astuto

1- è necessario ridurre i rumori con gaussian blur e find all the contours

2- trovare e visualizzare tutti i contours' areas.

3- il contorno più grande non sarà altro che il dipinto.

4- ora utilizzare perpective transformation per trasformare la forma in un rettangolo.

controllare sudoku solver examples per visualizzare il problema di elaborazione simile. (Il più grande contorno + prospettiva)

+3

in realtà sarebbe meglio se si sfoca l'immagine PRIMA dell'operatore astuto. – baci

+0

grazie Baci, ora posso rilevare il quadrato più grande nell'immagine: http://stackoverflow.com/questions/17611494/opencv-android-create-new-image-using-the-edges-of-the-largest-contour ma il mio problema è che non posso usare la trasformazione prospettica perché non conosco i quattro punti della regione quadrata/rettangolare più grande rilevata. Puoi aiutarmi su questo? –

+0

Vorrei sottolineare che l'output canny di guassian filtering è molto valido. Ho avuto qualche problema nel trovare rettangoli in alcune immagini rumorose. Così ho eseguito: filtraggio bilaterale, rilevamento dei bordi canny, quindi filtraggio guasisan sull'output canny. Il filtro guassiano si occupava di tutto il rumore residuo nell'output canny. Se ho provato a filtrare in modo troppo aggressivo prima dell'operazione, ho distorto i bordi dei miei rettangoli. – MeetTitan

1

Ci sono alcune domande correlate qui in SO. Dateci un'occhiata:

C'è anche un esempio fornito con OpenCV:

Una volta ottenuto il rettangolo, è possibile allineare l'immagine calcolando l'omografia con gli angoli del rettangolo e applicando una trasformazione prospettica.

9

ho messo un po 'per convertire il codice C++ a Java, ma qui è :-)

Attenzione! Codice raw, totalmente non ottimizzato e tutto.

ho declinare ogni responsabilità in caso di infortunio o incidente letale

List<MatOfPoint> squares = new ArrayList<MatOfPoint>(); 

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) { 

     if (Math.random()>0.80) { 

      findSquares(inputFrame.rgba().clone(),squares); 

     } 

     Mat image = inputFrame.rgba(); 

     Imgproc.drawContours(image, squares, -1, new Scalar(0,0,255)); 

     return image; 
    } 

    int thresh = 50, N = 11; 

// helper function: 
// finds a cosine of angle between vectors 
// from pt0->pt1 and from pt0->pt2 
    double angle(Point pt1, Point pt2, Point pt0) { 
      double dx1 = pt1.x - pt0.x; 
      double dy1 = pt1.y - pt0.y; 
      double dx2 = pt2.x - pt0.x; 
      double dy2 = pt2.y - pt0.y; 
      return (dx1*dx2 + dy1*dy2)/Math.sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); 
    } 

// returns sequence of squares detected on the image. 
// the sequence is stored in the specified memory storage 
void findSquares(Mat image, List<MatOfPoint> squares) 
{ 

    squares.clear(); 

    Mat smallerImg=new Mat(new Size(image.width()/2, image.height()/2),image.type()); 

    Mat gray=new Mat(image.size(),image.type()); 

    Mat gray0=new Mat(image.size(),CvType.CV_8U); 

    // down-scale and upscale the image to filter out the noise 
    Imgproc.pyrDown(image, smallerImg, smallerImg.size()); 
    Imgproc.pyrUp(smallerImg, image, image.size()); 

    // find squares in every color plane of the image 
    for(int c = 0; c < 3; c++) 
    { 

     extractChannel(image, gray, c); 

     // try several threshold levels 
     for(int l = 1; l < N; l++) 
     { 
      //Cany removed... Didn't work so well 


      Imgproc.threshold(gray, gray0, (l+1)*255/N, 255, Imgproc.THRESH_BINARY); 


      List<MatOfPoint> contours=new ArrayList<MatOfPoint>(); 

      // find contours and store them all as a list 
      Imgproc.findContours(gray0, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); 

      MatOfPoint approx=new MatOfPoint(); 

      // test each contour 
      for(int i = 0; i < contours.size(); i++) 
      { 

       // approximate contour with accuracy proportional 
       // to the contour perimeter 
       approx = approxPolyDP(contours.get(i), Imgproc.arcLength(new MatOfPoint2f(contours.get(i).toArray()), true)*0.02, true); 


       // square contours should have 4 vertices after approximation 
       // relatively large area (to filter out noisy contours) 
       // and be convex. 
       // Note: absolute value of an area is used because 
       // area may be positive or negative - in accordance with the 
       // contour orientation 

       if(approx.toArray().length == 4 && 
        Math.abs(Imgproc.contourArea(approx)) > 1000 && 
        Imgproc.isContourConvex(approx)) 
       { 
        double maxCosine = 0; 

        for(int j = 2; j < 5; j++) 
        { 
         // find the maximum cosine of the angle between joint edges 
         double cosine = Math.abs(angle(approx.toArray()[j%4], approx.toArray()[j-2], approx.toArray()[j-1])); 
         maxCosine = Math.max(maxCosine, cosine); 
        } 

        // if cosines of all angles are small 
        // (all angles are ~90 degree) then write quandrange 
        // vertices to resultant sequence 
        if(maxCosine < 0.3) 
         squares.add(approx); 
       } 
      } 
     } 
    } 
} 

void extractChannel(Mat source, Mat out, int channelNum) { 
    List<Mat> sourceChannels=new ArrayList<Mat>(); 
    List<Mat> outChannel=new ArrayList<Mat>(); 

    Core.split(source, sourceChannels); 

    outChannel.add(new Mat(sourceChannels.get(0).size(),sourceChannels.get(0).type())); 

    Core.mixChannels(sourceChannels, outChannel, new MatOfInt(channelNum,0)); 

    Core.merge(outChannel, out); 
} 

MatOfPoint approxPolyDP(MatOfPoint curve, double epsilon, boolean closed) { 
    MatOfPoint2f tempMat=new MatOfPoint2f(); 

    Imgproc.approxPolyDP(new MatOfPoint2f(curve.toArray()), tempMat, epsilon, closed); 

    return new MatOfPoint(tempMat.toArray()); 
} 
Problemi correlati