2013-07-07 14 views
10

Dies könnte beantwortet worden sein, aber ich brauche dringend eine Antwort dafür. Ich möchte das größte Quadrat oder Rechteck in einem Bild mit OpenCV in Android finden. Alle Lösungen, die ich gefunden habe, sind C++ und ich habe versucht, es zu konvertieren, aber es funktioniert nicht und ich weiß nicht, wo ich falsch liege.Android OpenCV Finden Largest Square oder Rectangle

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; 
} 

Was ich versuche, hier zu erreichen, in ein neues Bild zu erstellen, die auf dem größten Platz im Originalbild (Rückgabewert Mat Bild) gefunden basieren.

Dies ist, was ich passieren soll:

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

Es ist auch in Ordnung, dass ich die vier Punkte des größten Platzes nur bekommen, und ich denke, dass ich es von dort nehmen. Aber es wäre besser, wenn ich nur das zugeschnittene Bild zurückgeben könnte.

+1

Wenn Sie Quelle auf c haben ++ und es funktioniert, vielleicht zeigen Ihnen die volle Quelle (ich meine Sie zeigen, was es stattdessen Ihre '// I Ich weiß nicht, was ich hier machen soll. Wir können versuchen, den gesamten Code zusammen zu konvertieren. – McBodik

+2

Wenn Sie die Lösung gefunden haben, können Sie sie veröffentlichen? – TharakaNirmana

Antwort

11

Nach Canny

1- müssen Sie Geräusche mit gaussian blur und find all the contours

2- Fund reduzieren und eine Liste aller contours' areas.

3- die größte Kontur wird nichts als das Gemälde sein.

4- Jetzt verwenden Sie perpective transformation, um Ihre Form in ein Rechteck zu verwandeln.

überprüfen Sie sudoku solver examples, um das ähnliche Verarbeitungsproblem zu sehen. (Größte Kontur + Perspektive)

+3

eigentlich wäre es besser, wenn Sie das Bild BEFORE canny Operator verwischen. – baci

+0

danke Baci, ich kann jetzt das größte Quadrat im Bild erkennen: http://stackoverflow.com/questions/17611494/opencv-android-create-new-image-use-the-edges-of-the-largest-contour aber mein Problem ist, dass ich keine perspektivische Transformation verwenden kann, weil ich die vier Punkte der größten erkannten Quadrat-/Rechteckregion nicht kenne. Kannst du mir dabei helfen? –

+0

Ich möchte darauf hinweisen, dass guassian Filtering canny Ausgabe ist sehr gültig. Ich hatte Probleme, Rechtecke in einigen verrauschten Bildern zu finden. Also lief ich: bilaterales Filtern, schlaue Kantenerkennung, dann Guasisan-Filterung auf dem schlauen Ausgang. Der Guassian-Filter kümmerte sich um das gesamte Restgeräusch in der schlauen Ausgabe. Wenn ich vor der cleveren Operation zu aggressiv filterte, verzerrte ich die Kanten meiner Rechtecke. – MeetTitan

1

Es gibt einige verwandte Fragen hier in SO. Überprüfen Sie sie heraus:

Es ist auch ein Beispiel mit OpenCV ausgeliefert:

Sobald Sie das Rechteck haben, können Sie das Bild ausrichten, indem Sie die Homographie mit den Ecken des Rechtecks ​​berechnen und eine perspektivische Transformation anwenden.

9

dauerte eine Weile, den C++ Code zu Java konvertieren, aber hier ist es :-)

Achtung! Rohcode, total nicht optimiert und alles.

lehne ich jegliche Haftung im Falle von Verletzungen oder tödlichen Unfall

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()); 
}