2012-07-09 35 views
9

Tôi đang phát triển một dự án nhận dạng hình dạng bằng cách sử dụng JavaCV và tôi đã tìm thấy một số mã OpenCV để xác định các hình dạng U trong một hình ảnh cụ thể. Tôi đã cố gắng chuyển đổi nó thành JavaCV nhưng nó không cung cấp cho cùng một đầu ra. Bạn có thể vui lòng giúp tôi chuyển đổi mã OpenCV này thành JavaCV không?opencv/javacv: Làm cách nào để lặp qua các đường nét để nhận dạng hình dạng?

Đây là mã OpenCV:

import cv2 
import numpy as np 

img = cv2.imread('sofud.jpg') 
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
ret,thresh = cv2.threshold(gray,127,255,1) 
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 

for cnt in contours: 
    x,y,w,h = cv2.boundingRect(cnt) 
    if 10 < w/float(h) or w/float(h) < 0.1: 
     cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2) 

cv2.imshow('res',img) 
cv2.waitKey(0) 
cv2.destroyAllWindows() 

Đây là kết quả mong muốn

enter image description here

Đây là mã chuyển đổi:

import com.googlecode.javacpp.Loader; 
import com.googlecode.javacv.CanvasFrame; 
import static com.googlecode.javacpp.Loader.*; 
import static com.googlecode.javacv.cpp.opencv_core.*; 
import static com.googlecode.javacv.cpp.opencv_imgproc.*; 
import static com.googlecode.javacv.cpp.opencv_highgui.*; 
import java.io.File; 
import javax.swing.JFileChooser; 

public class TestBeam { 
    public static void main(String[] args) { 
     CvMemStorage storage=CvMemStorage.create(); 
     CvSeq squares = new CvContour(); 
     squares = cvCreateSeq(0, sizeof(CvContour.class), sizeof(CvSeq.class), storage); 
     JFileChooser f=new JFileChooser(); 
     int result=f.showOpenDialog(f);//show dialog box to choose files 
      File myfile=null; 
      String path=""; 
     if(result==0){ 
      myfile=f.getSelectedFile();//selected file taken to myfile 
      path=myfile.getAbsolutePath();//get the path of the file 
     } 
     IplImage src = cvLoadImage(path);//hear path is actual path to image 
     IplImage grayImage = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1); 
     cvCvtColor(src, grayImage, CV_RGB2GRAY); 
     cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY); 
     CvSeq cvSeq=new CvSeq(); 
     CvMemStorage memory=CvMemStorage.create(); 
     cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); 
     System.out.println(cvSeq.total()); 
     for (int i = 0; i < cvSeq.total(); i++) { 
      CvRect rect=cvBoundingRect(cvSeq, i); 
      int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width(); 
      if (10 < (w/h) || (w/h) < 0.1){ 
       cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0); 
       //cvSeqPush(squares, rect); 
      } 
     } 
     CanvasFrame cnvs=new CanvasFrame("Beam"); 
     cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 
     cnvs.showImage(src); 
     //cvShowImage("Final ", src); 

    } 
} 

Đây là sản phẩm mà tôi có. Xin ai đó có thể giúp tôi giải quyết vấn đề này?

enter image description here

+0

Tôi không thấy bất kỳ C++ nào, vì vậy tôi đã xóa thẻ. Tôi giả định ví dụ đầu tiên là Python. –

+1

Tôi có câu hỏi nhỏ liên quan đến câu hỏi này. Xin vui lòng một số có thể giải thích giá trị của "cvSeq.total()" phương pháp sau khi thực hiện "cvFindContours()" phương pháp? –

Trả lời

5

EDIT: Đây là phát hiện thú vị nhất - Tôi nghĩ rằng bạn đang không lặp lại một cách chính xác thông qua những đường nét - bạn nên làm điều gì đó như:

CvRect rect = cvBoundingRect(cvGetSeqElem(cvSeq, i),0); //python default? 

Hoặc:

// ... 
CvSeq contours = new CvSeq(); 
CvSeq ptr = new CvSeq(); 
CvRect rect = null; 
// ... 
cvFindContours(..., contours, ...); 

for (ptr = contours; ptr != null; ptr = ptr.h_next()) { 
    rect = cvBoundingRect(ptr, 0); 
    // ... Draw the box if meets criteria 
} 

Trước tiên, tôi nghĩ pst là đúng về việc tính tỷ lệ - bạn phải đúc chiều rộng để nổi. Thứ hai, tôi thấy rằng khi bạn đang làm cho hình ảnh màu xám trong python bạn sử dụng COLOR_BGR2GRAY và trong java bạn đang sử dụng CV_RGB2GRAY có thể dẫn đến một hình ảnh hoàn toàn khác nhau màu xám. Tôi sẽ thêm một số bước gỡ lỗi trên cả hai chương trình để lưu hình ảnh màu xám tạm thời và so sánh chúng cũng như in ra cho các giá trị x,y,wh khi (10 < (w/h) || (w/h) < 0.1) là đúng.

Một điều nữa là trong dung dịch java bạn sử dụng CV_RETR_CCOMP để có được những đường nét và trong dung dịch python bạn sử dụng CV_RETR_LIST theo các tài liệu:

CV_RETR_LIST lấy tất cả các đường nét mà không cần thiết lập bất kỳ mối quan hệ thứ bậc CV_RETR_CCOMP truy xuất tất cả các đường bao và sắp xếp chúng thành phân cấp hai cấp: ở cấp cao nhất là ranh giới bên ngoài của các thành phần, ở cấp thứ hai là các ranh giới của các lỗ trống . Nếu bên trong một lỗ của một thành phần kết nối có đường viền khác, nó sẽ vẫn được đưa vào cấp cao nhất

