2013-07-14 3 views
6

Ich bin ein wenig verwirrt mit den Parametern von getPerspectiveTransform, da ich kein richtiges Bild sehen kann. Hier ist mein Code. Die Variable original_image ist das Bild, das ein quadratisches Objekt (und einige andere) enthält, das ich zuschneiden und ein neues Bild erstellen möchte (etwa Android OpenCV Find Largest Square or Rectangle). Die Variablen p1, p2, p3 und p4 sind die Koordinaten der Ecken des größten Quadrats/Rechtecks ​​im Bild. p1 ist oben links, p2 ist oben rechts, p3 ist unten rechts und p4 ist unten links (Zuweisung im Uhrzeigersinn).Android OpenCV getPerspectiveTransform und warpPerspective

Mat src = new Mat(4,1,CvType.CV_32FC2); 
    src.put((int)p1.y,(int)p1.x, (int)p2.y,(int)p2.x, (int)p4.y,(int)p4.x, (int)p3.y,(int)p3.x); 
    Mat dst = new Mat(4,1,CvType.CV_32FC2); 
    dst.put(0,0, 0,original_image.width(), original_image.height(),original_image.width(), original_image.height(),0); 

    Mat perspectiveTransform = Imgproc.getPerspectiveTransform(src, dst); 
    Mat cropped_image = original_image.clone(); 
    Imgproc.warpPerspective(untouched, cropped_image, perspectiveTransform, new Size(512,512)); 

Wenn ich versuche, cropped_image anzuzeigen, bekomme ich ein "Ich weiß nicht, was es ist" Bild. Ich denke meine Parameter in getPerspectiveTransform() sind falsch (oder ist es). Bitte helfen Sie. Vielen Dank!

Update: Als ich meinen Code debuggte, fand ich heraus, dass die Kanten meines Quadrats/Rechtecks ​​inkorrekt sind, einige sind ziemlich richtig, außer für p4. Dies ist mein Code, um die Kanten des Quadrats oder Rechtecks ​​im Bild zu erkennen. Mein Bild ist ganz schwarz, mit Ausnahme der Kontur des größten Quadrats/Rechtecks, das einen weißen Umriss aufweist.

//we will find the edges of the new_image (corners of the square/rectangle) 
    Point p1 = new Point(10000, 10000); //upper left; minX && minY 
    Point p2 = new Point(0, 10000); //upper right; maxX && minY 
    Point p3 = new Point(0, 0); //lower right; maxX && maxY 
    Point p4 = new Point(10000, 0); //lower left; minX && maxY 
    double[] temp_pixel_color; 
    for (int x=0; x<new_image.rows(); x++) { 
     for (int y=0; y<new_image.cols(); y++) { 
      temp_pixel_color = new_image.get(x, y); //we have a black and white image so we only have one color channel 
      if (temp_pixel_color[0] > 200) { //we found a white pixel 
       if (x<=p1.x && y<=p1.y) { //for p1, minX && minY 
        p1.x = x; 
        p1.y = y; 
       } 
       else if (x>=p2.x && y<=p2.y) { //for p2, maxX && minY 
        p2.x = x; 
        p2.y = y; 
       } 
       else if (x>=p3.x && y>=p3.y) { //for p3, maxX && maxY 
        p3.x = x; 
        p3.y = y; 
       } 
       else if (x<=(int)p4.x && y>=(int)p4.y) { //for p4, minX && maxY 
        p4.x = x; 
        p4.y = y; 
       } 
      } 
     } 
    } 

Hier ist mein Beispielbild. ignorieren die farbigen Kreise, wie sie gezeichnet werden, nachdem die Kanten detektiert werden:

enter image description here

Update: 16. Juli 2013 ich die Ecken nur noch die approxCurve der maximal 4 zackigen Kontur mit erfassen kann. Hier ist mein Code:

