2013-07-14 35 views
6

Tôi hơi bối rối với các tham số của getPerspectiveTransform vì tôi không thể nhìn thấy một hình ảnh phù hợp. Đây là mã của tôi. Biến original_image là hình ảnh chứa một đối tượng hình vuông (và một số đối tượng khác) mà tôi muốn cắt và tạo một hình ảnh mới (một cái gì đó như thế này Android OpenCV Find Largest Square or Rectangle). Các biến p1, p2, p3 và p4 là tọa độ của các góc của hình vuông/hình chữ nhật lớn nhất trong hình ảnh. p1 là phía trên bên trái, p2 là phía trên bên phải, p3 là phía dưới bên phải, và p4 là phía dưới bên trái (chỉ định theo chiều kim đồng hồ).Android OpenCV getPerspectiveTransform và 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)); 

Khi tôi cố gắng hiển thị cropped_image, tôi nhận được hình ảnh "Tôi không biết nó là gì". Tôi nghĩ rằng các thông số của tôi trong getPerspectiveTransform() là không chính xác (hoặc là nó). Hãy giúp tôi. Cảm ơn!

Cập nhật: Khi tôi gỡ lỗi mã của mình, tôi phát hiện ra rằng các cạnh của hình vuông/hình chữ nhật của tôi không chính xác, một số khá đúng trừ p4. Đây là mã của tôi để phát hiện các cạnh của hình vuông hoặc hình chữ nhật trong hình ảnh. Hình ảnh của tôi có màu đen ngoại trừ đường viền của hình vuông/hình chữ nhật lớn nhất có viền trắng.

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

Đây là hình ảnh mẫu của tôi. bỏ qua các vòng tròn màu khi chúng được rút ra sau khi các cạnh được phát hiện:

enter image description here

Cập nhật: 16 Tháng 7 năm 2013 tôi có thể phát hiện các góc tại chỉ sử dụng approxCurve của tối đa đường viền 4 cánh. Đây là mã của tôi:

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

Dưới đây là hình ảnh kết quả mẫu:

enter image description here

Tôi đã rút ra vòng tròn cho các góc của hình vuông/hình chữ nhật và tôi cũng đã thêm một TextView để hiển thị tất cả các bốn điểm.

+0

OK, tôi sẽ xem lại mã của bạn khi có thời gian, nhưng cho đến lúc đó tôi sẽ cho bạn biết cách tiếp cận đơn giản hơn. Nếu bạn sử dụng [findContours] (http://docs.opencv.org/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours) bằng phương pháp "CV_CHAIN_APPROX_SIMPLE", bạn có thể lấy điểm ngay lập tức. – baci

+0

Ngoài ra, đó không phải là "cạnh", đó là "góc" :) – baci

+0

bạn có chắc là "src" và "dst" được tạo chính xác không? Tôi nghĩ sẽ tốt hơn nếu bạn sử dụng một mảng "Point2f" thay vì Mat. – baci

Trả lời

1

Điều này phù hợp với tôi. trong src_mat.put bạn nên có 0,0 lúc đầu và sau đó là các giá trị float cho các tọa độ.

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); 
Các vấn đề liên quan