Vì vậy, đầu tiên tôi sẽ tăng gấp đôi kiểm tra xem thông số tất cả của cv trong cả hai chương trình đều giống nhau, sau đó tôi sẽ thêm gỡ rối các bước để thấy rằng các biến trung gian chứa cùng một dữ liệu.

+0

Trong javacv cvBoundingRect() chúng ta không thể truyền con trỏ như tham số vì nó yêu cầu CvArr vì vậy tôi nghĩ rằng nó không thể là vấn đề. –

+0

@GumSlashy - xem chỉnh sửa của tôi. Theo README của javacv (http://code.google.com/p/javacv/source/browse/README.txt), đây là một cách chính xác để lặp qua các đường bao. Tôi cũng tìm thấy câu hỏi này trong SO http://stackoverflow.com/questions/9648482/ocr-with-javacv trong đó sử dụng cùng một phương pháp để nhận đường bao, và vẽ các hộp giới hạn của chúng. – zenpoy

+0

Tôi cố gắng đặt cvBoundingRect (cvGetSeqElem (cvSeq, i), 0); trong vấn đề nhưng nó đã không làm việc cho tôi và tôi đã đặt câu trả lời rằng tôi đã nhận được kết quả chính xác.anyway cảm ơn bạn rất nhiều vì đã trả lời của bạn. –

3

Kiểm tra chương trình khuyến mãi kiểu của bạn, ví dụ .:

if (10 < (w/h) || (w/h) < 0.1){ 

.. rất nghi ngờ. Để có được điểm nổi chia, một (hoặc cả hai) của toán hạng phải ít nhất là float (và tương tự như vậy là double để chia đôi). Nếu không, như trong trường hợp này, nó là một bộ phận số nguyên. (Lưu ý rằng gốc mã có chương trình khuyến mãi để float là tốt.)

Ví dụ:

float ratio = (float)w/h; // (float/int) => (float/float) -> float 
if (10 < ratio || ratio < 0.1) { 

(Mặc dù tôi không chắc chắn nếu điều này là vấn đề ở đây.)

Chúc mừng mã hóa!

+1

Cảm ơn bạn đã trả lời nhanh chóng và tôi đã thử sugetion của bạn nhưng nó đã đưa ra cùng đưa ra. –

+0

Tôi nghĩ rằng nó sẽ giúp cập nhật mã của bạn với những thay đổi của bạn. Có lẽ vẫn còn một phân chia số nguyên trong đó? – Noremac

+1

Tôi đã đặt câu trả lời và trong đó tôi cũng cố gắng để đúc w/h trong giá trị float nhưng nó did't cho hiệu quả đáng kể. Nhưng đúng là nó có thể ảnh hưởng đáng kể trong một số trường hợp khác. Cảm ơn bạn rất nhiều vì đã trả lời của bạn. –

2

Mã này hoạt động cho tôi và tôi chỉ cần đặt cvSeq = cvSeq.h_next(); dòng vào chương trình và loại bỏ vòng lặp for thêm trong khi vòng lặp cho thet.

package Beam; 
    import com.googlecode.javacpp.Loader; 
    import com.googlecode.javacv.CanvasFrame; 
    import static com.googlecode.javacpp.Loader.*; 
    import static com.googlecode.javacv.cpp.opencv_core.*; 
    import static com.googlecode.javacv.cpp.opencv_imgproc.*; 
    import static com.googlecode.javacv.cpp.opencv_highgui.*; 
    import java.io.File; 
    import javax.swing.JFileChooser; 

    public class TestBeam2 { 
     public static void main(String[] args) { 
      JFileChooser f=new JFileChooser(); 
      int result=f.showOpenDialog(f);//show dialog box to choose files 
       File myfile=null; 
       String path=""; 
      if(result==0){ 
       myfile=f.getSelectedFile();//selected file taken to myfile 
       path=myfile.getAbsolutePath();//get the path of the file 
      } 
      IplImage src = cvLoadImage(path);//hear path is actual path to image 
      IplImage grayImage = IplImage.create(src.width(), src.height(), IPL_DEPTH_8U, 1); 
      cvCvtColor(src, grayImage, CV_RGB2GRAY); 
      cvThreshold(grayImage, grayImage, 127, 255, CV_THRESH_BINARY); 
      CvSeq cvSeq=new CvSeq(); 
      CvMemStorage memory=CvMemStorage.create(); 
      cvFindContours(grayImage, memory, cvSeq, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); 

      while (cvSeq != null && !cvSeq.isNull()) { 
       CvRect rect=cvBoundingRect(cvSeq, 0); 
       int x=rect.x(),y=rect.y(),h=rect.height(),w=rect.width(); 
       if (10 < w/h || w/h < 0.1){ 
        cvRectangle(src, cvPoint(x, y), cvPoint(x+w, y+h), CvScalar.RED, 1, CV_AA, 0); 
       } 
       cvSeq=cvSeq.h_next(); 
      } 
      CanvasFrame cnvs=new CanvasFrame("Beam"); 
      cnvs.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 
      cnvs.showImage(src); 
      //cvShowImage("Final ", src); 
     } 
    } 
+2

Đây chính xác là phương pháp mà tôi đã đề xuất cách đây vài ngày - điều này quá tệ, bạn đã không thử: '// ... CvSeq contours = new CvSeq(); CvSeq ptr = new CvSeq(); CvRect rect = null; // ... cvFindContours (..., đường nét, ...); cho (ptr = contours; ptr! = Null; ptr = ptr.h_next()) { rect = cvBoundingRect (ptr, 0); // ... Vẽ hộp nếu đáp ứng tiêu chí } ' – zenpoy

Các vấn đề liên quan