private Mat findLargestRectangle(Mat original_image) { 
    Mat imgSource = original_image; 
    //Mat untouched = original_image.clone(); 

    //convert the image to black and white 
    Imgproc.cvtColor(imgSource, imgSource, Imgproc.COLOR_BGR2GRAY); 

    //convert the image to black and white does (8 bit) 
    Imgproc.Canny(imgSource, imgSource, 50, 50); 

    //apply gaussian blur to smoothen lines of dots 
    Imgproc.GaussianBlur(imgSource, imgSource, new Size(5, 5), 5);  

    //find the contours 
    List<MatOfPoint> contours = new ArrayList<MatOfPoint>(); 
    Imgproc.findContours(imgSource, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE); 

    double maxArea = -1; 
    int maxAreaIdx = -1; 
    MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point 
    MatOfPoint2f approxCurve = new MatOfPoint2f(); 
    MatOfPoint2f maxCurve = new MatOfPoint2f(); 
    List<MatOfPoint> largest_contours = new ArrayList<MatOfPoint>(); 
    for (int idx = 0; idx < contours.size(); idx++) { 
     temp_contour = contours.get(idx); 
     double contourarea = Imgproc.contourArea(temp_contour); 
     //compare this contour to the previous largest contour found 
     if (contourarea > maxArea) { 
      //check if this contour is a square 
      MatOfPoint2f new_mat = new MatOfPoint2f(temp_contour.toArray()); 
      int contourSize = (int)temp_contour.total(); 
      Imgproc.approxPolyDP(new_mat, approxCurve, contourSize*0.05, true); 
      if (approxCurve.total() == 4) { 
       maxCurve = approxCurve; 
       maxArea = contourarea; 
       maxAreaIdx = idx; 
       largest_contours.add(temp_contour); 
      } 
     } 
    } 

    //create the new image here using the largest detected square 
    Mat new_image = new Mat(imgSource.size(), CvType.CV_8U); //we will create a new black blank image with the largest contour 
    Imgproc.cvtColor(new_image, new_image, Imgproc.COLOR_BayerBG2RGB); 
    Imgproc.drawContours(new_image, contours, maxAreaIdx, new Scalar(255, 255, 255), 1); //will draw the largest square/rectangle 

    double temp_double[] = maxCurve.get(0, 0); 
    Point p1 = new Point(temp_double[0], temp_double[1]); 
    Core.circle(new_image, new Point(p1.x, p1.y), 20, new Scalar(255, 0, 0), 5); //p1 is colored red 
    String temp_string = "Point 1: (" + p1.x + ", " + p1.y + ")"; 

    temp_double = maxCurve.get(1, 0); 
    Point p2 = new Point(temp_double[0], temp_double[1]); 
    Core.circle(new_image, new Point(p2.x, p2.y), 20, new Scalar(0, 255, 0), 5); //p2 is colored green 
    temp_string += "\nPoint 2: (" + p2.x + ", " + p2.y + ")"; 

    temp_double = maxCurve.get(2, 0);  
    Point p3 = new Point(temp_double[0], temp_double[1]); 
    Core.circle(new_image, new Point(p3.x, p3.y), 20, new Scalar(0, 0, 255), 5); //p3 is colored blue 
    temp_string += "\nPoint 3: (" + p3.x + ", " + p3.y + ")"; 

    temp_double = maxCurve.get(3, 0); 
    Point p4 = new Point(temp_double[0], temp_double[1]); 
    Core.circle(new_image, new Point(p4.x, p4.y), 20, new Scalar(0, 255, 255), 5); //p1 is colored violet 
    temp_string += "\nPoint 4: (" + p4.x + ", " + p4.y + ")"; 

    TextView temp_text = (TextView)findViewById(R.id.temp_text); 
    temp_text.setText(temp_string); 

    return new_image; 
} 

Hier wird das Probenergebnis Bild:

enter image description here

I Kreise für die Ecken des Quadrats/Rechteck gezeichnet haben, und ich fügte auch einen Textview angezeigt werden alle vier Punkte.

+0

OK, ich werde über Ihren Code gehen, wenn ich Zeit habe, aber bis dahin werde ich Ihnen einen einfacheren Ansatz sagen. Wenn Sie [findContours] (http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours) mit der Methode "CV_CHAIN_APPROX_SIMPLE" verwenden, können Sie sofort die Eckpunkte erhalten. – baci

+0

Auch das sind keine "Kanten", das sind "Ecken" :) – baci

+0

bist du sicher "src" und "dst" sind richtig erstellt? Ich denke, es wäre besser, wenn Sie ein "Point2f" -Array anstelle von Mat verwenden würden. – baci

Antwort

1

Das funktionierte für mich. Im src_mat.put sollten Sie zuerst 0,0 und dann die Float-Werte für die Koordinaten haben.

Mat mat=Highgui.imread("inputImage.jpg"); 
    Mat src_mat=new Mat(4,1,CvType.CV_32FC2); 
    Mat dst_mat=new Mat(4,1,CvType.CV_32FC2); 


    src_mat.put(0,0,407.0,74.0,1606.0,74.0,420.0,2589.0,1698.0,2589.0); 
    dst_mat.put(0,0,0.0,0.0,1600.0,0.0, 0.0,2500.0,1600.0,2500.0); 
    Mat perspectiveTransform=Imgproc.getPerspectiveTransform(src_mat, dst_mat); 

    Mat dst=mat.clone(); 

    Imgproc.warpPerspective(mat, dst, perspectiveTransform, new Size(1600,2500)); 
    Highgui.imwrite("resultImage.jpg", dst);